DEV Community

Alex Spinov
Alex Spinov

Posted on

Dagger Has a Free API That Lets You Write CI/CD Pipelines in Real Code

Dagger lets you write CI/CD pipelines in TypeScript, Python, or Go instead of YAML. Run the same pipeline locally and in CI — no more YAML debugging on the 47th push.

What Is Dagger?

Dagger is a programmable CI/CD engine. Instead of GitHub Actions YAML or Jenkinsfiles, you write real code with real debugging, real testing, and real IDE support.

Quick Start

# Install Dagger CLI
curl -fsSL https://dl.dagger.io/dagger/install.sh | sh

# Initialize TypeScript module
dagger init --sdk=typescript my-pipeline
Enter fullscreen mode Exit fullscreen mode

Write a Pipeline

// dagger/src/index.ts
import { dag, Container, Directory, object, func } from '@dagger.io/dagger'

@object()
class MyPipeline {
  @func()
  async build(source: Directory): Promise<Container> {
    return dag
      .container()
      .from('node:20-slim')
      .withDirectory('/app', source)
      .withWorkdir('/app')
      .withExec(['npm', 'install'])
      .withExec(['npm', 'run', 'build'])
  }

  @func()
  async test(source: Directory): Promise<string> {
    return dag
      .container()
      .from('node:20-slim')
      .withDirectory('/app', source)
      .withWorkdir('/app')
      .withExec(['npm', 'install'])
      .withExec(['npm', 'test'])
      .stdout()
  }

  @func()
  async lint(source: Directory): Promise<string> {
    return dag
      .container()
      .from('node:20-slim')
      .withDirectory('/app', source)
      .withWorkdir('/app')
      .withExec(['npm', 'install'])
      .withExec(['npx', 'eslint', '.'])
      .stdout()
  }

  @func()
  async publishDocker(source: Directory, tag: string): Promise<string> {
    const built = await this.build(source)
    return built
      .withEntrypoint(['node', 'dist/index.js'])
      .publish(`registry.example.com/myapp:${tag}`)
  }
}
Enter fullscreen mode Exit fullscreen mode

Run Locally

# Run tests (same as CI!)
dagger call test --source=.

# Build
dagger call build --source=.

# Publish Docker image
dagger call publish-docker --source=. --tag=v1.0.0
Enter fullscreen mode Exit fullscreen mode

Use in GitHub Actions

# .github/workflows/ci.yml
name: CI
on: [push]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dagger/dagger-for-github@v6
        with:
          version: latest
          verb: call
          args: test --source=.
Enter fullscreen mode Exit fullscreen mode

Why Dagger?

Feature Dagger GitHub Actions Jenkins
Language TS/Py/Go YAML Groovy
Local run Yes Act (limited) No
Debugging Real debugger Print statements Print statements
Caching Built-in Manual Manual
Portable Any CI GitHub only Jenkins only

Key Benefits

  • Same pipeline locally and in CI: no more "works on my machine"
  • Real language: use loops, conditionals, functions, libraries
  • Type safety: catch errors before pushing
  • Caching: automatic layer caching for faster builds
  • Composable: import and reuse pipeline modules

Building CI/CD for scraping pipelines? Scrapfly handles web data extraction at scale. Email spinov001@gmail.com for CI/CD + scraping setups.

Top comments (0)