Tyler-R-Kendrick

dagger

Use when building CI/CD pipelines as code with Dagger. Covers Dagger Functions, modules, container-based execution, caching, and SDK usage in TypeScript, Python, and Go. USE FOR: CI/CD pipelines as code, Dagger Functions and modules, container-based build steps, reproducible pipelines DO NOT USE FOR: cloud infrastructure provisioning (use terraform or pulumi), container image authoring (use docker), Kubernetes deployment (use kubernetes)

Tyler-R-Kendrick 10 3 Updated 3mo ago

Resources

4
GitHub

Install

npx skillscat add tyler-r-kendrick/agent-skills/dagger

Install via the SkillsCat registry.

SKILL.md

Dagger

Overview

Dagger is an open-source runtime for composable software workflows. It lets you write CI/CD pipelines in real programming languages (TypeScript, Python, Go) that run in containers, providing automatic caching, reproducibility, and portability across local dev and CI environments.

Core Concepts

  • Functions — typed, cacheable units of work that run in containers
  • Modules — collections of related functions, shareable and composable
  • Dagger Engine — runs functions in containers with automatic caching

TypeScript Example

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:22")
      .withDirectory("/app", source)
      .withWorkdir("/app")
      .withExec(["npm", "ci"])
      .withExec(["npm", "run", "build"]);
  }

  @func()
  async test(source: Directory): Promise<string> {
    return this.build(source)
      .then(ctr => ctr.withExec(["npm", "test"]).stdout());
  }

  @func()
  async publish(source: Directory, tag: string): Promise<string> {
    const built = await this.build(source);
    return built
      .withEntrypoint(["node", "dist/index.js"])
      .publish(`ttl.sh/my-app:${tag}`);
  }
}

Python Example

import dagger
from dagger import dag, function, object_type

@object_type
class MyPipeline:
    @function
    async def build(self, source: dagger.Directory) -> dagger.Container:
        return (
            dag.container()
            .from_("python:3.12")
            .with_directory("/app", source)
            .with_workdir("/app")
            .with_exec(["pip", "install", "-r", "requirements.txt"])
        )

    @function
    async def test(self, source: dagger.Directory) -> str:
        return await (
            (await self.build(source))
            .with_exec(["pytest"])
            .stdout()
        )

CLI Usage

# Initialize a new Dagger module
dagger init --sdk=typescript

# Call a function
dagger call build --source=.

# Run tests
dagger call test --source=.

# Publish a container
dagger call publish --source=. --tag=latest

Key Features

Feature Description
Automatic caching Every function result is cached by inputs; unchanged steps are skipped
Container isolation Functions run in containers, ensuring reproducibility
Type safety Full type checking from your language's SDK
Composability Call functions from other modules
Local + CI parity Same pipeline runs identically on your laptop and in CI

Using Existing Modules

# Use a community module
dagger call -m github.com/dagger/dagger/modules/wolfi container --packages=curl,git

Best Practices

  • Write functions as small, composable units — each function should do one thing.
  • Use withDirectory to pass source code into containers rather than bind-mounting.
  • Leverage automatic caching — structure functions so unchanged inputs skip work.
  • Use dagger call locally to test pipelines before pushing to CI.
  • Use Dagger modules from the community instead of reimplementing common tasks (linting, testing, publishing).
  • Keep secrets out of function arguments — use Dagger's Secret type for sensitive values.