Skip to main content

Module Structure

Dagger Functions are packaged, shared and reused using Dagger modules. A new Dagger module is initialized by calling dagger init. This creates a new dagger.json configuration file in the current working directory, together with sample Dagger Function source code. The configuration file will default the name of the module to the current directory name, unless an alternative is specified with the --name argument.

Once a module is initialized, dagger develop --sdk=... sets up or updates all the resources needed to develop the module locally. By default, the module source code will be stored in the current working directory, unless an alternative is specified with the --source argument.

The default template from dagger develop creates the following structure:

.
├── LICENSE
├── dagger.gen.go
├── go.mod
├── go.sum
├── internal
│ ├── dagger
│ ├── querybuilder
│ └── telemetry
└── main.go
└── dagger.json

In this structure:

  • dagger.json is the Dagger module configuration file.
  • go.mod/go.sum manage the Go module and its dependencies.
  • main.go is where your Dagger module code goes. It contains sample code to help you get started.
  • internal contains automatically-generated types and helpers needed to configure and run the module:
    • dagger contains definitions for the Dagger API that's tied to the currently running Dagger Engine container.
    • querybuilder has utilities for building GraphQL queries (used internally by the dagger package).
    • telemetry has utilities for sending Dagger Engine telemetry.

For examples of modules written in Go, see Daggerverse Modules in Go.

note

While you can use the utilities defined in the automatically-generated code above, you cannot edit these files. Even if you edit them locally, any changes will not be persisted when you run the module.

Module layout

You can split your Dagger module into multiple files, not just main.go. To do this, you can just create another file beside main.go (for example, utils.go):

.
│── ...
│── main.go
│── utils.go
└── dagger.json

This file should be inside the same package as main.go, and as such, can access any private variables/functions/types inside the package.

Additionally, you can also split your Dagger module into Go subpackages (for example, utils):

.
│── ...
│── main.go
|── utils
│ └── utils.go
└── dagger.json

Because this is a separate package, you can only use the variables/functions/types that are exported from this package in main.go (you can't access types from main.go in the utils package).

note

Only types and functions in the top-level package are part of the public-facing API for the module.

You can access other Dagger types from a sub-package by importing the generated sub-package dagger/<module>/internal/dagger:

// utils/utils.go

import "dagger/<module>/internal/dagger"

func DoThing(client *dagger.Client) *dagger.Directory {
// we need to pass *dagger.Client in here, since we don't have access to `dag`
...
}

Runtime container

Dagger modules run in a runtime container that's bootstrapped by the Dagger Engine, with the necessary environment to run the Dagger module's code.

The runtime container is currently hardcoded to run in Go 1.21 (although this may be configurable in future).

Language-native packaging

The structure of a Dagger module mimics that of each language's conventional packaging mechanisms and tools.

Dagger modules written for use with the Go SDK are automatically created as Go modules. At module creation time, a go.mod and go.sum file will automatically be created that import the necessary dependencies. Dependencies can be installed and managed just as for any standard Go environment.

After using new dependencies in your code, update your go.mod/go.sum with the newly imported dependencies by using go mod tidy.

Go workspaces

Since it's common to have a sub-directory inside your main project containing your Dagger module code, you can manage your modules using Go workspaces.

When a new Dagger module is created, Dagger attempts to add it to a root go.work if it exists. If not, it can be added manually later with go work use ./path/to/mymodule.

// go.work
go 1.21.7

use (
./path/to/mymodule
)

Go vendor

Go vendor directories are not currently supported. See https://github.com/dagger/dagger/issues/6076 for more information.