Docker Deployment
Vania compiles to a native executable, making Docker deployments lightweight and fast.
Dockerfile
# Stage 1: Build
FROM dart:stable AS build
WORKDIR /app
COPY pubspec.* ./
RUN dart pub get
COPY . .
RUN dart pub get --offline
# Run migrations (optional - can also be done separately)
# RUN dart run lib/database/migrations/migrate.dart
# Compile to native executable
RUN dart compile exe bin/server.dart -o bin/server
# Stage 2: Runtime
FROM scratch
COPY --from=build /runtime/ /
COPY --from=build /app/bin/server /app/bin/server
COPY --from=build /app/.env /app/.env
COPY --from=build /app/public/ /app/public/
COPY --from=build /app/storage/ /app/storage/
WORKDIR /app
EXPOSE 8000
CMD ["bin/server"]
The scratch base image contains only your binary and its runtime dependencies — no OS, no Dart SDK, no package manager. The result is a minimal container (typically 10–30 MB).
docker-compose.yml
version: '3.8'
services:
app:
build: .
ports:
- "8000:8000"
environment:
- APP_HOST=0.0.0.0
- APP_PORT=8000
- DB_HOST=db
- DB_PORT=3306
- DB_DATABASE=my_app
- DB_USERNAME=root
- DB_PASSWORD=secret
- REDIS_HOST=redis
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
volumes:
- app-storage:/app/storage
db:
image: mysql:8
environment:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: my_app
ports:
- "3306:3306"
volumes:
- db-data:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 5s
timeout: 3s
retries: 10
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
db-data:
app-storage:
Build and Run
docker compose up --build
Your application is available at http://localhost:8000.
Running Migrations
Run migrations as a one-off command:
docker compose exec app dart run lib/database/migrations/migrate.dart --force
--force is required here because the container sets APP_ENV=production, where
the runner refuses to migrate by default — see
Migrations.
Or include migration in the Dockerfile build stage (uncomment the migration line).
Environment Variables
In production, pass environment variables through Docker rather than relying on the .env file:
environment:
- APP_KEY=your-production-key-here
- APP_ENV=production
- APP_DEBUG=false
- DB_HOST=your-rds-endpoint.amazonaws.com
- DB_PASSWORD=${DB_PASSWORD} # from host environment
Production Considerations
- Set
APP_DEBUG=falsein production to hide error details. - Use a strong, unique
APP_KEY(at least 32 characters). - Put the app behind a reverse proxy (nginx, Caddy) for TLS termination.
- Use connection pooling (
DB_POOL=true) under load. - Mount
storage/as a persistent volume so file uploads and sessions survive container restarts. - Set
APP_HOST=0.0.0.0to listen on all interfaces inside the container.