Dagger lets you write CI/CD pipelines in TypeScript, Python, or Go — run them locally, debug them in your IDE, then execute the same pipeline on any CI system.
Why Dagger Matters
Every CI system has its own YAML dialect. Moving from GitHub Actions to GitLab CI means rewriting everything. Dagger pipelines are code that runs anywhere — your laptop, GitHub Actions, GitLab, CircleCI, or bare metal.
What you get for free:
- Write CI/CD in TypeScript, Python, or Go — not YAML
- Run pipelines locally with
dagger call— test before pushing - Same pipeline runs on ANY CI system (GitHub Actions, GitLab, Jenkins)
- Built on containers — every step is reproducible and cacheable
- GraphQL API for composing pipeline modules
- Dagger Cloud: real-time pipeline visualization and caching
Quick Start
# Install Dagger
curl -fsSL https://dl.dagger.io/dagger/install.sh | sh
# Initialize module
dagger init --sdk=typescript
# Run a function
dagger call build --source=.
# Run tests
dagger call test --source=.
Build + Test + Deploy Pipeline
import { dag, Container, Directory, object, func } from "@dagger.io/dagger";
@object()
class CiPipeline {
@func()
async build(source: Directory): Promise<Container> {
return dag
.container()
.from("node:20-slim")
.withDirectory("/app", source)
.withWorkdir("/app")
.withExec(["npm", "ci"])
.withExec(["npm", "run", "build"]);
}
@func()
async test(source: Directory): Promise<string> {
const built = await this.build(source);
return built
.withExec(["npm", "test"])
.stdout();
}
@func()
async lint(source: Directory): Promise<string> {
const built = await this.build(source);
return built
.withExec(["npx", "eslint", "src/"])
.stdout();
}
@func()
async deploy(source: Directory, token: string): Promise<string> {
// Run tests first
await this.test(source);
// Build production image
const prod = await this.build(source);
// Push to registry
const ref = await prod
.withLabel("org.opencontainers.image.source", "https://github.com/myapp")
.publish(`ttl.sh/myapp-${Date.now()}:1h`);
return `Deployed: ${ref}`;
}
}
Multi-Language Matrix
@func()
async testMatrix(source: Directory): Promise<string[]> {
const versions = ["18", "20", "22"];
const results: string[] = [];
// Run tests in parallel across Node versions
for (const version of versions) {
const result = await dag
.container()
.from(`node:${version}-slim`)
.withDirectory("/app", source)
.withWorkdir("/app")
.withExec(["npm", "ci"])
.withExec(["npm", "test"])
.stdout();
results.push(`Node ${version}: ${result}`);
}
return results;
}
Use in GitHub Actions (2 lines)
- name: Run Dagger Pipeline
uses: dagger/dagger-for-github@v6
with:
verb: call
args: deploy --source=. --token=env:DEPLOY_TOKEN
Useful Links
- GitHub
- Documentation
- Daggerverse — reusable modules
Automating data collection pipelines? Check out my developer tools on Apify for ready-made web scrapers, or email spinov001@gmail.com for custom solutions.
Top comments (0)