DEV Community

Alex Spinov
Alex Spinov

Posted on

Dagger Has a Free CI/CD API That Runs Pipelines as Code

Dagger lets you write CI/CD pipelines in TypeScript, Python, or Go — not YAML. Run the same pipeline locally and in CI with container-based caching.

TypeScript Pipeline

import { dag, Container, Directory } from '@dagger.io/dagger';

async function main() {
  // Get source code
  const src = dag.host().directory('.');

  // Build
  const build = dag.container()
    .from('node:20-slim')
    .withDirectory('/app', src)
    .withWorkdir('/app')
    .withExec(['npm', 'install'])
    .withExec(['npm', 'run', 'build']);

  // Test
  const test = build.withExec(['npm', 'test']);
  await test.stdout();

  // Publish container image
  const image = build
    .withEntrypoint(['npm', 'start'])
    .publish('ttl.sh/my-app:latest');

  console.log(`Published: ${await image}`);
}
Enter fullscreen mode Exit fullscreen mode

Python Pipeline

import dagger

async def main():
    async with dagger.Connection() as client:
        src = client.host().directory(".")

        python = (
            client.container()
            .from_("python:3.12-slim")
            .with_directory("/app", src)
            .with_workdir("/app")
            .with_exec(["pip", "install", "-r", "requirements.txt"])
            .with_exec(["pytest", "-v"])
        )

        output = await python.stdout()
        print(output)
Enter fullscreen mode Exit fullscreen mode

Run Anywhere

# Local
dagger run node pipeline.mts

# GitHub Actions — same pipeline, no YAML conversion needed
# .github/workflows/ci.yml
# - run: dagger run node pipeline.mts

# GitLab CI — same command
# script: dagger run node pipeline.mts
Enter fullscreen mode Exit fullscreen mode

Caching (Automatic)

Dagger caches every operation by default. Second runs skip unchanged steps:

const deps = dag.container()
  .from('node:20')
  .withDirectory('/app', src.directory('.'), { include: ['package*.json'] })
  .withExec(['npm', 'ci']);
// This layer is cached if package.json hasn't changed

const app = deps
  .withDirectory('/app', src)
  .withExec(['npm', 'run', 'build']);
// Only this rebuilds when source changes
Enter fullscreen mode Exit fullscreen mode

Why This Matters

  • No YAML: Write pipelines in real programming languages
  • Local = CI: Same pipeline works everywhere
  • Container caching: Automatic, granular, fast
  • Portable: Works with any CI provider

Need custom CI/CD pipelines or build automation? I build developer tools. Check out my web scraping actors on Apify or reach out at spinov001@gmail.com for custom solutions.

Top comments (0)