TL;DR:
- Dagger replaces CI YAML with real code (Python, Go, or TypeScript) — pipelines run identically locally and in CI without “works on my machine” gaps.
- Everything runs in containers via the Dagger engine, so pipelines are reproducible and fully isolated from the host environment.
- Dagger Modules let you publish reusable pipeline components that any team can import, versioned like regular code packages.
YAML-based CI configurations are a common source of friction: they’re hard to test without pushing to a branch, they’re opaque when they fail, and sharing reusable logic across pipelines requires template hacks or copy-paste. Dagger takes a different approach — your pipeline is a program, written in a real language, that you can run on your laptop before it touches CI.
The Core Idea
Dagger exposes a DAG (directed acyclic graph) API for container operations through language-native SDKs. You chain operations like you’d chain function calls: start from a base image, mount source code, run tests, build an artifact, push to a registry. The Dagger engine figures out what can be parallelised and handles caching at each step.
A minimal TypeScript example:
import { dag, Container, object, func } from "@dagger.io/dagger";
@object()
class MyPipeline {
@func()
async test(source: Directory): Promise<string> {
return dag
.container()
.from("node:22-slim")
.withDirectory("/app", source)
.withWorkdir("/app")
.withExec(["npm", "ci"])
.withExec(["npm", "test"])
.stdout();
}
}
Run this locally with dagger call test --source . — it pulls the node container, installs dependencies, runs tests, and returns the output. The same call works in any CI environment by swapping the runner.
Why This Is Better Than YAML
Local debugging. Every CI workflow debugging cycle that requires a commit and a push adds minutes of overhead. With Dagger, you run dagger call locally and get the exact same environment as CI — same container, same tooling, same isolation. A pipeline bug that used to take six push-and-wait cycles to diagnose takes one local run.
Actual language features. Real code means real functions, loops, conditionals, error handling, and tests. You can write unit tests for your pipeline logic. You can compose pipelines using function calls instead of YAML anchors and <<: merge keys.
Reproducibility. Dagger runs everything in containers. There’s no “CI has bash 5.2 but I have bash 3.2” problem. The container is the environment, and it’s the same container everywhere.
Cache efficiency. The Dagger engine caches layer outputs by their inputs. If your dependency installation step hasn’t changed (same lockfile, same base image), it’s served from cache — locally and in CI. This is more granular than GitHub Actions cache actions because the caching is baked into the execution model.
Dagger Modules: Reusable Pipeline Components
Dagger Modules are versioned, importable pipeline components published to the Daggerverse (daggerverse.dev). Instead of copying a Docker build function across 12 repositories, you reference one module:
dagger install github.com/dagger/dagger/modules/docker@v0.9.0
Then call it directly:
import { dag } from "@dagger.io/dagger";
const image = await dag
.docker()
.build({ context: source, dockerfile: "Dockerfile" });
The module ecosystem includes pre-built components for Docker builds, Helm chart deployment, GitHub PR commenting, Slack notifications, Trivy security scans, GoReleaser, and dozens of others. Teams that publish their own modules can share pipeline logic across repositories without duplication.
Running in CI
Dagger pipelines run in existing CI platforms — you keep GitHub Actions, GitLab CI, or Buildkite as the trigger and runner, and Dagger provides the execution layer inside. A GitHub Actions workflow becomes minimal:
name: CI
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dagger/dagger-for-github@v7
- run: dagger call test --source .
- run: dagger call build --source .
- run: dagger call push --source . --tag ${{ github.sha }}
The dagger/dagger-for-github action installs the Dagger CLI and starts the engine. Everything after that is a Dagger call. The same three dagger call commands you’d run locally.
Dagger Cloud
Dagger Cloud (paid tier) adds a shared cache across all CI runs and team members, a web-based trace viewer for every pipeline run, and performance analytics. The shared cache means that when one developer runs the pipeline, the cache is populated for everyone else — subsequent runs (by any developer or CI job) skip already-completed steps. For large builds this can be the difference between a 15-minute CI run and a 3-minute one.
The trace viewer shows the exact DAG of every pipeline run with per-step timings, logs, and cache hit/miss indicators. Debugging a slow pipeline becomes a matter of looking at which step is the bottleneck rather than parsing CI log output.
When to Use Dagger
Dagger is most valuable when:
- Your CI YAML is getting complex — if you have hundreds of lines of YAML with anchors, conditionals, and shared templates that are hard to maintain, Dagger’s code-based approach scales better.
- You have multiple pipelines across multiple repositories — Dagger Modules let you share pipeline logic as versioned packages instead of copy-pasting.
- Your team loses hours to “works locally but fails in CI” — Dagger’s container-based execution model closes the local/CI gap.
- You want to compose pipelines from well-tested components — the Daggerverse module ecosystem covers most common tasks.
Dagger may be overkill if your CI workflow is simple (build, test, deploy in under 50 lines of YAML), your team is comfortable with the current YAML format, or the additional abstraction layer is harder to justify to stakeholders.
Getting Started
# Install Dagger CLI
curl -L https://dl.dagger.io/dagger/install.sh | sh
# Initialise a new module in your project
dagger init --sdk typescript
# Call a function
dagger call --help
The official docs at docs.dagger.io cover module development, calling conventions, and CI platform integration guides for GitHub Actions, GitLab CI, CircleCI, Jenkins, and Buildkite. The Daggerverse at daggerverse.dev is worth browsing before building custom modules — there’s a reasonable chance what you need already exists.
For teams that have outgrown YAML CI and want pipeline logic they can test, share, and debug locally, Dagger is the strongest option currently available.