How do declarative and scripted Jenkins pipeline patterns differ in practice, and when should architects use when() conditions, parallel stages, and matrix builds to optimize complex CI/CD workflows?
Quick Answer
Declarative pipelines use a structured pipeline {} block with built-in validation, stages, and post conditions, while scripted pipelines use raw Groovy in a node {} block for maximum flexibility. when() conditions enable conditional stage execution based on branch, environment, or expression. Parallel stages run independent work concurrently, and matrix builds generate combinations of axes to test across multiple dimensions. Architects choose based on the tradeoff between readability and flexibility.
Detailed Answer
Think of cooking from a recipe card versus freestyle cooking. A recipe card (declarative pipeline) has fixed sections — ingredients, prep time, steps, and serving instructions — making it easy for anyone to follow and for quality control to validate. Freestyle cooking (scripted pipeline) gives the chef complete freedom but makes the dish harder to reproduce and audit. Most restaurant chains use recipe cards with the option to add special techniques where needed, and Jenkins pipelines should follow the same pattern: declarative by default with scripted blocks where necessary.
Declarative pipelines enforce structure through the pipeline {} block, which requires agent, stages, and steps sections. This structure enables Jenkins to validate the pipeline syntax before execution, provide a clear Blue Ocean visualization, and apply standardized post-build actions. When() conditions on stages control conditional execution — a stage can run only on the main branch (when { branch 'main' }), only when a file changed (when { changeset 'src/**' }), only when a parameter is set (when { expression { params.DEPLOY == true } }), or combinations of these. This declarative approach makes pipeline behavior visible from the Jenkinsfile without tracing Groovy logic.
Scripted pipelines use a node {} block with raw Groovy, providing access to loops, conditionals, exception handling, and dynamic stage generation. This flexibility is necessary for pipelines that generate stages programmatically — such as deploying to a list of regions read from a configuration file, or running different test suites based on file-change detection. However, scripted pipelines lack built-in syntax validation, making errors harder to catch before execution. The script {} block inside a declarative pipeline bridges the gap, allowing Groovy logic within a single stage while keeping the overall pipeline declarative.
Parallel stages and matrix builds address the need for concurrent execution. Parallel stages run independent work simultaneously — building Docker images for three microservices in parallel, or running unit tests and security scans concurrently. Matrix builds multiply axes to generate stage combinations automatically: testing across three JDK versions and two operating systems generates six test stages from a compact matrix definition. Each matrix cell runs as an independent stage, and the failFast option controls whether one cell's failure immediately aborts other cells or lets them complete. Matrix builds with excludes allow skipping specific combinations that are known to be invalid.
The non-obvious gotcha is that parallel stages and matrix builds each consume a separate agent (or container within a Pod). A matrix with 3 JDK versions and 4 databases generates 12 concurrent stages, each needing its own executor. If the Kubernetes cluster cannot schedule 12 Pods simultaneously, builds queue and the theoretical time savings evaporate. Architects should set a parallelism limit on matrix builds, monitor executor utilization, and ensure cluster autoscaler can respond fast enough to prevent long queuing times. Another gotcha is that when() with beforeAgent true skips agent allocation for stages that will not run, which is important for matrix builds where many combinations might be excluded — without beforeAgent, Jenkins allocates agents for stages it will skip, wasting resources.