CloudOpsGuide
jenkins

Jenkins Shared Libraries: Reusable Pipeline Code

Intermediate
14 minutes
October 2026
CloudOpsGuide Team

Jenkins Shared Libraries: Reusable Pipeline Code

Create shared libraries to standardise pipeline code across teams — vars, src, resources, and best practices.

Table of Contents

What Is a Shared Library

A Jenkins Shared Library is a Git repository containing reusable pipeline code that can be loaded into any Jenkinsfile. Instead of copying the same deploy.sh wrapper into 50 pipelines, you define it once and call it everywhere.

vars/          — global functions callable from pipelines
src/           — Groovy classes (imported like normal Groovy)
resources/     — non-code files (YAML templates, scripts)

Library Structure

jenkins-shared-library/
├── vars/
│   ├── buildApp.groovy          # call with buildApp()
│   ├── deployToK8s.groovy       # call with deployToK8s()
│   ├── notifySlack.groovy
│   └── logUtils.groovy
├── src/
│   └── com/
│       └── company/
│           ├── Kubernetes.groovy # class for complex logic
│           └── PipelineConfig.groovy
└── resources/
    ├── k8s/
    │   └── deployment.yaml      # reusable K8s manifest template
    └── scripts/
        └── smoke-test.sh        # shared shell script

Setting Up the Library

1. Create the Git Repo

mkdir jenkins-shared-library
cd jenkins-shared-library
mkdir -p vars src/com/company resources/{k8s,scripts}
git init && git add . && git commit -m "Initial library"

2. Configure in Jenkins

Manage Jenkins → System → Global Pipeline Libraries:

  • Name: shared-lib (this is what pipelines reference)
  • Default version: main or a git tag
  • Retrieval method: Modern SCM → Git
  • Repo URL: https://github.com/myorg/jenkins-shared-library.git

Writing Shared Functions

Simple Function — vars/logUtils.groovy

def info(String message) {
    echo "[INFO] ${message}"
}

def error(String message) {
    echo "[ERROR] ${message}"
    error(message)
}

def success(String message) {
    echo "[SUCCESS] ${message}"
}

Function with Arguments — vars/deployToK8s.groovy

def call(Map config) {
    def image = config.image ?: error("image is required")
    def namespace = config.namespace ?: "default"
    def replicas = config.replicas ?: 1

    logUtils.info "Deploying ${image} to ${namespace} with ${replicas} replicas"

    sh """
        kubectl set image deployment/app app=${image} -n ${namespace} || \
        kubectl create deployment app --image=${image} -n ${namespace}
        kubectl scale deployment/app --replicas=${replicas} -n ${namespace}
        kubectl rollout status deployment/app -n ${namespace} --timeout=300s
    """
}

Loading Resources — vars/renderK8sManifest.groovy

def call(Map config) {
    // Load a YAML template from resources/
    def template = libraryResource('k8s/deployment.yaml')

    // Replace placeholders
    template = template.replace('{{IMAGE}}', config.image)
    template = template.replace('{{NAMESPACE}}', config.namespace)
    template = template.replace('{{REPLICAS}}', config.replicas.toString())

    writeFile file: 'rendered-deployment.yaml', text: template
    sh 'kubectl apply -f rendered-deployment.yaml'
}

Groovy Class — src/com/company/Kubernetes.groovy

package com.company

class Kubernetes implements Serializable {
    def steps

    Kubernetes(steps) {
        this.steps = steps
    }

    def deploy(String image, String namespace) {
        steps.sh "kubectl apply -f deployment.yaml -n ${namespace}"
    }

    def rollback(String deployment, String namespace) {
        steps.sh "kubectl rollout undo deployment/${deployment} -n ${namespace}"
    }

    def scale(String deployment, int replicas, String namespace) {
        steps.sh "kubectl scale deployment/${deployment} --replicas=${replicas} -n ${namespace}"
    }
}

Using in Pipelines

Load at the Top

@Library('shared-lib') _
// or pinned version:
// @Library('shared-lib@v1.2.0') _

pipeline {
    agent any
    stages {
        stage('Deploy') {
            steps {
                deployToK8s(
                    image: 'myapp:1.2.0',
                    namespace: 'staging',
                    replicas: 3
                )
            }
        }
    }
}

Using Classes

@Library('shared-lib') _

def k8s = new com.company.Kubernetes(this)

pipeline {
    agent any
    stages {
        stage('Deploy') {
            steps {
                script {
                    k8s.deploy('myapp:1.0', 'staging')
                }
            }
        }
    }
}

Library-Specific Methods in Pipelines

// In Jenkinsfile — call any var/ function directly
deployToK8s image: 'app:v2', namespace: 'prod', replicas: 5
renderK8sManifest image: 'app:v2', namespace: 'prod'
notifySlack channel: '#deploys', message: 'Deployed app:v2 to prod'

Versioning

Tag Releases

git tag v1.0.0
git push origin v1.0.0

Pin in Pipelines

@Library('shared-lib@v1.0.0') _    // pinned — stable
@Library('shared-lib@main') _      // latest — risky for prod

Global Default Version

In Global Pipeline Libraries, set default version to a tag (v1.0.0), not main. Override per-pipeline for testing.

Best Practices

1. Keep Functions Small and Focused

// Bad — one function does everything
def call(Map config) {
    // 200 lines of build + test + deploy + notify
}

// Good — compose small functions
buildApp(image: config.image)
testApp(image: config.image)
deployToK8s(image: config.image, namespace: config.namespace)
notifySlack(channel: '#deploys', message: "Deployed ${config.image}")

2. Return Values for Data

// vars/getVersion.groovy
def call() {
    return sh(script: 'git describe --tags', returnStdout: true).trim()
}
// In Jenkinsfile
def version = getVersion()
echo "Deploying version ${version}"

3. Validate Inputs Early

def call(Map config) {
    if (!config.image) error("image is required")
    if (!config.namespace) error("namespace is required")
    if (config.replicas && config.replicas < 0) error("replicas must be positive")
    // ...
}

4. Don't Expose Secrets

// Bad — hardcoded
def call(Map config) {
    sh "docker login -u admin -p secret123"
}

// Good — pass credentials ID
def call(Map config) {
    steps.withCredentials([usernamePassword(
        credentialsId: config.credentialsId ?: 'default-creds',
        usernameVariable: 'USER',
        passwordVariable: 'PASS'
    )]) {
        sh 'echo $PASS | docker login -u $USER --password-stdin'
    }
}

5. Document Your API

Each vars/*.groovy should have a README or comments showing usage:

/**
 * Deploy to Kubernetes
 *
 * @param config.image       Docker image tag (required)
 * @param config.namespace   K8s namespace (default: "default")
 * @param config.replicas    Replica count (default: 1)
 * @param config.timeout     Rollout timeout in seconds (default: 300)
 */
def call(Map config) { ... }

Common Patterns

Pipeline Wrapper

// vars/standardPipeline.groovy — defines the whole pipeline
def call(Map config) {
    pipeline {
        agent any
        stages {
            stage('Checkout') {
                steps { checkout scm }
            }
            stage('Build') {
                steps { buildApp(image: config.image) }
            }
            stage('Test') {
                steps { testApp() }
            }
            stage('Deploy') {
                when { branch 'main' }
                steps {
                    deployToK8s(
                        image: config.image,
                        namespace: config.namespace
                    )
                }
            }
        }
        post {
            always { notifySlack(channel: '#builds') }
        }
    }
}

Then every Jenkinsfile becomes:

@Library('shared-lib') _
standardPipeline(image: 'myapp', namespace: 'production')

Related Articles


Last Updated: October 2026
Author: CloudOpsGuide Team
Difficulty: Intermediate
Estimated Reading Time: 14 minutes