Project and Setup
The [coast] section is the only required section in a Coastfile. It identifies the project and configures how the Coast container is created. The optional [coast.setup] subsection lets you install packages and run commands inside the container at build time.
[coast]
name (required)
A unique identifier for the project. Used in container names, volume names, state tracking, and CLI output.
[coast]
name = "my-app"
compose
Path to a Docker Compose file. Relative paths are resolved against the project root (the directory containing the Coastfile, or root if set).
[coast]
name = "my-app"
compose = "./docker-compose.yml"
[coast]
name = "my-app"
compose = "./infra/docker-compose.yml"
If omitted, the Coast container starts without running docker compose up. You can either use bare services or interact with the container directly via coast exec.
You cannot set both compose and [services] in the same Coastfile.
runtime
Which container runtime to use. Defaults to "dind" (Docker-in-Docker).
"dind"— Docker-in-Docker with--privileged. The only production-tested runtime. See Runtimes and Services."sysbox"— Uses the Sysbox runtime instead of privileged mode. Requires Sysbox to be installed."podman"— Uses Podman as the inner container runtime.
[coast]
name = "my-app"
runtime = "dind"
root
Overrides the project root directory. By default, the project root is the directory containing the Coastfile. A relative path is resolved against the Coastfile's directory; an absolute path is used as-is.
[coast]
name = "my-app"
root = "../my-project"
This is uncommon. Most projects keep the Coastfile at the actual project root.
worktree_dir
Directories where git worktrees live. Accepts a single string or an array of strings. Defaults to ".worktrees".
# Single directory
worktree_dir = ".worktrees"
# Multiple directories, including an external one
worktree_dir = [".worktrees", ".claude/worktrees", "~/.codex/worktrees"]
Relative paths are resolved against the project root. Paths starting with ~/ or / are treated as external directories — Coast adds a separate bind mount so the container can access them. This is how you integrate with tools like Codex that create worktrees outside the project root.
At runtime, Coast auto-detects the worktree directory from existing git worktrees (via git worktree list) and prefers that over the configured default when all worktrees agree on a single directory.
See Worktree Directories for the full reference, including external directory behavior, project filtering, and examples.
default_worktree_dir
Which directory to use when creating new worktrees. Defaults to the first entry in worktree_dir. Only relevant when worktree_dir is an array.
[coast]
name = "my-app"
worktree_dir = [".worktrees", "~/.codex/worktrees"]
default_worktree_dir = ".worktrees"
autostart
Whether to automatically run docker compose up (or start bare services) when a Coast instance is created with coast run. Defaults to true.
Set to false when you want the container running but want to start services manually — useful for test-runner variants where you invoke tests on demand.
[coast]
name = "my-app"
extends = "Coastfile"
autostart = false
primary_port
Names a port from the [ports] section to use for quick-links and subdomain routing. The value must match a key defined in [ports].
[coast]
name = "my-app"
primary_port = "web"
[ports]
web = 3000
api = 8080
See Primary Port and DNS for how this enables subdomain routing and URL templates.
private_paths
Workspace-relative directories that should be per-instance rather than shared across Coast instances. Each listed path gets its own bind mount from a per-instance storage directory (/coast-private/) inside the container.
[coast]
name = "my-app"
private_paths = ["frontend/.next"]
This solves conflicts caused by multiple Coast instances sharing the same underlying filesystem via bind mounts. When two instances both run next dev against the same project root, the second instance sees the first's .next/dev/lock file lock and refuses to start. With private_paths, each instance gets its own .next directory so the locks don't collide.
Use private_paths for any directory where concurrent instances writing to the same inode causes problems: file locks, build caches, PID files, or tool-specific state directories.
Accepts an array of relative paths. Paths must not be absolute, must not contain .., and must not overlap (e.g., listing both frontend/.next and frontend/.next/cache is an error). See Private Paths for the full concept.
[coast]
name = "my-app"
private_paths = ["frontend/.next", ".turbo", "apps/web/.next"]
[coast.setup]
Customizes the Coast container itself — installing tools, running build steps, and materializing config files. Everything in [coast.setup] runs inside the DinD container (not inside your compose services).
packages
APK packages to install. These are Alpine Linux packages since the base DinD image is Alpine-based.
[coast.setup]
packages = ["nodejs", "npm", "git", "curl"]
run
Shell commands executed in order during build. Use these for installing tools that aren't available as APK packages.
[coast.setup]
packages = ["nodejs", "npm", "python3", "wget", "bash", "ca-certificates"]
run = [
"ARCH=$(uname -m | sed 's/aarch64/arm64/' | sed 's/x86_64/amd64/') && wget -qO /tmp/go.tar.gz https://go.dev/dl/go1.24.1.linux-${ARCH}.tar.gz && tar -C /usr/local -xzf /tmp/go.tar.gz && rm /tmp/go.tar.gz",
"GOBIN=/usr/local/bin go install github.com/air-verse/air@v1.61.7",
]
[[coast.setup.files]]
Files to create inside the container. Each entry has a path (required, must be absolute), content (required), and optional mode (3-4 digit octal string).
[coast.setup]
packages = ["nodejs", "npm"]
run = ["mkdir -p /app/config"]
[[coast.setup.files]]
path = "/app/config/dev.json"
content = '''
{
"logLevel": "debug",
"featureFlags": { "newDashboard": true }
}
'''
mode = "0644"
Validation rules for file entries:
pathmust be absolute (start with/)pathmust not contain..componentspathmust not end with/modemust be a 3 or 4 digit octal string (e.g."600","0644")
Full example
A Coast container set up for Go and Node.js development:
[coast]
name = "my-fullstack-app"
compose = "./docker-compose.yml"
runtime = "dind"
worktree_dir = [".worktrees", "~/.codex/worktrees"]
primary_port = "web"
[coast.setup]
packages = ["nodejs", "npm", "python3", "make", "curl", "git", "bash", "ca-certificates", "wget", "gcc", "musl-dev"]
run = [
"ARCH=$(uname -m | sed 's/aarch64/arm64/' | sed 's/x86_64/amd64/') && wget -qO /tmp/go.tar.gz https://go.dev/dl/go1.24.1.linux-${ARCH}.tar.gz && tar -C /usr/local -xzf /tmp/go.tar.gz && rm /tmp/go.tar.gz && ln -s /usr/local/go/bin/go /usr/local/bin/go",
"GOBIN=/usr/local/bin go install github.com/air-verse/air@v1.61.7",
"pip3 install --break-system-packages pgcli",
]
[[coast.setup.files]]
path = "/app/config/dev.json"
content = '''
{
"logLevel": "debug",
"featureFlags": { "newDashboard": true }
}
'''
mode = "0644"