Pipeline-as-Code
Pipeline definitions versioned in the repo. GitHub Actions, GitLab CI, Jenkinsfile — and how to keep them DRY at scale.
Overview
What pipeline-as-code is
Pipeline-as-code means the build, test and deploy pipeline is defined as version-controlled source code in the same repository as the application, not as a click-configured job in a CI server's UI.
- Travis CI — .travis.yml — 2011
- GitLab CI — .gitlab-ci.yml — 2015
- Jenkins 2.0 — Jenkinsfile, the release that popularized the shift — 2016
- CircleCI — .circleci/config.yml
- GitHub Actions — .github/workflows/*.yml — 2019
Why it matters
Before pipeline-as-code, CI configuration was a server-side artifact: Jenkins jobs configured through a web UI, drift between environments, no review process for pipeline changes, and no audit trail beyond "Steve modified the build step on Tuesday."
Two stylistic camps
- Declarative — GitHub Actions, GitLab CI, CircleCI, Bitbucket Pipelines, Tekton, Argo Workflows. A YAML document of stages, jobs, steps and triggers that the CI server interprets — Easy to read, lint and validate — Complex logic (loops, conditionals, computed matrices) becomes awkward
- Scripted — Jenkins's Groovy-based Jenkinsfile (and its "declarative pipeline" subset, YAML-shaped Groovy). The pipeline is code with full language semantics — Arbitrary logic, library imports, reuse via shared libraries — Harder to read and lint
Modern adoption
JetBrains 2024 State of Developer Ecosystem survey. GitHub Actions overtook Jenkins around 2022-2023.
- GitHub Actions — ~33%, most popular
- Jenkins — ~28%
- GitLab CI — ~21%
Reusability mechanisms
- GitHub Actions — Reusable workflows (workflow_call) and composite actions. Service repos reference a central file via uses: org/.github/.github/workflows/build-node.yml@v1, versioned by tag
- GitLab CI — include: pulls a fragment from another repo
- Jenkins — Shared Libraries: Groovy libraries imported into every Jenkinsfile
- CircleCI — Orbs: versioned reusable config packages
Key concepts
- Pipeline-as-code
- Pipeline definition lives in the application repo as source-controlled config. Reviewed, versioned, branched alongside code. CI server reads the file; CI server has no separate state. The pipeline is a build artifact, not a server-side configuration.
- Declarative pipeline
- YAML-style pipeline definitions (GitHub Actions, GitLab CI, Tekton). Easy to read; awkward for complex logic. Best for the common case of "build → test → deploy." Most teams should default here.
- Scripted pipeline
- Code-style pipeline definitions (Jenkinsfile in Groovy). Powerful and flexible; harder to constrain and review. Reach for it only when YAML's logic ceiling actually bites.
- Reusable workflow / composite action
- GitHub Actions: a workflow file callable from other workflows via workflow_call. Versioned by ref. Equivalent: GitLab include:, CircleCI Orbs, Jenkins Shared Libraries. Lets a platform team ship one canonical "build a Node service" workflow consumed by 30 service repos.
- Self-hosted runner
- A runner agent owned by the team rather than the CI provider. Required for on-prem dependencies, GPU, or scale beyond hosted limits. Introduces supply-chain attack surface — use ephemeral or per-job runners; never run on long-lived persistent VMs.
- SHA pinning for actions
- Reference actions by SHA, not tag: uses: actions/checkout@b4ffde65... not @v4. The SHA is content-addressed; if the upstream rewrites the v4 tag to point at malicious code (supply chain attack), your pipeline still uses the original. Comment the version next to the SHA. Dependabot updates SHAs automatically.
When to use it
- Migrating off click-configured Jenkins jobs to a versioned, reviewable pipeline definition
- Building a platform team that ships pipelines as a product to dozens of service teams
- Standardising language- or framework-specific build patterns across an org via reusable workflows
- Auditing pipeline changes — every modification is a PR with a reviewer
Interview questions
- Why is pipeline-as-code strictly better than UI-configured jobs?
- GitHub Actions vs Jenkins vs GitLab CI — when do you pick which?
- How do you keep pipelines DRY across 30 microservices without creating a single point of failure?
Sign up free to read the full topic
More DevOps topics
- OpenFeature & Feature Flag Governance
- OpenTelemetry
- OpenTelemetry Collector — Pipelines & Deployment
- Overlay vs Underlay Networking
- PCI-DSS and SOC 2 for Kubernetes
- Perl and PowerShell for Build Automation
- Platform Engineering
- Platform Engineering & IDP Design
- Platform Engineering Maturity Model
- Pod Startup and Scheduling Errors — ImagePullBackOff, CrashLoopBackOff, Pending, Evicted
- Policy as Code
- Production Patterns
Start free on Cariara · Coding problems · System design studio