Bun Docker
Deploy Bun applications in Docker containers using official images.
Official Images
Latest stable
docker pull oven/bun
Specific version
docker pull oven/bun:1.0.0
Variants
oven/bun:latest # Full image (~100MB) oven/bun:slim # Minimal image (~80MB) oven/bun:alpine # Alpine-based (~50MB) oven/bun:distroless # Distroless (~60MB) oven/bun:debian # Debian-based (~100MB)
Basic Dockerfile
FROM oven/bun:1 AS base
WORKDIR /app
Install dependencies
COPY package.json bun.lockb ./ RUN bun install --frozen-lockfile
Copy source
COPY . .
Run
EXPOSE 3000 CMD ["bun", "run", "src/index.ts"]
Multi-Stage Build (Production)
Build stage
FROM oven/bun:1 AS builder
WORKDIR /app
COPY package.json bun.lockb ./ RUN bun install --frozen-lockfile
COPY . . RUN bun run build
Production stage
FROM oven/bun:1-slim AS production
WORKDIR /app
Copy only production dependencies
COPY package.json bun.lockb ./ RUN bun install --frozen-lockfile --production
Copy built assets
COPY --from=builder /app/dist ./dist
Run as non-root
USER bun
EXPOSE 3000 CMD ["bun", "run", "dist/index.js"]
Alpine Image
FROM oven/bun:1-alpine
WORKDIR /app
Alpine uses apk for packages
RUN apk add --no-cache git
COPY package.json bun.lockb ./ RUN bun install --frozen-lockfile
COPY . .
CMD ["bun", "run", "src/index.ts"]
Distroless Image
Build stage
FROM oven/bun:1 AS builder
WORKDIR /app COPY . . RUN bun install --frozen-lockfile RUN bun build src/index.ts --compile --outfile=app
Runtime stage
FROM gcr.io/distroless/base
COPY --from=builder /app/app /app
ENTRYPOINT ["/app"]
Docker Compose
docker-compose.yml
version: "3.8"
services: app: build: . ports: - "3000:3000" environment: - NODE_ENV=production - DATABASE_URL=postgres://db:5432/app depends_on: - db restart: unless-stopped
db: image: postgres:16-alpine environment: POSTGRES_DB: app POSTGRES_USER: user POSTGRES_PASSWORD: password volumes: - postgres_data:/var/lib/postgresql/data
volumes: postgres_data:
Hot Reload in Development
docker-compose.dev.yml
version: "3.8"
services: app: build: context: . dockerfile: Dockerfile.dev ports: - "3000:3000" volumes: - ./src:/app/src - ./package.json:/app/package.json command: bun --hot run src/index.ts
Dockerfile.dev
FROM oven/bun:1
WORKDIR /app
COPY package.json bun.lockb ./ RUN bun install
Source mounted as volume
CMD ["bun", "--hot", "run", "src/index.ts"]
Compiled Binary
FROM oven/bun:1 AS builder
WORKDIR /app COPY . . RUN bun install --frozen-lockfile RUN bun build src/index.ts --compile --outfile=server
Minimal runtime
FROM ubuntu:22.04
Install runtime dependencies
RUN apt-get update && apt-get install -y --no-install-recommends
ca-certificates
&& rm -rf /var/lib/apt/lists/*
COPY --from=builder /app/server /usr/local/bin/server
USER nobody EXPOSE 3000 CMD ["server"]
SQLite with Docker
FROM oven/bun:1
WORKDIR /app
COPY package.json bun.lockb ./ RUN bun install --frozen-lockfile
COPY . .
Create data directory
RUN mkdir -p /app/data
Volume for SQLite database
VOLUME /app/data
ENV DATABASE_PATH=/app/data/app.sqlite
CMD ["bun", "run", "src/index.ts"]
Health Checks
FROM oven/bun:1
WORKDIR /app COPY . . RUN bun install --frozen-lockfile
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3
CMD curl -f http://localhost:3000/health || exit 1
CMD ["bun", "run", "src/index.ts"]
// Health endpoint app.get("/health", (c) => c.json({ status: "ok" }));
Environment Variables
FROM oven/bun:1
WORKDIR /app
Build-time args
ARG NODE_ENV=production ARG API_URL
Runtime env
ENV NODE_ENV=${NODE_ENV} ENV API_URL=${API_URL}
COPY . . RUN bun install --frozen-lockfile
CMD ["bun", "run", "src/index.ts"]
Build with args
docker build --build-arg API_URL=https://api.example.com -t myapp .
Run with env
docker run -e DATABASE_URL=postgres://... myapp
Caching Optimization
FROM oven/bun:1 AS base
WORKDIR /app
Cache dependencies separately
FROM base AS deps COPY package.json bun.lockb ./ RUN bun install --frozen-lockfile
Build
FROM deps AS builder COPY . . RUN bun run build
Production
FROM base AS runner COPY --from=deps /app/node_modules ./node_modules COPY --from=builder /app/dist ./dist COPY package.json ./
USER bun CMD ["bun", "run", "dist/index.js"]
Security Best Practices
FROM oven/bun:1-slim
WORKDIR /app
Don't run as root
USER bun
Copy with correct ownership
COPY --chown=bun:bun package.json bun.lockb ./ RUN bun install --frozen-lockfile --production
COPY --chown=bun:bun . .
Read-only filesystem
(use with: docker run --read-only)
EXPOSE 3000 CMD ["bun", "run", "src/index.ts"]
.dockerignore
node_modules .git .gitignore .md Dockerfile docker-compose* .env* .DS_Store coverage dist .bun
Common Commands
Build
docker build -t myapp .
Run
docker run -p 3000:3000 myapp
Run with env file
docker run --env-file .env -p 3000:3000 myapp
Interactive shell
docker run -it oven/bun sh
Check Bun version
docker run oven/bun bun --version
Common Errors
Error Cause Fix
bun.lockb not found
Missing lockfile Run bun install locally
EACCES permission
File ownership Use --chown=bun:bun
OOM killed
Memory limit Increase container memory
No space left
Large layers Use multi-stage builds
When to Load References
Load references/optimization.md when:
-
Image size reduction
-
Layer caching
-
Build performance
Load references/kubernetes.md when:
-
K8s deployment
-
Horizontal scaling
-
Service mesh