Build Once. Run Anywhere.
Seriously.
Run fast, containerized builds that behave identically everywhere. No more broken pipelines, no more “works on my machine”.
Overcome the CI Feedback Bottleneck
Software engineers lose hours every week waiting for cloud CI runners and dealing with environment drift. EarthBuild gives you the speed and certainty of local iteration.
Traditional CI & Build Friction
"Works on my machine" Syndrome
Mismatched Node, Python, or Go versions, missing local headers, and OS differences create constant environment drift.
Remote CI Guess-and-Check Loops
You cannot easily reproduce remote CI pipelines locally. Every adjustment requires pushing commits and waiting in runner queues.
Untestable Pipeline Scripts in YAML
Multi-step YAML files with embedded shell scripts that cannot be tested, stepped through, or executed directly on local machines.
Redundant Rebuilds & Expensive Cloud Compute
CI runners re-download dependencies, re-compile static assets, and rerun unchanged test suites from scratch on every push.
The EarthBuild Paradigm
Deterministic Container Sandboxing
Every step runs inside an isolated container with declared inputs. If it builds on your workstation, it builds in CI identically.
Instant Local CI Parity
Run
earth +testorearth +cidirectly in your terminal. Get instant local feedback in seconds without pushing a single commit.Familiar, Declarative Syntax
Instant readability with Dockerfile verbs (
FROM,RUN,COPY) and Makefile targets (+build,+docker). Zero complex DSLs.Automatic Parallelism & Instant Caching
EarthBuild automatically discovers target dependencies, executes independent steps simultaneously, and caches layers instantly.
Built for Maximum Engineering Velocity
Everything you need to orchestrate complex polyglot builds, monorepos, and multi-service systems without cognitive fatigue.
Automatic Parallelism
EarthBuild automatically discovers target dependencies and runs independent steps in parallel simultaneously, fully utilizing your CPU cores and network bandwidth without race conditions.
FROM alpine:3.24
COPY +backend/server ./bin/server # Compiles Go backend
COPY +frontend/dist ./public # Compiles React in parallel!
SAVE IMAGE my-app:latest
Docker, Podman & Apple Containers
Supports Podman, Docker, and Apple container engines out-of-the-box by default. Zero host toolchain contamination with complete container isolation.
Universal File & Image Output
While extracting host files with Docker typically requires dedicated --output type=local stages or docker cp, EarthBuild natively exports compiled binaries, test reports, and container images simultaneously in a single build pass.
Monorepo & Remote Repo Imports
Reference and execute targets across nested subdirectories or remote Git repositories with pinpoint caching. Re-use shared proto generators, linters, or base images with one line.
Native Multi-Platform Builds
Build for multiple CPU architectures simultaneously (e.g. linux/amd64 and linux/arm64). Test Apple Silicon and AWS Graviton targets locally with zero hassle.
Zero-Leak Secret Management
Mount API keys, deploy tokens, and NPM/GitHub credentials at build time without ever baking them into container layers or build artifacts. Pass secrets via CLI, environment, or secret managers safely.
Engineered for Zero-Trust Security. Built for AI Agents.
Isolate untrusted open-source packages, protect enterprise credentials, and give autonomous AI coding assistants complete build freedom without risking your host machine.
Hermetic Host Sandboxing
Every build step executes inside an unprivileged container namespace. Malicious npm, pip, or cargo post-install scripts can never access host files, SSH keys, cloud credentials, or environment variables.
The Safe Sandbox for AI Coding Agents
Give autonomous coding agents (Claude Code, Devin, Cursor, Antigravity CLI) full freedom to install dependencies, compile code, and run test suites. If an agent hallucinates a dangerous command, the blast radius is isolated inside the container sandbox.
Zero-Leak Secret Injection
Secrets mounted via RUN --secret exist exclusively in RAM during target execution over secure gRPC. They are never baked into cache layers, exported images, or build logs.
Faster Feedback Loops. Everywhere You Build.
See how EarthBuild layer caching eliminates redundant compilation on your workstation and in CI. Watch a live 3-way execution race comparing a clean build, an incremental build, and a zero-work rebuild.
VERSION 0.8
FROM python:3.14-slim
WORKDIR /app
# deps caches pip dependencies in isolated container layer
deps:
COPY requirements.txt .
RUN --mount=type=cache,target=/root/.cache/pip pip install -r requirements.txt
# test runs unit tests inside isolated container
test:
FROM +deps
COPY src src
RUN pytest src/How EarthBuild Compares to Alternatives
See why engineering teams choose EarthBuild over Dagger, Bazel, Docker Buildx, Makefiles, and brittle CI YAML.
| Capability | EarthBuild | Dagger | Bazel | Docker Buildx | Make / Just | GitHub Actions |
|---|---|---|---|---|---|---|
| Local == CI 100% Parity Exact same build outputs locally & in CI | ✓ Native | ✓ Native | ✓ Native | ◐ Image only | ✕ Host dependent | ✕ Cloud only |
| Automatic Container Sandboxing Zero toolchain drift across laptops | ✓ Yes (Built-in) | ✓ Yes (Containers) | ◐ Strict sandbox | ✓ Yes | ✕ None | ◐ VM-level |
| Familiar Declarative Syntax Familiar Dockerfile & Make verbs | ✓ Declarative DSL | ◐ Code SDKs (Go/TS/Python) | ◐ Starlark DSL | ✓ Dockerfile | ✓ Makefile | ◐ CI YAML |
| Zero-Rewrite Adoption Wrap existing tools (cargo, go, npm, pip) | ✓ Drop-in Wrapper | ◐ Requires SDK code | ✕ Total rewrite | ✓ Drop-in | ✓ Drop-in | ✓ Drop-in |
| Local Artifact Export to Host Native SAVE ARTIFACT ... AS LOCAL | ✓ Native (1-line) | ✓ Via Directory API | ✓ Native | ◐ Requires --output flag | ✓ Host writes | ✕ Upload artifact |
| Automatic DAG Parallelism Build independent targets simultaneously | ✓ Automatic (BuildKit) | ✓ Automatic | ✓ Automatic | ◐ Multi-stage only | ◐ make -j (Unsandboxed) | ◐ Matrix jobs |
| Multi-Tier Layer Caching Local layer cache + remote registry cache | ✓ Instant Layer Cache | ✓ Layer Cache | ✓ Content-addressed | ✓ BuildKit cache | ✕ Timestamp based | ◐ actions/cache |
| Monorepo & Cross-Repo Imports Reference targets across folders or git URLs | ✓ First-class | ✓ Module imports | ✓ Monorepo only | ✕ Single file only | ◐ include directives | ✕ Submodules |
| 100% Community Open Source (MPL-2.0) No proprietary locks, fully self-hostable | ✓ 100% Open Source | ◐ Apache 2.0 + Cloud service | ✓ Open source | ◐ Apache 2.0 (Buildx) / Desktop terms | ✓ Open source | ✕ Proprietary SaaS |
Calculate Your Time, Compute & CO₂ Savings
See how much developer focus, CI runner capacity, and data center energy your team saves by eliminating redundant rebuilds.
Adopt EarthBuild in Under 5 Minutes
Adopt EarthBuild alongside your existing toolchain without disrupting active pipelines or rewriting your repository. Start with a single target and migrate at your own pace.
FROM golang:1.27-alpine3.24 AS deps
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
FROM deps AS test
COPY *.go ./
RUN go test -v ./...
FROM deps AS builder
COPY *.go ./
RUN CGO_ENABLED=0 go build -o bin/app .
FROM alpine:3.24 AS runtime
COPY --from=builder /app/bin/app /usr/local/bin/app
ENTRYPOINT ["/usr/local/bin/app"]VERSION 0.8
FROM golang:1.27-alpine3.24
WORKDIR /app
deps:
COPY go.mod go.sum ./
RUN go mod download
test:
FROM +deps
COPY *.go ./
RUN go test -v ./...
build:
FROM +deps
COPY *.go ./
RUN CGO_ENABLED=0 go build -o bin/app .
SAVE ARTIFACT bin/app AS LOCAL bin/app
docker:
FROM alpine:3.24
COPY +build/bin/app /usr/local/bin/app
ENTRYPOINT ["/usr/local/bin/app"]
SAVE IMAGE --push docker.io/myorg/myapp:latest
all:
BUILD +test
BUILD +build
BUILD +dockergroup "default" {
targets = ["test", "build", "image"]
}
target "test" {
dockerfile = "Dockerfile"
target = "test"
}
target "build" {
dockerfile = "Dockerfile"
target = "builder"
output = ["type=local,dest=bin"]
}
target "image" {
dockerfile = "Dockerfile"
target = "runtime"
tags = ["docker.io/myorg/myapp:latest"]
push = true
}VERSION 0.8
FROM golang:1.27-alpine3.24
WORKDIR /app
deps:
COPY go.mod go.sum ./
RUN go mod download
test:
FROM +deps
COPY *.go ./
RUN go test -v ./...
build:
FROM +deps
COPY *.go ./
RUN CGO_ENABLED=0 go build -o bin/app .
SAVE ARTIFACT bin/app AS LOCAL bin/app
docker:
FROM alpine:3.24
COPY +build/bin/app /usr/local/bin/app
ENTRYPOINT ["/usr/local/bin/app"]
SAVE IMAGE --push docker.io/myorg/myapp:latest
all:
BUILD +test
BUILD +build
BUILD +docker.PHONY: all test build docker
all: test build docker
test:
go test -v ./...
build:
CGO_ENABLED=0 go build -o bin/app .
docker: build
docker build -t docker.io/myorg/myapp:latest .
docker push docker.io/myorg/myapp:latestVERSION 0.8
FROM golang:1.27-alpine3.24
WORKDIR /app
deps:
COPY go.mod go.sum ./
RUN go mod download
test:
FROM +deps
COPY *.go ./
RUN go test -v ./...
build:
FROM +deps
COPY *.go ./
RUN CGO_ENABLED=0 go build -o bin/app .
SAVE ARTIFACT bin/app AS LOCAL bin/app
docker:
FROM alpine:3.24
COPY +build/bin/app /usr/local/bin/app
ENTRYPOINT ["/usr/local/bin/app"]
SAVE IMAGE --push docker.io/myorg/myapp:latest
all:
BUILD +test
BUILD +build
BUILD +dockerpackage main
import (
"context"
"dagger/pipeline/internal/dagger"
)
type Pipeline struct{}
func (m *Pipeline) base(src *dagger.Directory) *dagger.Container {
return dag.Container().
From("golang:1.27-alpine3.24").
WithWorkdir("/app").
WithDirectory(".", src, dagger.ContainerWithDirectoryOpts{Include: []string{"go.mod", "go.sum"}}).
WithExec([]string{"go", "mod", "download"}).
WithDirectory(".", src, dagger.ContainerWithDirectoryOpts{Include: []string{"*.go"}})
}
func (m *Pipeline) Test(ctx context.Context, src *dagger.Directory) (string, error) {
return m.base(src).WithExec([]string{"go", "test", "-v", "./..."}).Stdout(ctx)
}
func (m *Pipeline) Build(ctx context.Context, src *dagger.Directory) (*dagger.File, error) {
bin := m.base(src).
WithEnvVariable("CGO_ENABLED", "0").
WithExec([]string{"go", "build", "-o", "bin/app", "."}).
File("bin/app")
if _, err := bin.Export(ctx, "bin/app"); err != nil {
return nil, err
}
return bin, nil
}
func (m *Pipeline) Publish(ctx context.Context, src *dagger.Directory) (string, error) {
bin, err := m.Build(ctx, src)
if err != nil {
return "", err
}
return dag.Container().
From("alpine:3.24").
WithFile("/usr/local/bin/app", bin).
WithEntrypoint([]string{"/usr/local/bin/app"}).
Publish(ctx, "docker.io/myorg/myapp:latest")
}VERSION 0.8
FROM golang:1.27-alpine3.24
WORKDIR /app
deps:
COPY go.mod go.sum ./
RUN go mod download
test:
FROM +deps
COPY *.go ./
RUN go test -v ./...
build:
FROM +deps
COPY *.go ./
RUN CGO_ENABLED=0 go build -o bin/app .
SAVE ARTIFACT bin/app AS LOCAL bin/app
docker:
FROM alpine:3.24
COPY +build/bin/app /usr/local/bin/app
ENTRYPOINT ["/usr/local/bin/app"]
SAVE IMAGE --push docker.io/myorg/myapp:latest
all:
BUILD +test
BUILD +build
BUILD +dockername: CI & Release
on: [push]
jobs:
pipeline:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with: { go-version: '1.27' }
- uses: actions/cache@v4
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('go.sum') }}
- name: Run Tests
run: go test -v ./...
- name: Build Host Binary
run: CGO_ENABLED=0 go build -o bin/app .
- uses: actions/upload-artifact@v4
with:
name: app-binary
path: bin/app
- uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USER }}
password: ${{ secrets.DOCKER_TOKEN }}
- uses: docker/build-push-action@v6
with:
context: .
push: true
tags: docker.io/myorg/myapp:latestname: CI & Release
on: [push]
jobs:
pipeline:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USER }}
password: ${{ secrets.DOCKER_TOKEN }}
- name: Setup EarthBuild
uses: earthbuild/actions-setup@v2
- name: Test, Build Binary & Push Image
run: earth --ci --push +allLoved by Engineers & DevOps
Here is what developers say about replacing brittle CI YAML and complex monorepo tooling with EarthBuild.