Jenkinsfile Fundamentals
A Jenkinsfile is a text file, checked into source control alongside the application code it builds, that defines a Jenkins Pipeline using code rather than manual point-and-click job configuration in the Jenkins web UI. This 'Pipeline as Code' approach was a significant shift for Jenkins users: pipeline definitions became versioned, reviewable in pull requests, reproducible across environments, and recoverable if the Jenkins controller were ever rebuilt from scratch, none of which was true of the old free-style job configuration stored only inside Jenkins' internal XML files. Almost all modern Jenkins usage centers on the Jenkinsfile, typically using the declarative syntax covered elsewhere, so understanding its core directives is essential groundwork.
Cricket analogy: A Jenkinsfile checked into source control is like writing a team's batting order into an official, published scorecard rather than the captain scribbling it on a napkin in the dressing room -- the scorecard version is reviewable by selectors, reproducible for the next match, and recoverable even if the dressing room whiteboard gets wiped.
The core directives: agent, stages, steps
Every declarative Jenkinsfile requires an agent directive specifying where the pipeline (or, if set to none at the top level, each individual stage) runs — agent any uses any available agent, agent { label 'x' } targets agents with a specific label, and agent { docker { image 'node:20' } } runs the stage inside a freshly-started container from that image. Inside stages, each stage('Name') { steps { ... } } block groups related work and is what shows up as a distinct segment in Jenkins' pipeline visualization (including Blue Ocean and the classic stage view). steps is where the actual work happens: shell commands via sh (or bat/powershell on Windows), source checkout via checkout scm, and calls into any of the hundreds of plugin-provided pipeline steps.
Cricket analogy: The agent directive is like choosing which ground a match is played on -- agent any is playing at whichever venue is available, agent { label 'x' } is insisting on a spin-friendly pitch in Chennai, and agent { docker { image 'node:20' } } is like building a brand-new, freshly-prepared pitch just for this match; stages are the session breaks (morning, afternoon, evening) that structure the day, and steps are the actual deliveries bowled within each session.
environment, parameters, and options
The environment block defines environment variables available to all steps (or scoped to a single stage if declared inside it), and it is the idiomatic place to bind credentials via credentials('id'), which Jenkins automatically masks in console log output. The parameters block declares build parameters — string, booleanParam, choice, and others — that surface as a form when a human triggers a build manually, letting one Jenkinsfile serve many parameterized use cases (e.g. choosing a target environment). The options block configures pipeline-wide behavior such as timeout(time: 30, unit: 'MINUTES'), retry(2), disableConcurrentBuilds(), and timestamps() for log formatting.
Cricket analogy: The environment block is like a team's confidential dressing-room signals available to every player, with sensitive ones (credentials) shared only through the coach's private earpiece never shouted aloud; parameters are like a pre-match form where the captain picks conditions (pitch type, format); and options are ground rules like a rain timeout, a retry for a washed-out toss, and a rule barring two matches on the same ground at once (disableConcurrentBuilds).
pipeline {
agent any
options {
timeout(time: 30, unit: 'MINUTES')
disableConcurrentBuilds()
}
parameters {
choice(name: 'ENVIRONMENT', choices: ['staging', 'production'], description: 'Deploy target')
}
environment {
DEPLOY_TOKEN = credentials('deploy-token-id')
}
stages {
stage('Checkout') {
steps { checkout scm }
}
stage('Build') {
steps { sh 'make build' }
}
stage('Deploy') {
when { expression { params.ENVIRONMENT == 'production' } }
steps { sh './deploy.sh --env=${ENVIRONMENT}' }
}
}
post {
always { archiveArtifacts artifacts: 'build/**', fingerprint: true }
failure { echo 'Build failed — check console output.' }
}
}The when directive attached to a stage is one of declarative pipeline's most powerful features: it lets a single Jenkinsfile conditionally include or skip an entire stage based on branch name, a build parameter, an environment variable, or a custom Groovy expression { }, without needing separate Jenkinsfiles per branch or environment.
The post section defines actions that run after all stages complete, based on the final build result: always runs regardless of outcome (ideal for artifact archiving or workspace cleanup), success and failure run conditionally, changed runs only if the result differs from the previous build (useful for 'build is fixed now' or 'build just broke' notifications rather than repeating the same alert every run), and cleanup always runs last, even after other post conditions, and is the conventional place for deleteDir() workspace cleanup.
Cricket analogy: The post section is like a team's end-of-match routine: always is the mandatory kit collection done regardless of result, success and failure are the celebratory team huddle versus the somber review meeting, changed is only sending the town a special parade if the result flipped from a loss last match to a win now (not repeating the same announcement every win), and cleanup is the groundstaff always rolling the covers last, after every other post-match ritual is done.
A common beginner mistake is putting credential values directly into sh step strings via Groovy interpolation, e.g. sh "curl -H 'Authorization: ${DEPLOY_TOKEN}'". Depending on how the string is built, this can bypass Jenkins' automatic credential masking in the console log. The safer pattern is to let the shell itself read the environment variable — sh 'curl -H "Authorization: $DEPLOY_TOKEN"' — using single quotes so Groovy does not interpolate the secret into the literal step string that gets logged.
- A Jenkinsfile turns pipeline configuration into version-controlled, reviewable code ('Pipeline as Code').
agent,stages, andstepsare the three directives required to define where and what a pipeline runs.environmentbinds env vars and credentials;parametersdefines user-facing build inputs;optionsconfigures pipeline-wide behavior like timeouts.- The
whendirective conditionally runs a stage based on branch, parameters, or a custom expression. postruns cleanup/notification logic keyed on build outcome: always, success, failure, changed, cleanup.- Credentials should be referenced via
credentials('id')and passed to shell steps with single quotes so Jenkins' log-masking applies correctly.
Practice what you learned
1. What is the primary benefit of defining a pipeline in a Jenkinsfile rather than the classic Jenkins UI job configuration?
2. Which directive would you use to run a specific stage only when a build parameter equals 'production'?
3. Which post condition runs only when the current build's result differs from the immediately preceding build?
4. Why should a secret environment variable be referenced with single quotes inside an `sh` step rather than Groovy string interpolation?
5. What does `agent { docker { image 'node:20' } }` do in a stage?
Was this page helpful?
You May Also Like
Declarative vs Scripted Pipelines
Compare Jenkins' two pipeline authoring styles — the structured, opinionated declarative syntax versus the fully programmable Groovy-based scripted syntax — and when to reach for each.
Jenkins Architecture Basics
Understand Jenkins' controller/agent architecture, how builds are distributed to executors, and the core components — controller, agents, executors, and the job queue.
Jenkins Plugins and Agents
Explore how Jenkins' plugin ecosystem extends core functionality and how agents are provisioned, connected, and secured — including static, SSH, and dynamic cloud agents.
Managing Secrets in CI/CD
CI/CD pipelines need credentials for external systems, so secrets must be stored encrypted, injected at runtime, scoped narrowly, and never committed to source control or build logs.
Related Reading
Related Study Notes in DevOps
Browse all study notesNginx Study Notes
DevOps · 30 topics
DevOpsAnsible Study Notes
DevOps · 30 topics
DevOpsAdvanced Kubernetes Study Notes
Kubernetes · 30 topics
DevOpsAdvanced Bash Scripting Study Notes
Bash · 30 topics
DevOpsApache Kafka Study Notes
Kafka · 30 topics
DevOpsDocker & Kubernetes Study Notes
YAML · 40 topics