Skip to main content

Toolchains

Dagger toolchains allow you to install and use multiple Dagger modules as composable extensions to your own module. Unlike dependencies or blueprints, toolchains provide a flexible way to combine functionality from multiple modules, making them available as namespaced functions within your module's API.

Key Concepts​

What are Toolchains?​

Toolchains are Dagger modules that are installed into your module to provide additional functionality without needing to integrate with your module's SDK or blueprint. When you install a toolchain:

  • The toolchain's functions become available in your module's API as a namespaced field
  • Multiple toolchains can be installed simultaneously
  • Toolchains work with modules that have an SDK, use a blueprint, or neither
  • Each toolchain maintains its own context and can access files from your module's directory

Use Cases​

Platform Engineering​

Toolchains are ideal for platform teams providing standardized tools to application teams:

# Platform team publishes toolchains
github.com/platform/linter
github.com/platform/security-scanner
github.com/platform/deployer

# App teams install them
dagger toolchain install github.com/platform/linter
dagger toolchain install github.com/platform/security-scanner
dagger toolchain install github.com/platform/deployer

dagger call linter lint

CI/CD Composition​

Build a complete CI/CD pipeline by composing toolchains:

dagger toolchain install github.com/example/tester
dagger toolchain install github.com/example/builder
dagger toolchain install github.com/example/publisher
dagger toolchain install github.com/example/notifier

Run your entire pipeline:

dagger call tester test && \
dagger call builder build && \
dagger call publisher publish && \
dagger call notifier notify --status success

Polyglot Projects​

Use toolchains written in different languages without worrying about compatibility:

# Go toolchain
dagger toolchain install github.com/example/go-linter

# Python toolchain
dagger toolchain install github.com/example/python-tester

# TypeScript toolchain
dagger toolchain install github.com/example/ts-bundler

All toolchains work together seamlessly regardless of their implementation language.

Installing Toolchains​

Install a Toolchain​

To install a toolchain in your module, use the dagger toolchain install command:

dagger toolchain install github.com/example/toolchain

You can install toolchains from:

  • GitHub repositories: github.com/user/repo/path
  • Local paths: ./path/to/toolchain or /absolute/path
  • Git URLs: Any valid Git URL with optional version tags

Install with a Custom Name​

By default, the toolchain is accessible using its module name. If the module name is not suitable or conflicts with a function in your module, you can specify a custom name:

dagger toolchain install github.com/example/toolchain --name mytool

Install Multiple Toolchains​

You can install as many toolchains as you need:

dagger toolchain install github.com/example/hello
dagger toolchain install github.com/example/builder
dagger toolchain install github.com/example/tester

Each toolchain becomes available under its own namespace in your module's API.

Using Toolchains​

Calling Toolchain Functions​

Once installed, toolchain functions are available through the toolchain's namespace. For example, if you installed a toolchain named hello:

dagger call hello message

If the toolchain has a constructor that accepts parameters, you can provide them:

dagger call hello --config myconfig.txt field-config

Accessing Module Files from Toolchains​

Toolchains have access to your module's context directory. This means a toolchain can reference files in your module using default path parameters or explicit file arguments:

// In a toolchain module
func (m *Hello) AppConfig(
ctx context.Context,
// +defaultPath="./app-config.txt"
config *dagger.File,
) (string, error) {
return config.Contents(ctx)
}

When called from your module, app-config.txt will be resolved from your module's directory, not the toolchain's repository.

Toolchains with SDKs​

Toolchains work seamlessly with modules that have an SDK. Your module can implement its own functions while also exposing toolchain functions:

Example: Go Module with Toolchain​

Initialize a Go module and install a toolchain:

dagger init --sdk=go
dagger toolchain install github.com/example/hello

Now you can call both your module's functions and the toolchain's functions:

# Call your module's function
dagger call container-echo --string-arg "hello" stdout

# Call the toolchain's function
dagger call hello message

Toolchains with Blueprints​

Toolchains can be combined with blueprints, giving you the best of both worlds: a blueprint provides the core template for your module, while toolchains add supplementary functionality.

dagger init --blueprint=github.com/example/app-blueprint
dagger toolchain install github.com/example/linter
dagger toolchain install github.com/example/deployer

This configuration allows you to:

  • Use the blueprint's functions as your module's primary API
  • Access additional toolchain functions for auxiliary tasks
  • Keep your module focused while still having access to extended functionality

Toolchains without an SDK​

Even if your module doesn't use an SDK or blueprint, toolchains are valuable. They let you compose functionality from multiple modules without writing any code:

dagger init
dagger toolchain install github.com/example/hello
dagger toolchain install github.com/example/builder
dagger toolchain install github.com/example/tester

Your module becomes a collection point for these toolchains, making their combined functionality available through a single interface:

dagger call hello message
dagger call builder build --source ./app
dagger call tester test --source ./app

Filtering Toolchain Checks​

When you install a toolchain that includes checks, all checks from that toolchain are automatically included when you run dagger check. However, there may be times when you want to exclude certain checks from a toolchain while keeping others. The ignoreChecks configuration allows you to selectively filter out specific checks from a toolchain.

Using ignoreChecks​

To ignore checks from a toolchain, you can manually edit your dagger.json configuration file to add an ignoreChecks array to the toolchain configuration:

{
"name": "my-app",
"engineVersion": "v0.16.0",
"toolchains": [
{
"name": "linter",
"source": "github.com/example/linter",
"ignoreChecks": [
"failing-check",
"optional-check"
]
}
]
}

The check patterns in ignoreChecks are scoped to the toolchain, so you don't need to include the toolchain name prefix. For example, if a toolchain named linter has a check linter:code-style, you would only specify code-style in the ignoreChecks array.

Using Glob Patterns​

The ignoreChecks configuration supports glob patterns, allowing you to ignore multiple checks that match a pattern:

{
"name": "my-app",
"engineVersion": "v0.16.0",
"toolchains": [
{
"name": "security-scanner",
"source": "github.com/example/security",
"ignoreChecks": [
"experimental-*",
"*-beta"
]
}
]
}

This is useful when you want to:

  • Exclude all experimental or beta checks: experimental-*, *-beta
  • Skip checks for specific components: frontend-*, *-integration
  • Ignore checks by category: style-*, performance-*

When to Use ignoreChecks​

Common use cases for ignoring toolchain checks include:

  • Gradual adoption: Ignore failing checks while your codebase is being updated to meet new standards
  • Environment-specific checks: Skip checks that don't apply to certain projects or environments
  • Experimental features: Exclude experimental or beta checks that may not be stable
  • Performance optimization: Skip expensive checks that aren't critical for your workflow

Viewing Active Checks​

To see which checks are available after applying ignoreChecks filters, use the dagger check -l command:

dagger check -l

This will list all checks that will run, excluding any that match your ignoreChecks patterns.

Best Practices​

Keep Toolchains Focused​

Each toolchain should provide a cohesive set of related functions. Instead of creating a monolithic "everything" toolchain, create smaller, focused toolchains that teams can mix and match.

Namespace Considerations​

When naming toolchains (especially with --name), choose clear, descriptive names that won't conflict with your module's own functions or other toolchains.

Use ignoreChecks Sparingly​

While ignoreChecks provides flexibility, it's generally better to work with toolchain maintainers to address problematic checks at the source. Use ignoreChecks as a temporary measure or for legitimate environment-specific filtering, not as a way to permanently suppress important checks.

Conclusion​

Toolchains provide a powerful way to compose and extend Dagger modules. Whether you're building a platform, assembling a CI/CD pipeline, or creating a collection of useful utilities, toolchains give you the flexibility to combine functionality from multiple sources while maintaining clean, organized APIs.