Shared Libraries: vars and src
Extract repeated pipeline logic into a versioned Shared Library so every project reuses the same battle-tested steps instead of copy-pasting Groovy.
Once you have more than a handful of pipelines, you will notice the same 40 lines of Groovy pasted into every Jenkinsfile. That copy-paste is where drift and bugs live. A Shared Library is a separate Git repository that Jenkins loads and makes available to every pipeline, so you write the logic once and version it like real code.
The two folders that matter
vars/— each file becomes a global step.vars/deployApp.groovygives every pipeline adeployApp()call. The specialcall()method is what runs. This is the friendly, high-level API your teams use.src/— regular Groovy classes under a package path (e.g.src/org/acme/Notifier.groovy). Use this for real logic, helpers, and anything you want to unit test.
Loading it
Configure the library once under Manage Jenkins > System > Global Trusted Pipeline Libraries, then pull it into a pipeline with @Library('acme-pipelines@main') _ at the very top. Pinning to a tag or commit instead of a branch means a library change can never silently break every build at 3 a.m.
Why it is worth it
- One fix propagates everywhere.
- New services get a production-grade pipeline in three lines.
- The library can be reviewed, tested, and released on its own cadence.
Example
// === Shared library repo layout ===
// (acme-pipelines.git)
// vars/
// deployApp.groovy
// src/org/acme/
// Notifier.groovy
// --- vars/deployApp.groovy ---
def call(Map cfg = [:]) {
// sensible defaults so callers stay short
String env = cfg.get('env', 'staging')
String tag = cfg.get('tag', env.BUILD_TAG)
echo "Deploying ${tag} to ${env}"
sh "kubectl set image deploy/app app=registry/app:${tag} -n ${env}"
sh "kubectl rollout status deploy/app -n ${env} --timeout=120s"
}
// --- Jenkinsfile in a service repo ---
@Library('[email protected]') _
pipeline {
agent any
stages {
stage('Deploy') {
steps {
deployApp(env: 'production', tag: "v${BUILD_NUMBER}")
}
}
}
}When to use it
- A platform team ships a buildAndPush() step in a shared library so each microservice Jenkinsfile is 5 lines instead of 50.
- A security team injects a mandatory SAST scan by including it in the shared library's base pipeline class used by all projects.
- Versioned releases of the shared library allow projects to pin to v1.2.0 while the team develops a breaking v2.0.0 in parallel.
More examples
vars/ global step definition
Defines a reusable buildAndPush() global variable step in the vars/ directory of a shared library.
// vars/buildAndPush.groovy
def call(String image, String registry = 'registry.example.com') {
sh "docker build -t ${registry}/${image}:${env.BUILD_NUMBER} ."
sh "docker push ${registry}/${image}:${env.BUILD_NUMBER}"
return "${registry}/${image}:${env.BUILD_NUMBER}"
}src/ Groovy class for complex logic
A Serializable Groovy class in src/ that wraps Kubernetes deployment commands for reuse across pipelines.
// src/com/example/DeployHelper.groovy
package com.example
class DeployHelper implements Serializable {
def script
DeployHelper(script) { this.script = script }
def toKubernetes(String ns, String image) {
script.sh "kubectl set image deploy/app app=${image} -n ${ns}"
script.sh "kubectl rollout status deploy/app -n ${ns}"
}
}Consume library with version pin
Pins to library version v1.2.0, calls the global step, and uses the src/ class for deployment in one Jenkinsfile.
@Library('[email protected]') _
import com.example.DeployHelper
pipeline {
agent any
stages {
stage('Build & Push') {
steps { script { env.IMAGE = buildAndPush('myapp') } }
}
stage('Deploy') {
steps {
script {
new DeployHelper(this).toKubernetes('production', env.IMAGE)
}
}
}
}
}
Discussion