In a Jenkins declarative Jenkinsfile, which blocks are mandatory, and where do the actual build commands go?
answer
- one outer block, fixed shape
- where to run, then what to run
- two required children of pipeline
- commands live one level deeper than the stage
- steps holds sh and bat
basics
~20 sA declarative Jenkinsfile is one pipeline block that must contain an agent directive and a stages block. Inside stages, every stage needs a name and a steps block, and the actual commands live in steps. Everything else is optional.
solid answer
~50 sDeclarative syntax has a fixed skeleton. The file opens with `pipeline { }`, and directly inside it Jenkins requires one `agent` directive saying where the work runs and one `stages` block. `stages` holds one or more `stage('Name')` entries, and each stage must contain `steps` (or `parallel`, or nested `stages`). The real work — `sh`, `bat`, `checkout`, plugin steps — goes inside `steps`, never directly under `stage`. Optional directives sit alongside: `environment` for variables, `options`, `parameters`, `triggers`, `tools`, plus per-stage `when` and `post`. `agent any` is the usual starting point; `agent none` at the top is legal only if every stage declares its own agent. Because the shape is fixed, Jenkins parses and validates the whole file before running anything, so a misplaced block fails the build immediately with a line number rather than halfway through.
code
groovy · 15 linespipeline {
agent any
stages {
stage('Build') {
steps {
sh './gradlew build'
}
}
stage('Test') {
steps {
sh './gradlew test'
}
}
}
}go deeper
Be able to write the four-block skeleton from memory — pipeline, agent, stages, stage with steps — and say plainly that commands go in steps, never directly under stage.
Explain what each directive owns and where it is legal: environment and options at pipeline or stage level, when and post per stage, and why agent none forces every stage to declare its own agent.
Show that you use the fixed structure operationally: linting Jenkinsfiles before merge, choosing per-stage agents so long-running stages do not pin an executor, and reading declarative parse errors quickly.
Own the standard: decide what a Jenkinsfile in your organisation is allowed to contain, and how much structure teams get for free versus how much they must hand-roll each time.
## The fixed shape Jenkins supports two pipeline syntaxes. Declarative is the newer, opinionated one: the whole file is a single `pipeline` block whose contents must match a known schema. That schema is small enough to memorise, and knowing it is the first thing an interviewer checks. The smallest legal declarative Jenkinsfile looks like this: ```groovy pipeline { agent any stages { stage('Build') { steps { sh './gradlew build' } } } } ``` Four nested blocks, all four required: `pipeline` → `agent` + `stages` → `stage` → `steps`. ## What each required block owns **`pipeline`** is the outermost block and there is exactly one per file. Nothing may sit outside it except `import` statements and shared-library annotations. **`agent`** answers *where does this run*. `agent any` means any executor Jenkins can find; `agent { label 'linux' }` restricts it; `agent none` declares that the pipeline itself claims no executor, in which case every `stage` must declare its own `agent` or the build fails validation. The agent directive also decides where the workspace lives, and in the default case declarative performs an implicit source checkout for you. **`stages`** is the container. It holds the ordered list of `stage` entries and nothing else. **`stage`** takes a mandatory display name — `stage('Unit tests')` — which is what shows up in the pipeline visualisation and in the build log headers. A stage is a labelled chunk of work, not a scoping trick: you cannot put a `sh` call straight inside it. **`steps`** is where the commands go. Every `stage` must contain exactly one of `steps`, `parallel`, `matrix`, or a nested `stages` block. Inside `steps` you call pipeline steps: `sh 'make'` on Unix, `bat 'build.cmd'` on Windows, `echo`, `checkout scm`, `archiveArtifacts`, and whatever steps your installed plugins contribute. ## The optional directives Around that spine sit optional directives, each legal only in particular positions: ```groovy pipeline { agent any environment { REGISTRY = 'registry.example.com' } options { timestamps() } parameters { string(name: 'TARGET', defaultValue: 'staging') } triggers { cron('H 2 * * *') } tools { jdk 'jdk21' } stages { stage('Deploy') { when { branch 'main' } steps { sh './deploy.sh' } } } } ``` `environment` defines variables (top level for the whole run, or inside a stage for just that stage). `options` sets build-level behaviour. `parameters` declares the inputs the job prompts for. `triggers` schedules the job from inside the file. `tools` installs configured JDK/Maven/Gradle versions onto the agent's PATH. `when` guards a single stage. `post` declares what to run after a stage or after the pipeline, regardless of outcome. ## Why the shape is fixed The rigidity is the feature. Because the file must match a schema, Jenkins parses and validates the *entire* Jenkinsfile before executing the first step. A stage misspelled at the bottom of a 300-line file fails the build in seconds with a message naming the line and what was expected there — you do not spend eleven minutes compiling and then discover a typo in the deploy stage. The same fixed structure is what lets the surrounding tooling work. The Blue Ocean visual editor can round-trip a declarative file because it knows what shapes are legal. "Restart from stage" can resume a finished build at a named stage because the stage list is statically known. A linter can check a file without running it: Jenkins exposes a declarative linter through its CLI and through a validation endpoint on the controller, so a pre-commit hook or a CI check can reject a broken Jenkinsfile before anyone pushes it. ## The mistakes it catches The three errors new users hit are all structural. Putting `sh 'make'` directly under `stage` fails, because a stage's only legal children are the directives plus one of `steps`/`parallel`/`matrix`/`stages`. Writing a bare Groovy `if` inside `steps` fails, because `steps` accepts step calls, not arbitrary control flow — that needs a `script { }` block or a `when` directive. And omitting `agent` fails, because declarative always wants to know where the work happens. All three surface at parse time, which is precisely why most teams start here rather than in scripted syntax.
- What happens if you call sh directly inside a stage block instead of inside steps?The build fails immediately at parse time, before any stage executes. Declarative validates the whole file against its schema first, and a stage's only legal children are its directives plus one of steps, parallel, matrix, or nested stages. The error names the line and lists what was expected there, so you never reach the executor.
- When is agent none at the top level the right choice?When stages need different environments, or when early stages do no real work. agent none means the pipeline claims no global executor, so each stage must declare its own — a Linux label for the build, a Windows label for packaging, a Kubernetes pod for tests. It also stops a long approval or notification stage from holding an executor idle.
- How can you validate a Jenkinsfile without pushing a commit?Jenkins ships a declarative linter: you can pipe the file to the linter command through the Jenkins CLI, or POST it to the controller's pipeline-model-converter validation endpoint. Both check the structure against the declarative schema and report errors with line numbers. Teams wire that into a pre-commit hook or a lint job so broken files never reach the branch.
saying these in an interview costs you the question
- Says pipeline and node blocks are interchangeable
- Puts sh commands directly inside the stage block
- Thinks the agent directive is optional in declarative
- Assumes a syntax error only fails the stage containing it
- Uses stages and steps as if they meant the same thing