Skip to content

Jenkins Shared Libraries — Reusable Pipeline Code Guide

DodaTech Updated 2026-06-24 5 min read

In this tutorial, you'll learn about Jenkins Shared Libraries. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.

Jenkins Shared Libraries let you define reusable pipeline functions, steps, and variables in a separate Repository, allowing teams to share standardized CI/CD logic without duplicating code across hundreds of Jenkinsfiles.

What You'll Learn

Why It Matters

When 50 Microservices each copy-paste the same build-and-deploy logic into their Jenkinsfiles, updating a single step requires touching every Repository. Shared Libraries consolidate pipeline logic into a single source of truth — update one function, and every pipeline using it gets the change immediately. DodaTech reduced pipeline maintenance effort by 80% after moving common build, test, and deploy logic into shared libraries.

Real-World Use

DodaZIP's shared library defines standard stages for Docker image building, container scanning, Kubernetes deployment, and Slack notifications. Any team's Jenkinsfile imports this library and calls dodatechBuild() to get a production-ready pipeline with zero configuration.

flowchart TD
    A[Shared Library Repo] --> B[vars/dodatechBuild.groovy]
    A --> C[vars/sendSlackNotification.groovy]
    A --> D[vars/dockerPublish.groovy]
    A --> E[src/org/dodatech/PipelineUtils.groovy]
    B --> F[Team A Jenkinsfile]
    B --> G[Team B Jenkinsfile]
    B --> H[Team C Jenkinsfile]
    C --> F
    C --> G
    D --> H
    style A fill:#D24939,color:#fff
    style B fill:#4CAF50,color:#fff
â„šī¸ Info

Prerequisites: Understanding of Jenkins Pipeline syntax. Admin access to a Jenkins instance to configure shared libraries.

Repository Structure

Shared libraries follow a standard directory layout:

dodatech-pipeline-lib/
  src/                       # Helper classes
    org/dodatech/
      PipelineUtils.groovy
      DockerUtils.groovy
  vars/                      # Global DSL variables
    dodatechBuild.groovy
    dodatechTest.groovy
    sendSlackNotification.groovy
    dockerPublish.groovy
    deployKubernetes.groovy
  resources/                 # Static resources
    org/dodatech/
      templates/
        build.sh
        deploy.sh

Configuring the Library in Jenkins

// Jenkins configuration (Manage Jenkins > Configure System > Global Pipeline Libraries)
// Name: dodatech-lib
// Default version: main
// Retrieval method: Modern SCM
// Source Code Management: Git
// Project Repository: https://github.com/dodatech/pipeline-lib.git

Writing a Simple Library Step

// vars/dodatechBuild.groovy
def call(Map config = [:]) {
    def nodeVersion = config.nodeVersion ?: '20'
    def buildCommand = config.buildCommand ?: 'npm run build'

    pipeline {
        agent any

        tools {
            nodejs "Node-${nodeVersion}"
        }

        stages {
            stage('Install Dependencies') {
                steps {
                    sh 'npm ci'
                }
            }

            stage('Lint') {
                steps {
                    sh 'npm run lint'
                }
            }

            stage('Build') {
                steps {
                    sh buildCommand
                }
            }

            stage('Test') {
                steps {
                    sh 'npm test'
                }
                post {
                    always {
                        junit '**/junit.xml'
                    }
                }
            }
        }
    }
}

Expected behavior: Any Jenkinsfile can call dodatechBuild(nodeVersion: '22', buildCommand: 'npm run build:prod') to get a complete build pipeline.

Using the Library in a Jenkinsfile

// Jenkinsfile at root of any microservice repository
@Library('dodatech-lib@v2.5') _

dodatechBuild(
    nodeVersion: '22',
    buildCommand: 'npm run build:prod'
)

dockerPublish(
    registry: 'registry.dodatech.com',
    imageName: 'user-service',
    scanEnabled: true
)

deployKubernetes(
    environment: 'staging',
    namespace: 'user-service',
    replicas: 3
)

Expected output: Jenkins resolves the library from the configured Repository at version v2.5, imports the global variables, and executes the three pipeline steps sequentially.

Global Variables with Multiple Methods

// vars/dockerPublish.groovy
def call(Map config) {
    stage('Docker Build') {
        sh "docker build -t ${config.registry}/${config.imageName}:${BUILD_NUMBER} ."
    }

    if (config.scanEnabled) {
        stage('Container Scan') {
            sh "trivy image ${config.registry}/${config.imageName}:${BUILD_NUMBER}"
        }
    }

    stage('Docker Push') {
        withDockerRegistry([credentialsId: 'docker-registry-creds', url: "https://${config.registry}"]) {
            sh "docker push ${config.registry}/${config.imageName}:${BUILD_NUMBER}"
        }
    }
}

Helper Classes in src/

// src/org/dodatech/PipelineUtils.groovy
package org.dodatech

class PipelineUtils implements Serializable {
    static String gitCommitHash() {
        return "git rev-parse --short HEAD".execute().text.trim()
    }

    static String versionFromFile(String filePath) {
        return readFile(filePath).trim()
    }

    static boolean isMainBranch() {
        return env.BRANCH_NAME == 'main'
    }

    static String buildTag(String appName) {
        return "${appName}-${BUILD_NUMBER}-${gitCommitHash()}"
    }
}
// Usage in Jenkinsfile
@Library('dodatech-lib@v2.5') _
import org.dodatech.PipelineUtils

pipeline {
    agent any
    stages {
        stage('Build') {
            steps {
                script {
                    def tag = PipelineUtils.buildTag('auth-service')
                    echo "Tag: ${tag}"
                }
            }
        }
    }
}

Versioning and Branching

// Jenkinsfile using a specific version
@Library('dodatech-lib@v2.5') _

// Jenkinsfile using a feature branch
@Library('dodatech-lib@feature/new-deploy-strategy') _

// Jenkinsfile using default version (configured in Jenkins)
@Library('dodatech-lib') _

Testing Shared Libraries

// test/vars/DockerPublishSpec.groovy
class DockerPublishSpec extends PipelineSpockBase {
    def 'dockerPublish builds and pushes image'() {
        given:
        def config = [registry: 'registry.dodatech.com', imageName: 'test-app']

        when:
        dockerPublish(config)

        then:
        1 * sh("docker build -t registry.dodatech.com/test-app:${BUILD_NUMBER} .")
        1 * sh("docker push registry.dodatech.com/test-app:${BUILD_NUMBER}")
    }
}

Common Configuration Mistakes

  1. Not pinning library versions: Using @Library('dodatech-lib')_ without a version pulls the default branch. Pinning to @Library('dodatech-lib@v2.5')_ ensures consistency across pipelines.

  2. Overwriting library-vended environment variables: Libraries often set env variables that can conflict with Jenkinsfile variables. Use unique prefixes like DODATECH_* to avoid collisions.

  3. Missing Serializable in helper classes: Pipeline steps must be serializable for Jenkins to pause and resume. Add implements Serializable to all helper classes.

  4. Hardcoding credentials in library code: Libraries should accept credential IDs as parameters and use withCredentials internally, not hardcode IDs.

  5. Ignoring library test coverage: Untested library changes break all consuming pipelines. Use JenkinsPipelineUnit or Spock to test library functions.

Practice Questions

  1. What is the purpose of the vars/ directory in a shared library? Answer: The vars/ directory defines global DSL variables that appear as top-level pipeline steps. Each .groovy file in vars/ becomes a callable function.

  2. How do you version shared libraries? Answer: Library versions correspond to Git tags or branches in the library Repository. Use @Library('name@version')_ to pin a specific version.

  3. What is the difference between vars/ and src/ in a shared library? Answer: vars/ defines global DSL functions callable from any Jenkinsfile. src/ contains standard Groovy classes for complex logic, loaded via import statements.

  4. How are shared libraries loaded at pipeline runtime? Answer: The @Library annotation loads the library at pipeline start, checking out the specified version from the configured SCM Repository.

Challenge

Create a Jenkins Shared Library Repository with global variables for building Java (Maven/Gradle), Node.js, and Python applications. Include helper classes for version management, artifact upload to Nexus, and multi-environment Kubernetes deployment. Write unit tests for each function. Create a sample Jenkinsfile that uses all library features.

Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro