Skip to main content

Interactive Terminal

Dagger provides an interactive terminal that can help greatly when trying to debug a pipeline failure.

To use this, set one or more explicit breakpoints in your Dagger pipeline with the Container.terminal() method. Dagger then starts an interactive terminal session at each breakpoint. This lets you inspect a Directory or a Container at any point in your pipeline run, with all the necessary context available to you.

Here is a simple example, which opens an interactive terminal in an alpine container:

dagger core container from --address=alpine terminal

Here is an example of a Dagger Function which opens an interactive terminal at two different points in the Dagger pipeline to inspect the built container:

package main

import (
"dagger/my-module/internal/dagger"
)

type MyModule struct{}

func (m *MyModule) Container() *dagger.Container {
return dag.Container().
From("alpine:latest").
Terminal().
WithExec([]string{"sh", "-c", "echo hello world > /foo && cat /foo"}).
Terminal()
}

The Container.terminal() method can be chained. It returns a Container, so it can be injected at any point in a pipeline (in this example, between Container.from() and Container.withExec() methods).

tip

Multiple terminals are supported in the same Dagger Function; they will open in sequence.

It's also possible to inspect a directory using the Container.terminal() method. Here is an example of a Dagger Function which opens an interactive terminal on a directory:

package main

import (
"context"
)

type MyModule struct{}

func (m *MyModule) SimpleDirectory(ctx context.Context) (string, error) {
return dag.
Git("https://github.com/dagger/dagger.git").
Head().
Tree().
Terminal().
File("README.md").
Contents(ctx)
}

Under the hood, this creates a new container (defaults to alpine) and starts a shell, mounting the directory inside. This container can be customized using additional options. Here is a more complex example, which produces the same result as the previous one but this time using an ubuntu container image and bash shell instead of the default alpine container image and sh shell:

package main

import (
"context"
"dagger/my-module/internal/dagger"
)

type MyModule struct{}

func (m *MyModule) AdvancedDirectory(ctx context.Context) (string, error) {
return dag.
Git("https://github.com/dagger/dagger.git").
Head().
Tree().
Terminal(dagger.DirectoryTerminalOpts{
Container: dag.Container().From("ubuntu"),
Cmd: []string{"/bin/bash"},
}).
File("README.md").
Contents(ctx)
}