LogoRevali

Overview

Generate production-ready Dockerfiles for Revali applications

Revali Docker is a Build Construct that automatically generates optimized, production-ready Dockerfiles for your Revali applications. It creates multi-stage Docker builds that compile your Dart server into an efficient, standalone executable.

Overview#

When you run revali build, the Docker construct automatically generates a Dockerfile configured specifically for your project. This Dockerfile uses a multi-stage build process to create a minimal, secure production image.

Key features:

  • Multi-stage builds - Small final image size
  • Optimized compilation - AOT-compiled Dart binaries
  • Environment variables - Support for build-time configuration
  • Build mode support - Respects release/profile modes
  • Secure base images - Uses official Dart and Alpine Linux
  • Production-ready - Includes only necessary runtime dependencies

Quick Start#

Generate a Dockerfile for your project:

dart run revali build

The generated Dockerfile will be created at:

.revali/build/Dockerfile

Build and run your Docker image:

# Build the image
docker build -f .revali/build/Dockerfile -t my-app .

# Run the container
docker run -p 8080:8080 my-app

Generated Dockerfile Structure#

Here's an example of a generated Dockerfile with explanations:

.revali/build/Dockerfile
# Stage 1: Build environment
FROM dart:stable AS build

WORKDIR /app
COPY . .
RUN rm pubspec_overrides.yaml || true

# Get dependencies
RUN dart pub get

# Build the server with Revali
RUN dart run revali build --release --type constructs --recompile

# Compile to native executable
RUN dart compile exe .revali/server/server.dart -o /app/server

# Stage 2: Runtime environment
FROM alpine:latest

# Install runtime dependencies
RUN apk add --no-cache libc6-compat ca-certificates

# Copy compiled server
COPY --from=build /app/server /app/bin/server

# Run the server
CMD ["/app/bin/server"]

Build Modes#

The generated Dockerfile respects the build mode specified in the revali build command.

Release Mode (Default)#

Generates a fully optimized production build:

dart run revali build --release

Generated Dockerfile includes:

# Full optimizations enabled
RUN dart run revali build --release --type constructs --recompile
RUN dart compile exe .revali/server/server.dart -o /app/server

Characteristics:

  • Maximum performance optimizations
  • Smallest binary size
  • No debug information
  • Recommended for production

Profile Mode#

Generates an optimized build with profiling capabilities:

dart run revali build --profile

Generated Dockerfile includes:

# Optimizations with profiling enabled
RUN dart run revali build --profile --type constructs --recompile
RUN dart compile exe .revali/server/server.dart -o /app/server

Characteristics:

  • Performance optimizations
  • Profiling information included
  • Revali logs enabled
  • Useful for performance analysis

Environment Variables#

Pass environment variables to your Docker build using --dart-define:

dart run revali build --dart-define=API_KEY=secret --dart-define=PORT=3000

This generates a Dockerfile with build argument declarations (values must be provided via --build-arg when building):

Dockerfile
FROM dart:stable AS build

WORKDIR /app
COPY . .
RUN rm pubspec_overrides.yaml || true

RUN dart pub get

# Build arguments from --dart-define (values provided via --build-arg at build time)
ARG API_KEY
ARG PORT

RUN dart run revali build --release --type constructs --recompile

# Pass to compilation
RUN dart compile exe .revali/server/server.dart -o /app/server \
  -DAPI_KEY=$API_KEY \
  -DPORT=$PORT

FROM alpine:latest

RUN apk add --no-cache libc6-compat ca-certificates

COPY --from=build /app/server /app/bin/server

CMD ["/app/bin/server"]

Providing Values at Build Time#

Provide build argument values when building the Docker image:

docker build \
  --build-arg API_KEY=production_key \
  --build-arg PORT=8080 \
  -f .revali/build/Dockerfile \
  -t my-app .

Building Docker Images#

Basic Build#

Build an image from the generated Dockerfile:

docker build -f .revali/build/Dockerfile -t my-app:latest .

Tagged Build#

Tag your image for versioning:

docker build -f .revali/build/Dockerfile -t my-app:v1.0.0 .

Multi-Platform Build#

Build for multiple architectures:

docker buildx build \
  --platform linux/amd64,linux/arm64 \
  -f .revali/build/Dockerfile \
  -t my-app:latest .

Cross-Compiling#

By default, Revali Docker compiles your server inside the Docker build (the multi-stage dart:stable build shown above). If you'd rather compile once on the host — no container pull, no pub get inside Docker — add a build: section to your revali.yaml:

revali.yaml
build:
  target_os: linux
  target_arch: [x64, arm64]

revali build will compile the server directly via dart compile exe --target-os --target-arch — cross-compiling to Linux works from any host OS (macOS, Windows, or Linux), no extra toolchain required. Revali Docker then generates a minimal single-stage Dockerfile instead:

FROM alpine:latest

RUN apk add --no-cache libc6-compat ca-certificates

# single arch:
COPY .revali/build/server-amd64 /app/bin/server
# multiple arches (picks the right one via buildx's $TARGETARCH):
# ARG TARGETARCH
# COPY .revali/build/server-${TARGETARCH} /app/bin/server
RUN chmod +x /app/bin/server

CMD ["/app/bin/server"]

When target_arch lists more than one architecture, the ARG TARGETARCH form is used automatically — the existing Multi-Platform Build docker buildx build --platform ... command above still works unchanged, now backed by fast native host compiles instead of a QEMU-emulated compile inside the container for each target platform.

.dockerignore#

If you exclude .revali/ in your .dockerignore (recommended below, since it holds dev-time artifacts you don't want in your build context), you need to explicitly re-include .revali/build/ — otherwise the COPY above can't find the compiled binary. Docker's !negation pattern cannot re-include a path whose parent directory was itself excluded, so exclude .revali/'s children individually instead of the directory itself:

.dockerignore
.revali/*
!.revali/build

--dart-define values#

Without cross-compiling, dart-defines are deferred to docker build --build-arg at image-build time (see Environment Variables above). With cross-compiling, they're baked into the executable directly at revali build time using their real resolved values, since there's no container build step left to defer them to.

Build with Custom Arguments#

Provide build arguments:

docker build \
  --build-arg API_KEY=my_key \
  --build-arg DATABASE_URL=postgres://... \
  -f .revali/build/Dockerfile \
  -t my-app .

Running Docker Containers#

Basic Run#

Start your container:

docker run -p 8080:8080 my-app

With Environment Variables#

Pass runtime environment variables:

docker run \
  -e PORT=3000 \
  -e LOG_LEVEL=debug \
  -p 3000:3000 \
  my-app

Detached Mode#

Run in the background:

docker run -d -p 8080:8080 --name my-app-container my-app

With Volume Mounts#

Mount persistent storage:

docker run \
  -p 8080:8080 \
  -v $(pwd)/data:/app/data \
  my-app

Docker Compose#

For more complex deployments, use Docker Compose:

docker-compose.yml
version: "3.8"

services:
  app:
    build:
      context: .
      dockerfile: .revali/build/Dockerfile
      args:
        API_KEY: ${API_KEY}
        DATABASE_URL: ${DATABASE_URL}
    ports:
      - "8080:8080"
    environment:
      - PORT=8080
      - LOG_LEVEL=info
    restart: unless-stopped
    networks:
      - app-network

  database:
    image: postgres:15
    environment:
      POSTGRES_DB: myapp
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password
    volumes:
      - postgres-data:/var/lib/postgresql/data
    networks:
      - app-network

networks:
  app-network:

volumes:
  postgres-data:

Run with Docker Compose:

docker-compose up -d

Image Optimization#

Best Practices#

Use .dockerignore

Create a .dockerignore file to exclude unnecessary files:

.dockerignore
.git/
.github/
.dart_tool/
.revali/
build/
*.md
LICENSE
.gitignore
.env
node_modules/
doc-site/
examples/
test/

Deployment#

Once you have your Docker image, deploy it to your preferred platform:

  1. Fly.io - Global deployment with automatic scaling
  2. DigitalOcean App Platform - Managed container hosting
  3. Heroku - Simple container deployment
  4. Railway - Easy deployment with auto-scaling
  5. Render - Developer-friendly container platform

What's Next?#