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
- Go to Manage Jenkins → Configure System → Global Pipeline Libraries
- Click Add:
- Name:
my-shared-lib - Default version:
main - Retrieval method: Modern SCM → GitHub → your repo URL
- Name:
- 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('my-shared-lib@v1.2.0') _
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