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/toolchainor/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.