Jenkins Shared Libraries let you reuse pipeline code across multiple Jenkins jobs, keeping your CI/CD logic DRY (Don’t Repeat Yourself) and maintainable.

Let’s see a simple shared library in action. Imagine you have a common step like building a Docker image.

// vars/dockerBuild.groovy
def call(Map config = [:]) {
    sh "docker build -t ${config.imageName}:${config.tag} ${config.contextPath ?: '.'}"
    echo "Built Docker image ${config.imageName}:${config.tag}"
}

Now, in your Jenkinsfile, you can use this as if it were a built-in step:

// Jenkinsfile
@Library('my-shared-library@main') _

pipeline {
    agent any
    stages {
        stage('Build Docker') {
            steps {
                dockerBuild(imageName: 'my-app', tag: 'v1.0.0', contextPath: 'docker/')
            }
        }
    }
}

When this pipeline runs, Jenkins will look for dockerBuild.groovy in the vars directory of the my-shared-library Git repository (configured in Jenkins Global Configuration). It then executes the call method within that script, passing the provided arguments. This makes complex build logic reusable and easy to manage.

The core problem shared libraries solve is the proliferation of duplicate pipeline code. Without them, every Jenkinsfile needing a specific build, deploy, or test sequence would have to reimplement that logic, leading to inconsistencies and maintenance nightmares. Shared libraries centralize this logic into a version-controlled repository, accessible by any Jenkins job.

Internally, Jenkins treats the vars directory of a shared library as Groovy classes. Each .groovy file in vars becomes a callable step, and the call method within that script is invoked. For example, vars/dockerBuild.groovy makes a dockerBuild() step available. The src directory is for more complex, class-based logic that can be imported and instantiated.

You control shared libraries through their configuration in Jenkins Global Tool Configuration. You specify the Git repository URL, the branch to use, and optionally a subdirectory within the repository if your library isn’t at the root. Jenkins will then clone this repository and make its contents available to pipelines.

The @Library annotation in your Jenkinsfile tells Jenkins which shared library to load. The underscore (_) after the library name indicates that you want to load all defined steps and classes from that library. You can also specify specific named libraries if you have multiple configured.

A common pattern is to define a Jenkinsfile within the root of your shared library repository. This Jenkinsfile can then be used to test and demonstrate the library’s functionality, ensuring it works as expected before being deployed to production jobs.

When you need to pass complex configuration or state between different steps within your shared library code, you can define custom Groovy classes in the src directory of your library. These classes can have constructors and methods, allowing you to encapsulate more elaborate logic and data structures, which can then be instantiated and used within your vars scripts.

The next step in mastering shared libraries is understanding how to define and use custom step parameters with validation and default values to make your reusable logic more robust and user-friendly.

Want structured learning?

Take the full Jenkins course →