Skip to main content

Filesystems

This page contains practical examples for working with files and directories in Dagger. Each section below provides code examples in multiple languages and demonstrates different approaches to filesystem operations.

Clone a remote Git repository into a container

The following Dagger Function accepts a Git repository URL and a Git reference. It copies the repository at the specified reference to the /src path in a container and returns the modified container.

note

For examples of SSH-based cloning, including private or public Git repositories with an SSH reference format, select the SSH tabs below. This approach requires explicitly forwarding the host SSH_AUTH_SOCK to the Dagger Function. Learn more about this in Dagger's security model.

package main

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

// Demonstrates cloning a Git repository over HTTP(S).
//
// For SSH usage, see the SSH snippet (CloneWithSsh).
type MyModule struct{}

func (m *MyModule) Clone(ctx context.Context, repository string, ref string) *dagger.Container {
d := dag.Git(repository).Ref(ref).Tree()

return dag.Container().
From("alpine:latest").
WithDirectory("/src", d).
WithWorkdir("/src")
}

Examples

Clone the public dagger/dagger GitHub repository to /src in the container:

dagger -c 'clone https://github.com/dagger/dagger 196f232a4d6b2d1d3db5f5e040cf20b6a76a76c5'

Clone the public dagger/dagger GitHub repository at reference 196f232a4d6b2d1d3db5f5e040cf20b6a76a76c5 to /src in the container and open an interactive terminal to inspect the container filesystem:

dagger <<EOF
clone https://github.com/dagger/dagger 196f232a4d6b2d1d3db5f5e040cf20b6a76a76c5 |
terminal
EOF

Clone over SSH with socket forwarding:

dagger <<EOF
clone-with-ssh git@github.com:dagger/dagger.git 196f232a4d6b2d1d3db5f5e040cf20b6a76a76c5 $SSH_AUTH_SOCK |
terminal
EOF

Mount or copy a directory or remote repository to a container

The following Dagger Function accepts a Directory argument, which could reference either a directory from the local filesystem or from a remote Git repository. It mounts the specified directory to the /src path in a container and returns the modified container.

note

When working with private Git repositories, ensure that SSH authentication is properly configured on your Dagger host.

package main

import (
"context"

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

type MyModule struct{}

// Return a container with a mounted directory
func (m *MyModule) MountDirectory(
ctx context.Context,
// Source directory
source *dagger.Directory,
) *dagger.Container {
return dag.Container().
From("alpine:latest").
WithMountedDirectory("/src", source)
}

An alternative option is to copy the target directory in the container. The difference between these two approaches is that mounts only take effect within your workflow invocation; they are not copied to, or included, in the final image. In addition, any changes to mounted files and/or directories will only be reflected in the target directory and not in the mount sources.

tip

Besides helping with the final image size, mounts are more performant and resource-efficient. The rule of thumb should be to always use mounts where possible.

package main

import (
"context"

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

type MyModule struct{}

// Return a container with a specified directory
func (m *MyModule) CopyDirectory(
ctx context.Context,
// Source directory
source *dagger.Directory,
) *dagger.Container {
return dag.Container().
From("alpine:latest").
WithDirectory("/src", source)
}

Examples

  • Mount the /myapp host directory to /src in the container and return the modified container:

    dagger -c 'mount-directory ./myapp/'
  • Mount the public dagger/dagger GitHub repository to /src in the container and return the modified container:

    dagger -c 'mount-directory https://github.com/dagger/dagger#main'
  • Mount the private user/foo GitHub repository to /src in the container and return the modified container:

    dagger -c 'mount-directory ssh://git@github.com/user/foo#main'
  • Mount the public dagger/dagger GitHub repository to /src in the container and list the contents of the directory:

    dagger -c 'mount-directory https://github.com/dagger/dagger#main | directory /src | entries'
  • Copy the /myapp host directory to /src in the container and return the modified container:

    dagger -c 'copy-directory ./myapp/'
  • Copy the public dagger/dagger GitHub repository to /src in the container and return the modified container:

    dagger -c 'copy-directory https://github.com/dagger/dagger#main'
  • Copy the private user/foo GitHub repository to /src in the container and return the modified container:

    dagger -c 'copy-directory ssh://git@github.com/user/foo#main'
  • Copy the public dagger/dagger GitHub repository to /src in the container and list the contents of the directory:

    dagger -c 'copy-directory https://github.com/dagger/dagger#main | directory /src | entries'

Modify a copied directory or remote repository in a container

The following Dagger Function accepts a Directory argument, which could reference either a directory from the local filesystem or from a remote Git repository. It copies the specified directory to the /src path in a container, adds a file to it, and returns the modified container.

warning

When a host directory or file is copied or mounted to a container's filesystem, modifications made to it in the container do not automatically transfer back to the host.

Data flows only one way between Dagger operations, because they are connected in a DAG. To transfer modifications back to the local host, you must explicitly export the directory or file back to the host filesystem.

note

When working with private Git repositories, ensure that SSH authentication is properly configured on your Dagger host.

When working with private Git repositories, ensure that SSH authentication is properly configured on your Dagger host. :::

package main

import (
"context"

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

type MyModule struct{}

// Return a container with a specified directory and an additional file
func (m *MyModule) CopyAndModifyDirectory(
ctx context.Context,
// Source directory
source *dagger.Directory,
) *dagger.Container {
return dag.Container().
From("alpine:latest").
WithDirectory("/src", source).
WithExec([]string{"/bin/sh", "-c", `echo foo > /src/foo`})
}

Examples

Copy the /myapp host directory to /src in the container, add a file to it, and return the modified container:

dagger -c 'copy-and-modify-directory ./myapp/'

Copy the public dagger/dagger GitHub repository to /src in the container, add a file to it, and return the modified container:

dagger -c 'copy-and-modify-directory github.com/dagger/dagger#main'

Copy the private user/foo GitHub repository to /src in the container, add a file to it, and return the modified container:

dagger -c 'copy-and-modify-directory ssh://git@github.com/user/foo#main'

Copy the public dagger/dagger GitHub repository to /src in the container, add a file to it, and list the contents of the directory:

dagger -c 'copy-and-modify-directory https://github.com/dagger/dagger#main | directory /src | entries'

Copy a subset of a directory or remote repository to a container using filters specified at run-time

The following Dagger Function accepts a Directory argument, which could reference either a directory from the local filesystem or a remote Git repository. It copies the specified directory to the /src path in a container, using a filter pattern specified at call-time to exclude specified sub-directories and files, and returns the modified container.

note

When working with private Git repositories, ensure that SSH authentication is properly configured on your Dagger host.

note

This is an example of post-call filtering with directory filters.

package main

import (
"context"

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

type MyModule struct{}

// Return a container with a filtered directory
func (m *MyModule) CopyDirectoryWithExclusions(
ctx context.Context,
// Source directory
source *dagger.Directory,
// Exclusion pattern
// +optional
exclude []string,
) *dagger.Container {
return dag.Container().
From("alpine:latest").
WithDirectory("/src", source, dagger.ContainerWithDirectoryOpts{Exclude: exclude})
}

Examples

Copy the current host directory to /src in the container, excluding all sub-directories and files starting with dagger, and return the modified container:

dagger -c 'copy-directory-with-exclusions . --exclude=dagger*'

Copy the public dagger/dagger GitHub repository to /src in the container, excluding all Markdown files, and list the contents of the directory:

dagger <<EOF
copy-directory-with-exclusions https://github.com/dagger/dagger#main --exclude=*.md |
directory /src |
entries
EOF

Copy the private user/foo GitHub repository to /src in the container, excluding all Markdown files, and list the contents of the directory:

dagger <<EOF
copy-directory-with-exclusions ssh://git@github.com/user/foo#main --exclude=*.md |
directory /src |
entries
EOF

Copy a subset of a directory or remote repository to a container using pre-defined filters

The following Dagger Function accepts a Directory argument, which could reference either a directory from the local filesystem or a remote Git repository. It copies the specified directory to the /src path in a container, using pre-defined filter patterns to exclude specified sub-directories and files, and returns the modified container.

note

When working with private Git repositories, ensure that SSH authentication is properly configured on your Dagger host.

note

This is an example of pre-call filtering with directory filters.

package main

import (
"context"
"main/internal/dagger"
)

type MyModule struct{}

func (m *MyModule) CopyDirectoryWithExclusions(
ctx context.Context,
// +ignore=["*", "!**/*.md"]
source *dagger.Directory,
) (*dagger.Container, error) {
return dag.
Container().
From("alpine:latest").
WithDirectory("/src", source).
Sync(ctx)
}

Examples

Copy the specified host directory to /src in the container, excluding everything except Markdown files, and return the modified container:

dagger -c 'copy-directory-with-exclusions ../docs'

Copy the public dagger/dagger GitHub repository to /src in the container, excluding everything except Markdown files, and list the contents of the /src directory in the container:

dagger -c 'copy-directory-with-exclusions https://github.com/dagger/dagger#main | directory /src | entries'

Mount or copy a local or remote file to a container

The following Dagger Function accepts a File argument, which could reference either a file from the local filesystem or from a remote Git repository. It mounts the specified file to a container in the /src/ directory and returns the modified container.

package main

import (
"context"
"fmt"

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

type MyModule struct{}

// Return a container with a mounted file
func (m *MyModule) MountFile(
ctx context.Context,
// Source file
f *dagger.File,
) *dagger.Container {
name, _ := f.Name(ctx)
return dag.Container().
From("alpine:latest").
WithMountedFile(fmt.Sprintf("/src/%s", name), f)
}

An alternative option is to copy the target file to the container. The difference between these two approaches is that mounts only take effect within your workflow invocation; they are not copied to, or included, in the final image. In addition, any changes to mounted files and/or directories will only be reflected in the target directory and not in the mount sources.

tip

Besides helping with the final image size, mounts are more performant and resource-efficient. The rule of thumb should be to always use mounts where possible.

package main

import (
"context"
"fmt"

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

type MyModule struct{}

// Return a container with a specified file
func (m *MyModule) CopyFile(
ctx context.Context,
// Source file
f *dagger.File,
) *dagger.Container {
name, _ := f.Name(ctx)
return dag.Container().
From("alpine:latest").
WithFile(fmt.Sprintf("/src/%s", name), f)
}

Examples

Mount the /home/admin/archives.zip file on the host to the /src directory in the container and return the modified container:

dagger -c 'mount-file /home/admin/archives.zip'

Mount the README.md file from the public dagger/dagger GitHub repository to the /src directory in the container:

dagger -c 'mount-file https://github.com/dagger/dagger.git#main:README.md'

Mount the README.md file from the public dagger/dagger GitHub repository to the /src directory in the container and display its contents:

dagger <<EOF
mount-file https://github.com/dagger/dagger.git#main:README.md |
file /src/README.md |
contents
EOF

Copy the /home/admin/archives.zip file on the host to the /src directory in the container and return the modified container:

dagger -c 'copy-file /home/admin/archives.zip'

Copy the /home/admin/archives.zip file on the host to the /src directory in the container and list the contents of the directory:

dagger -c 'copy-file /home/admin/archives.zip | directory /src | entries'

Copy the README.md file from the public dagger/dagger GitHub repository to the /src directory in the container:

dagger -c 'copy-file https://github.com/dagger/dagger.git#main:README.md'

Copy the README.md file from the public dagger/dagger GitHub repository to the /src directory in the container and display its contents:

dagger <<EOF
copy-file https://github.com/dagger/dagger.git#main:README.md |
file /src/README.md |
contents
EOF

Copy a file to the Dagger module runtime container for custom processing

The following Dagger Function accepts a File argument and copies the specified file to the Dagger module runtime container. This makes it possible to add one or more files to the runtime container and manipulate them using custom logic.

package main

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

type MyModule struct{}

// Copy a file to the Dagger module runtime container for custom processing
func (m *MyModule) CopyFile(ctx context.Context, source *dagger.File) {
source.Export(ctx, "foo.txt")
// your custom logic here
// for example, read and print the file in the Dagger Engine container
fmt.Println(os.ReadFile("foo.txt"))
}

Examples

Copy the data.json host file to the runtime container and process it:

dagger -c 'copy-file ../data.json'

Export a directory or file to the host

The following Dagger Functions return a just-in-time directory and file. These outputs can be exported to the host with dagger call ... export ....

note

When a host directory or file is copied or mounted to a container's filesystem, modifications made to it in the container do not automatically transfer back to the host. Data flows only one way between Dagger operations, because they are connected in a DAG. To transfer modifications back to the local host, you must explicitly export the directory or file back to the host filesystem.

package main

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

type MyModule struct{}

// Return a directory
func (m *MyModule) GetDir() *dagger.Directory {
return m.Base().
Directory("/src")
}

// Return a file
func (m *MyModule) GetFile() *dagger.File {
return m.Base().
File("/src/foo")
}

// Return a base container
func (m *MyModule) Base() *dagger.Container {
return dag.Container().
From("alpine:latest").
WithExec([]string{"mkdir", "/src"}).
WithExec([]string{"touch", "/src/foo", "/src/bar"})
}

Examples

  • Export the directory returned by the Dagger Function to the /home/admin/export path on the host:

    dagger -c 'get-dir | export /home/admin/export'
  • Export the file returned by the Dagger Function to the /home/admin/myfile path on the host:

    dagger -c 'get-file | export /home/admin/myfile'

Request a file over HTTP/HTTPS and save it in a container

package main

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

type MyModule struct{}

func (m *MyModule) ReadFileHttp(
ctx context.Context,
url string,
) *dagger.Container {
file := dag.HTTP(url)
return dag.Container().
From("alpine:latest").
WithFile("/src/myfile", file)
}

Examples

Request the README.md file from the public dagger/dagger GitHub repository over HTTPS, save it as /src/myfile in the container, and return the container:

dagger -c 'read-file-http https://raw.githubusercontent.com/dagger/dagger/refs/heads/main/README.md'

Request the README.md file from the public dagger/dagger GitHub repository over HTTPS, save it as /src/myfile in the container, and display its contents:

dagger <<EOF
read-file-http https://raw.githubusercontent.com/dagger/dagger/refs/heads/main/README.md |
file /src/myfile |
contents
EOF

Set a module-wide default path

The following Dagger module uses a constructor to set a module-wide Directory argument and point it to a default path on the host. This eliminates the need to pass a common Directory argument individually to each Dagger Function in the module. If required, the default path can be overridden by specifying a different Directory value at call time.

package main

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

type MyModule struct {
Source *dagger.Directory
}

func New(
// +defaultPath="."
source *dagger.Directory,
) *MyModule {
return &MyModule{
Source: source,
}
}

func (m *MyModule) Foo(ctx context.Context) ([]string, error) {
return dag.Container().
From("alpine:latest").
WithMountedDirectory("/app", m.Source).
Directory("/app").
Entries(ctx)
}

Examples

Call the Dagger Function without arguments. The default path (the current directory .) is used:

dagger -c foo

Call the Dagger Function with a constructor argument. The specified directory (/src/myapp) is used:

dagger -c 'my-module --source $(host | directory /src/myapp) | foo'