Dockerfile Requirements

Burrito builds and runs your application from a Dockerfile. This page covers the rules your Dockerfile must follow, how to install system packages, and best practices for layer caching.

For complete, copy-paste-ready Dockerfiles for every major language and framework, see Example Dockerfiles.

Requirements

Every Dockerfile deployed to Burrito must satisfy these three rules:

  1. Dockerfile in the repository root — Burrito looks for a file named Dockerfile in the root of your git repository
  2. Use EXPOSE to declare your port — Burrito reads the EXPOSE directive from your Dockerfile to determine which port your app listens on. If no EXPOSE is found, it defaults to port 80
  3. Health check endpoint — your app should respond to GET / with a 200 status (used for readiness checks)

If any of these are missing, the deployment will either fail to build or fail the readiness check and be rolled back.

Installing System Packages

Many applications need system libraries (database drivers, image processing, build tools). How you install them depends on your base image.

Debian / Ubuntu (-slim images)

Most official language images default to Debian. Use apt-get:

RUN apt-get update && \
    apt-get install -y --no-install-recommends \
        libpq-dev \
        imagemagick \
    && rm -rf /var/lib/apt/lists/*

Always pair apt-get update with install in one RUN layer. The rm at the end keeps the image small.

Alpine (-alpine images)

Alpine images use apk:

RUN apk add --no-cache \
    postgresql-dev \
    imagemagick

The --no-cache flag avoids storing the package index.

Common Packages

Need Debian (apt-get) Alpine (apk)
PostgreSQL client libs libpq-dev postgresql-dev
MySQL client libs default-libmysqlclient-dev mariadb-dev
Git git git
C compiler / make build-essential build-base
Image processing imagemagick imagemagick
SSL / crypto libssl-dev openssl-dev
XML parsing libxml2-dev libxml2-dev
Curl curl curl

Docker Layer Caching

Docker caches each layer. If a layer hasn't changed, Docker reuses it. The key insight: copy dependency files first, install dependencies, then copy your source code. This way, npm install or pip install only reruns when your dependency files change — not on every code change.

# 1. Copy only the dependency manifest
COPY package.json package-lock.json ./
RUN npm ci --production

# 2. Copy everything else
COPY . .

Dependency Files by Language

Language Copy first
Node.js package.json, package-lock.json (or yarn.lock, pnpm-lock.yaml)
Python requirements.txt (or pyproject.toml, poetry.lock)
Go go.mod, go.sum
Ruby Gemfile, Gemfile.lock
Java (Maven) pom.xml
Java (Gradle) build.gradle, settings.gradle, gradle/
Rust Cargo.toml, Cargo.lock
PHP composer.json, composer.lock
.NET *.csproj, *.sln

.dockerignore

Create a .dockerignore file in your repository root to exclude files from the build context. This speeds up builds and prevents secrets from leaking into images.

.git
.gitignore
.env
.env.*
node_modules
__pycache__
*.pyc
.venv
target
bin
obj
.DS_Store
README.md
LICENSE

Multi-Stage Builds

Use multi-stage builds to keep your final image small. Compile in one stage, copy only the binary or built assets to a minimal runtime stage:

# Build stage — has compilers, build tools, dev dependencies
FROM golang:1.23-alpine AS build
WORKDIR /app
COPY . .
RUN go build -o server .

# Runtime stage — minimal image, only the binary
FROM alpine:3.20
COPY --from=build /app/server /server
EXPOSE 80
CMD ["/server"]

This pattern works for any compiled language (Go, Rust, Java, .NET) and for frontend builds (TypeScript → JavaScript).

Tips

  • Always include an EXPOSE directive — Burrito uses it to detect your app's port. If omitted, it defaults to 80
  • Use -slim or -alpine base images to reduce build time and image size
  • Pin your base image version (node:22-alpine, not node:alpine) for reproducible builds
  • Install only production dependencies — skip dev/test packages in the final image
  • See Example Dockerfiles for complete, working examples for every major stack