Skip to main content
Jenkins advanced Lesson 4 of 4

Jenkins Shared Libraries

Eliminate copy-pasted Jenkinsfiles by extracting common pipeline logic into a Shared Library—versioned, tested, and available to all team pipelines.

As your team grows, you end up copy-pasting the same Jenkinsfile stages across dozens of repos. Shared Libraries let you write pipeline steps once, version them, and use them everywhere.

Learning outcomes

By the end you can:

  • create a Shared Library repository with the correct structure
  • write and use global vars (steps)
  • load a library in a Jenkinsfile
  • use implicit and explicit library loading

1) Why Shared Libraries?

Without shared libraries:

  • Every repo has its own Jenkinsfile with duplicated Docker build/push logic
  • Fixing a bug means updating every repo
  • No central version control or testing for CI logic

With shared libraries:

  • One library repo contains reusable pipeline steps
  • Pipelines import the library—one fix propagates everywhere
  • The library itself is versioned, testable, and code-reviewed

2) Shared Library directory structure

jenkins-shared-library/
├── vars/
│   ├── buildDockerImage.groovy   # global step: buildDockerImage(...)
│   ├── deployToKubernetes.groovy # global step: deployToKubernetes(...)
│   └── notifySlack.groovy        # global step: notifySlack(...)
├── src/
│   └── org/
│       └── example/
│           └── PipelineUtils.groovy  # Groovy class
├── resources/
│   └── org/example/
│       └── deploy.sh             # scripts or templates
└── README.md

3) Writing a global step (vars/)

Each file in vars/ defines a call() method that becomes the step name.

// vars/buildDockerImage.groovy

def call(Map config = [:]) {
  // Provide defaults
  def registry  = config.registry  ?: 'registry.example.com'
  def imageName = config.imageName ?: error('imageName is required')
  def tag       = config.tag       ?: env.BUILD_NUMBER

  def fullImage = "${registry}/${imageName}:${tag}"

  echo "Building Docker image: ${fullImage}"

  sh "docker build -t ${fullImage} ."
  sh "docker push ${fullImage}"

  return fullImage
}
// vars/notifySlack.groovy

def call(String message, String color = 'good') {
  slackSend(
    channel: '#deployments',
    color: color,
    message: "${message} — ${env.JOB_NAME} #${env.BUILD_NUMBER} (<${env.BUILD_URL}|Open>)"
  )
}

4) Register the library in Jenkins

  1. Go to Manage Jenkins → Configure System → Global Pipeline Libraries
  2. Click Add:
    • Name: my-shared-lib
    • Default version: main
    • Retrieval method: Modern SCM → GitHub → your repo URL
  3. Tick Load implicitly (optional, auto-loads in all pipelines) or leave unchecked (explicit @Library)

5) Using the library in a Jenkinsfile

Explicit loading

@Library('my-shared-lib@main') _   // underscore imports all vars/

pipeline {
  agent any

  stages {
    stage('Build Image') {
      steps {
        script {
          def image = buildDockerImage(
            registry: 'registry.example.com',
            imageName: 'myapp',
            tag: env.BUILD_NUMBER
          )
          env.DOCKER_IMAGE = image
        }
      }
    }

    stage('Deploy') {
      when { branch 'main' }
      steps {
        deployToKubernetes(
          image: env.DOCKER_IMAGE,
          namespace: 'production',
          deployment: 'myapp'
        )
      }
    }
  }

  post {
    success { notifySlack("✅ Deploy succeeded") }
    failure { notifySlack("❌ Deploy failed", 'danger') }
  }
}

6) Kubernetes deploy step example

// vars/deployToKubernetes.groovy

def call(Map config = [:]) {
  def image      = config.image      ?: error('image is required')
  def namespace  = config.namespace  ?: 'default'
  def deployment = config.deployment ?: error('deployment is required')

  withCredentials([file(credentialsId: 'kubeconfig', variable: 'KUBECONFIG')]) {
    sh """
      kubectl set image deployment/${deployment} \
        ${deployment}=${image} \
        --namespace=${namespace}
      kubectl rollout status deployment/${deployment} \
        --namespace=${namespace} \
        --timeout=120s
    """
  }
}

7) Versioning the library

Pin to a specific git tag for stability:

@Library('[email protected]') _

Or always use latest from main (risky for production):

@Library('my-shared-lib@main') _

8) Testing Shared Library code

Use jenkins-spock or plain Groovy unit tests.

Minimum: write a test playbook pipeline that calls each step with representative inputs and verify it runs end-to-end in a test Jenkins instance.

Next steps

  • Pair with Ansible: trigger playbooks from shared library steps
  • Jenkins Configuration as Code (JCasC) for managing Jenkins itself via YAML
  • GitOps pattern: replace Jenkins pushes with ArgoCD pull-based deploys

Frequently Asked Questions

Where do I host a Jenkins Shared Library?
In any Git repository (GitHub, GitLab, Bitbucket). You configure it under Manage Jenkins → Configure System → Global Pipeline Libraries. Jenkins checks out the library at pipeline start.
What is the difference between vars/ and src/ in a Shared Library?
Files in vars/ define global variables and are loaded automatically (call them like myFunction()). Files in src/ are Groovy classes you import explicitly with @Library—useful for more structured, testable code.