How to Deploy Bun to Docker Without Writing a Dockerfile
You can containerize any Bun application without writing a Dockerfile using migetpacks. It auto-detects your Bun version from .bun-version or bunfig.toml, caches dependencies with bun install, detects your entry point automatically, and produces an optimized slim image. One command, zero configuration.
Why Is Writing a Dockerfile for Bun So Complicated?
A production-ready Bun Dockerfile requires:
- Choosing between
oven/bunandoven/bun:slimimages - Proper layer ordering for
bun installcaching - Handling both
bun.lock(text) andbun.lockb(binary) formats - Entry point detection for TypeScript files
- Running build scripts if present
- Bun-specific environment configuration
Bun is new and tutorials are often outdated or miss caching best practices.
How Do I Containerize a Bun App Without a Dockerfile?
Open your terminal, navigate to your Bun project, and run:
cd ~/projects/my-bun-api
docker run --rm \
-v "$PWD":/workspace/source \
-v /var/run/docker.sock:/var/run/docker.sock \
-e OUTPUT_IMAGE=my-bun-api:latest \
miget/migetpacks:latest
That's it. migetpacks will:
- Detect Bun from
bun.lock,bun.lockb,bunfig.toml, or.bun-version - Read version from
.bun-versionorbunfig.toml - Run
bun installwith caching - Run
bun run buildif a build script exists - Output a slim production image
How Does migetpacks Detect Bun?
migetpacks detects Bun when any of these signals are present:
| Priority | Signal |
|---|---|
| 1 | bun.lock or bun.lockb (lockfiles) |
| 2 | bunfig.toml (config file) |
| 3 | .bun-version (version file) |
| 4 | bun-types in package.json dependencies |
Bun detection runs after backend frameworks (Ruby, Python, Go, etc.) but before Node.js.
How Is the Bun Version Detected?
| Priority | Source | Example |
|---|---|---|
| 1 | BUN_VERSION env var | BUN_VERSION=1.3.4 |
| 2 | .bun-version file | 1.3.4 |
| 3 | version in bunfig.toml | version = "1.3.4" |
| 4 | Default | Latest stable |
How Is the Entry Point Detected?
The entry point is automatically detected in this order:
.ts/.jsfile referenced inscripts.startofpackage.json- Common file patterns:
index.ts,server.ts,app.ts,main.ts,src/index.ts,src/server.ts,index.js,server.js - Falls back to
index.ts
What Does the Generated Dockerfile Look Like?
# Builder stage
FROM oven/bun:1.3.4 AS builder
WORKDIR /build
COPY package.json bun.lock ./
RUN bun install
COPY . .
RUN bun run build
# Runtime stage
FROM oven/bun:1.3.4-slim
WORKDIR /app
COPY --from=builder /build /app
You never write or maintain this file - migetpacks handles it automatically.
What Run Command Is Used?
The default run command:
bun run {entrypoint}
Override with RUN_COMMAND or a Procfile:
web: bun run server.ts
What About the Build Script?
If package.json contains a "build" script, bun run build is automatically executed after dependency installation. Override with BUILD_COMMAND:
docker run --rm \
-v "$PWD":/workspace/source \
-v /var/run/docker.sock:/var/run/docker.sock \
-e OUTPUT_IMAGE=my-bun:latest \
-e BUILD_COMMAND="bun run build:prod" \
miget/migetpacks:latest
How Do I Build Secure Distroless Images?
Enable Docker Hardened Images for minimal containers:
docker run --rm \
-v "$PWD":/workspace/source \
-v /var/run/docker.sock:/var/run/docker.sock \
-e OUTPUT_IMAGE=my-app:latest \
-e USE_DHI=true \
miget/migetpacks:latest
DHI images for Bun are available starting from version 1.3.6. The runtime image is distroless with no shell.
What's the Difference Between Bun, Node.js, and Deno?
| Runtime | Package Manager | TypeScript | Speed |
|---|---|---|---|
| Bun | bun (built-in) | Native | Fastest |
| Node.js | npm/yarn/pnpm | Via build step | Standard |
| Deno | deno (built-in) | Native | Fast |
Next Steps
- Full Bun documentation - version detection, caching, DHI
- Deploy on Miget - unlimited apps, one price
- Star on GitHub - migetpacks is open source
- Related guides: Node.js, Deno