Jenkins Pipeline — Declarative CI/CD Syntax Complete Guide
Advertisement
Introduction
Why This Matters
Jenkins remains one of the most widely deployed CI/CD platforms in enterprise environments. Declarative pipeline syntax — introduced to replace scripted pipelines — gives teams a structured, readable format that lives in version control alongside application code. Mastering Jenkinsfile authoring means your build process is reproducible, reviewable, and recoverable when things go wrong.
Declarative Pipeline Structure
Every declarative pipeline follows a required top-level structure:
pipeline {
agent any
environment {
APP_NAME = 'my-service'
REGISTRY = 'registry.example.com'
}
options {
timeout(time: 1, unit: 'HOURS')
buildDiscarder(logRotator(numToKeepStr: '10'))
disableConcurrentBuilds()
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Build') {
steps {
sh 'npm ci'
sh 'npm run build'
}
}
stage('Test') {
steps {
sh 'npm test -- --reporter=junit'
junit 'test-results.xml'
}
}
stage('Deploy') {
when {
branch 'main'
}
steps {
sh 'npm run deploy'
}
}
}
post {
always {
cleanWs()
}
failure {
emailext(
subject: "Build FAILED: ${env.JOB_NAME} #${env.BUILD_NUMBER}",
body: "Check console: ${env.BUILD_URL}",
to: 'team@example.com'
)
}
success {
slackSend(color: 'good', message: "Build passed: ${env.JOB_NAME}")
}
}
}Agent Configuration
Agents define where a pipeline or stage runs:
// Global agent: any available node
pipeline {
agent any
}
// Docker agent: runs inside container
pipeline {
agent {
docker {
image 'node:20-alpine'
args '-v /tmp:/tmp'
}
}
}
// Kubernetes pod agent
pipeline {
agent {
kubernetes {
yaml '''
apiVersion: v1
kind: Pod
spec:
containers:
- name: node
image: node:20
command: [sleep, infinity]
'''
defaultContainer 'node'
}
}
}
// Stage-level agent override
stage('Build on Linux') {
agent { label 'linux' }
steps {
sh 'uname -a'
}
}Parallel Stages
Run stages concurrently to reduce pipeline duration:
stage('Test Suite') {
parallel {
stage('Unit Tests') {
steps {
sh 'npm run test:unit'
}
}
stage('Integration Tests') {
steps {
sh 'npm run test:integration'
}
}
stage('Lint') {
steps {
sh 'npm run lint'
}
}
}
}Parameters and Credentials
pipeline {
parameters {
string(name: 'VERSION', defaultValue: 'latest', description: 'Image version')
booleanParam(name: 'SKIP_TESTS', defaultValue: false)
choice(name: 'ENV', choices: ['staging', 'production'], description: 'Target env')
}
stages {
stage('Deploy') {
steps {
withCredentials([
usernamePassword(
credentialsId: 'docker-registry',
usernameVariable: 'DOCKER_USER',
passwordVariable: 'DOCKER_PASS'
)
]) {
sh 'docker login -u $DOCKER_USER -p $DOCKER_PASS registry.example.com'
sh "docker push registry.example.com/app:${params.VERSION}"
}
}
}
}
}Shared Libraries
Reuse pipeline logic across multiple repositories:
// Jenkinsfile in application repo
@Library('company-pipeline-lib') _
standardPipeline(
name: 'my-service',
registry: 'registry.example.com',
deployEnvs: ['staging', 'production']
)// vars/standardPipeline.groovy in shared library
def call(Map config) {
pipeline {
agent any
stages {
stage('Build') {
steps {
sh "docker build -t ${config.registry}/${config.name} ."
}
}
}
}
}Common Mistakes
- Storing credentials directly in Jenkinsfile instead of the Jenkins credential store
- Using scripted pipeline syntax (
node { }) when declarative (pipeline { }) is clearer - Missing
cleanWs()in post steps, causing disk exhaustion on build agents - Not using
disableConcurrentBuilds()for deployment pipelines that should not run simultaneously - Omitting
whenconditions on deploy stages, causing accidental production deployments from feature branches
Best Practices
- Store your Jenkinsfile at the repo root and version it with code
- Pin Docker image versions in agent blocks — avoid
latesttags - Use parallel stages for test and lint steps to cut pipeline wall time
- Keep credentials in Jenkins Credential Store; reference by ID only
- Use shared libraries for DRY pipeline logic across multiple projects
- Set build timeouts to prevent hung pipelines from blocking agents indefinitely
- Archive test results and artifacts for post-build analysis
Key Takeaways
- Declarative pipeline syntax (
pipeline { }) is the recommended modern approach over scripted pipelines - The
agentdirective controls where pipeline stages execute — supports Docker, Kubernetes, and labeled nodes - The
postblock handles always, success, failure, and unstable outcomes after all stages parallelstages run concurrently and reduce total pipeline execution time- Jenkins Shared Libraries enable teams to extract and reuse pipeline logic across repositories
whenconditions prevent stages like Deploy from running on non-main branches- Credentials should always be injected via
withCredentials— never hardcoded in Jenkinsfile - The
optionsblock (timeout,disableConcurrentBuilds,buildDiscarder) controls pipeline behavior globally
Advertisement
Related reading
GitHub Actions Complete Guide 2026 — CI/CD Pipelines, Workflows, and Automation5 min readCI/CD Pipeline Design Guide 2026 — From Commit to Production in Under 15 Minutes6 min readAnsible Configuration Management 2026 — Automate Server Setup and Deployments7 min readDevOps Engineer Roadmap 2026 — From Zero to $150K+ in 18 Months9 min readPython Virtual Environments — The Right Way to Manage Dependencies5 min readGitHub Actions in Production — Reusable Workflows, OIDC Auth, and Cutting Build Times6 min read