What's the practical difference between a Jenkins Declarative Pipeline and a Scripted Pipeline, and why do most teams default to Declarative today?
Quick Answer
Declarative Pipeline enforces a fixed, predictable structure (pipeline { agent {} stages { stage {} } } blocks) with a constrained but validated syntax, while Scripted Pipeline is arbitrary Groovy code giving full programmatic control but no structural guardrails. Most teams default to Declarative because its structure is easier to read, can be validated before running (catching syntax errors without executing a build), and is approachable for developers who aren't deeply familiar with Groovy.
Detailed Answer
Declarative Pipeline defines a specific, opinionated grammar: a pipeline block with required agent and stages sections, where each stage contains steps, and optional sections like post, environment, parameters, and when conditions for conditional stage execution. Because the structure is fixed and known ahead of time, Jenkins can lint/validate a Declarative Jenkinsfile (including via the Jenkins CLI's declarative-linter or the Blue Ocean editor) before ever running it, catching typos and structural mistakes early. Escape hatches to arbitrary Groovy still exist via the script { } block inside a stage's steps, for the (hopefully rare) cases where Declarative's structure genuinely can't express what's needed.
Scripted Pipeline is just Groovy code executed against Jenkins's own pipeline DSL, wrapped in a single node { } block — arbitrary loops, conditionals, functions, and Groovy language features are all directly available with no structural constraint, which gives maximum flexibility but means there's no equivalent up-front validation, and pipelines can become very difficult to read/maintain as Groovy complexity grows, especially for developers less familiar with Groovy who need to read or modify them.
The practical tradeoff most teams land on: Declarative for the vast majority of pipelines, since the structure genuinely helps readability and safety at the cost of some flexibility, dropping into script { } blocks only for the specific logic that needs true programmatic control (dynamic stage generation, complex conditional logic), rather than writing a fully Scripted pipeline from scratch.
Code Example
pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'make build'
}
}
}
}Interview Tip
Mention the script{} escape hatch inside Declarative — it shows you know the two aren't fully mutually exclusive, which is a common point of confusion.