Introduction
Earthly tackles the "my build works on my machine, but not in CI" problem. By running every step in containers (via BuildKit), it guarantees reproducibility. Syntax is a hybrid of Dockerfile + Makefile: familiar yet expressive, with parallel targets, caching, and artifact sharing between targets.
With over 12,000 GitHub stars, Earthly is used by teams that want CI-as-code without GitHub-specific YAML, and by polyglot monorepos that need language-agnostic builds.
What Earthly Does
Earthly parses an Earthfile that declares targets (like Make) with container-based steps (like Dockerfile). Each target runs in an isolated container, cached by layer hash. Targets can depend on other targets (+target syntax), share artifacts via SAVE ARTIFACT, and emit Docker images via SAVE IMAGE.
Architecture Overview
Earthfile (targets: +deps, +build, +test, +docker)
|
[Earthly CLI]
|
[BuildKit engine]
container-based, layer cache
|
+------+------+------+
| | | |
[+deps] [+build][+test][+docker]
shared cache across targets
|
Artifacts (SAVE ARTIFACT)
Images (SAVE IMAGE)
|
Consumers:
- Local dev
- GitHub Actions / GitLab CI / Jenkins
- Earthly Satellites (remote build farm)Self-Hosting & Configuration
VERSION 0.8
all:
BUILD +lint
BUILD +test
BUILD +build-all
build-all:
BUILD +build --GOOS=linux --GOARCH=amd64
BUILD +build --GOOS=linux --GOARCH=arm64
BUILD +build --GOOS=darwin --GOARCH=arm64
build:
ARG GOOS=linux
ARG GOARCH=amd64
FROM golang:1.22-alpine
WORKDIR /src
COPY . .
RUN GOOS=$GOOS GOARCH=$GOARCH go build -o /out/api-$GOOS-$GOARCH ./cmd/api
SAVE ARTIFACT /out/* AS LOCAL dist/
lint:
FROM golangci/golangci-lint:v1.59-alpine
WORKDIR /src
COPY . .
RUN golangci-lint run ./...
# Integrate with GitHub Actions
# - uses: earthly/actions-setup@v1
# - run: earthly --ci +allKey Features
- Earthfile syntax — Dockerfile + Makefile familiar hybrid
- Container-based steps — each step runs in isolation, reproducible
- BuildKit caching — layer cache reused across local + CI
- Parallel targets —
BUILD +a +bruns concurrently - Artifacts — pass outputs between targets, save to host
- Image outputs — emit + push Docker images from targets
- Secrets —
--secretflag or integration with Vault/SSM - Satellites — hosted remote build workers with persistent cache
Comparison with Similar Tools
| Feature | Earthly | Makefile + Docker | Bazel | Nx | BuildKit |
|---|---|---|---|---|---|
| Reproducibility | Strong (containers) | Weak (host deps) | Strongest (hermetic) | JS focus | Strong |
| Learning curve | Low | Low | High | Moderate | Low |
| Multi-lang | Yes | Yes | Yes | Limited | Yes |
| Caching | Layer-based | Manual | Advanced (content) | Input-based | Layer-based |
| Remote cache | Satellites | Manual | Remote build | Nx Cloud | Via BuildKit |
| Best For | Polyglot CI | Simple builds | Huge monorepos | JS monorepos | Custom pipelines |
FAQ
Q: Earthly vs Bazel — when to pick which? A: Bazel offers stronger hermetic guarantees for massive polyglot monorepos but has a steep learning curve. Earthly is much easier to adopt and gets you 80% of the benefits for most teams.
Q: Do I replace my CI YAML?
A: Mostly yes. Keep CI YAML minimal (checkout + earthly +all). The real build logic lives in the Earthfile and runs the same on laptops and in CI.
Q: What are Earthly Satellites? A: Remote build workers with persistent BuildKit caches. They make CI builds dramatically faster by reusing cache across runs and branches — think self-hosted GitHub runners but purpose-built for Earthly.
Q: Is Earthly open source? A: Yes, MPL-2.0. Earthly the company sells Satellites + Cloud features; the local CLI and Earthfile format are fully open.
Sources
- GitHub: https://github.com/earthly/earthly
- Docs: https://docs.earthly.dev
- Company: Earthly
- License: MPL-2.0