Jenkins Shared Libraries for Reusable Code

Shared Libraries let you write pipeline code once and use it across many jobs. Instead of copying the same stages and steps into every Jenkinsfile, you write the logic once in a shared library and all pipelines reference it.

Imagine twenty bakers in a bakery. Without a shared recipe book, each baker writes their own recipe from scratch and makes different versions of the same bread. A shared recipe book gives everyone the same, tested recipe. Shared Libraries work the same way for Jenkins pipelines.

The Problem Shared Libraries Solve

WITHOUT shared libraries:

  Job A Jenkinsfile:          Job B Jenkinsfile:          Job C Jenkinsfile:
    stage('Docker Build')       stage('Docker Build')       stage('Docker Build')
      sh 'docker build ...'       sh 'docker build ...'       sh 'docker build ...'
      sh 'docker push ...'        sh 'docker push ...'        sh 'docker push ...'
                                                              // slightly different
    stage('Notify Slack')       stage('Notify Slack')       stage('Notify Slack')
      slackSend ...               slackSend ...               slackSend ...  // typo here

Problem: If the Docker build process changes, you edit 20+ Jenkinsfiles.
         One job has a typo in Slack notification — inconsistent behavior.

WITH shared libraries:

  Shared Library (one place):
    def dockerBuild(image, tag) { ... }
    def notifySlack(channel, message) { ... }

  Job A, B, C Jenkinsfile:
    @Library('my-shared-lib') _
    dockerBuild('myapp', env.BUILD_NUMBER)
    notifySlack('#builds', 'Build complete')

Change in one place → All jobs get the update automatically.

Shared Library Repository Structure

A Shared Library is a Git repository with a specific folder structure Jenkins expects.

my-jenkins-shared-library/
├── vars/
│   ├── dockerBuild.groovy       ← Global variable (callable as a function)
│   ├── notifySlack.groovy       ← Another global variable
│   └── deployToKubernetes.groovy
│
├── src/
│   └── com/
│       └── mycompany/
│           └── Utils.groovy     ← Groovy class (more complex logic)
│
└── resources/
    └── config/
        └── deploy-config.yaml   ← Static resource files

The vars/ directory is the most important. Each .groovy file in vars/ becomes a callable function in your pipeline. The file name is the function name.

Creating a Global Variable in vars/

Create a file in the vars/ folder. The file must contain a call method. When a pipeline calls the function name, it runs the call method.

vars/dockerBuild.groovy

def call(String imageName, String imageTag) {
    echo "Building Docker image: ${imageName}:${imageTag}"

    sh "docker build -t ${imageName}:${imageTag} ."
    sh "docker push ${imageName}:${imageTag}"

    echo "Docker image pushed successfully"
}

vars/notifySlack.groovy

def call(String channel, String status) {
    def color = status == 'SUCCESS' ? 'good' : 'danger'
    def message = "${env.JOB_NAME} #${env.BUILD_NUMBER} — ${status}"

    slackSend(
        channel: channel,
        color: color,
        message: message
    )
}

vars/deployToKubernetes.groovy

def call(Map config = [:]) {
    // config is a named parameter map
    // Usage: deployToKubernetes(app: 'myapp', env: 'production', image: 'myapp:1.0')

    def app   = config.app
    def env   = config.env   ?: 'staging'
    def image = config.image ?: 'latest'

    echo "Deploying ${app} to ${env} with image ${image}"

    sh "kubectl set image deployment/${app} app=${image} -n ${env}"
    sh "kubectl rollout status deployment/${app} -n ${env}"
}

Registering the Shared Library in Jenkins

Step 1: Go to Manage Jenkins → System (or Configure System)
Step 2: Scroll to "Global Pipeline Libraries"
Step 3: Click "Add"
Step 4: Fill in:
    Name:           my-shared-lib        ← Used in @Library annotation
    Default version: main                ← Git branch to use by default
    Retrieval method: Modern SCM
    Source Code Management: Git
    Repository URL: https://github.com/myorg/jenkins-shared-library.git
    Credentials: github-token
Step 5: Check "Load implicitly" (optional — auto-loads without @Library)
Step 6: Save

Using the Shared Library in a Jenkinsfile

// Load the library at the top of the Jenkinsfile
@Library('my-shared-lib') _

pipeline {
    agent any

    stages {
        stage('Build and Push') {
            steps {
                script {
                    dockerBuild('mycompany/myapp', env.BUILD_NUMBER)
                }
            }
        }

        stage('Deploy') {
            steps {
                script {
                    deployToKubernetes(
                        app: 'myapp',
                        env: 'production',
                        image: "mycompany/myapp:${env.BUILD_NUMBER}"
                    )
                }
            }
        }
    }

    post {
        always {
            script {
                notifySlack('#deployments', currentBuild.currentResult)
            }
        }
    }
}

Loading a Specific Version of the Library

Reference a specific branch, tag, or commit hash in the @Library annotation. This protects a pipeline from unintended changes in the library's main branch.

// Use the main branch (default)
@Library('my-shared-lib') _

// Use a specific branch
@Library('my-shared-lib@develop') _

// Use a specific tag (recommended for production)
@Library('my-shared-lib@v2.3.0') _

// Use a specific commit hash (most stable)
@Library('my-shared-lib@a3f9c12') _

Using Groovy Classes in src/

For more complex logic, put Groovy classes in the src/ directory. These classes work like regular Groovy/Java classes.

// src/com/mycompany/DeployHelper.groovy
package com.mycompany

class DeployHelper implements Serializable {
    def script

    DeployHelper(script) {
        this.script = script
    }

    def deploy(String environment, String version) {
        script.echo "Deploying ${version} to ${environment}"
        script.sh "kubectl set image deployment/app app=myimage:${version} -n ${environment}"
    }
}
// In Jenkinsfile:
@Library('my-shared-lib') import com.mycompany.DeployHelper

pipeline {
    agent any
    stages {
        stage('Deploy') {
            steps {
                script {
                    def helper = new DeployHelper(this)
                    helper.deploy('production', env.BUILD_NUMBER)
                }
            }
        }
    }
}

Key Points

  • Shared Libraries store reusable pipeline code in a Git repository that all jobs can use.
  • Files in the vars/ directory become callable functions in your pipelines.
  • Register the library in Manage Jenkins → System under Global Pipeline Libraries.
  • Load the library with @Library('library-name') at the top of your Jenkinsfile.
  • Reference a specific version tag in @Library to protect pipelines from unexpected changes.

Leave a Comment