Run 2.0 is experimental and opt-in. Use run v2 to access the v2 commands.
This guide helps you migrate from Docker/Docker Compose to Run 2.0.
| Metric | Docker | Run 2.0 | Improvement |
|---|---|---|---|
| Startup time | 5-10s | <10ms | 500-1000x |
| Image size | 50-500MB | <5MB | 10-100x |
| Memory usage | 256MB+ | <10MB | 25x+ |
| Build time | 1-5min | <10s | 6-30x |
| Cold start | 500ms+ | <10ms | 50x+ |
Additional Benefits:
Keep Docker for stateful services (databases, caches), migrate application logic to WASI.
Docker Compose -> Run 2.0 Hybrid
App (Docker) -> App (WASI) <10ms
DB (Docker) -> DB (Docker) Keep
Cache -> Cache Keep
Migrate everything to WASI components.
Run 2.0 Hybrid -> Run 2.0 Pure
App (WASI) -> App (WASI)
DB (Docker) -> DB (WASI) All WASI
Cache -> Cache
# Install Run 2.0
curl -sSL https://run.esubalew.et/install.sh | bash
# Analyze compose file
cd your-project
run v2 compose analyze docker-compose.yml
Output:
Services:
OK web-api -> WASI component (can migrate)
OK worker -> WASI component (can migrate)
WARN postgres -> Docker bridge (stateful, keep Docker)
WARN redis -> Docker bridge (stateful, keep Docker)
Recommendation: Hybrid mode (2 WASI + 2 Docker)
Estimated startup: 5s (Docker) + 10ms (WASI)
Estimated size: 128MB (Docker) + 3MB (WASI)
run v2 compose migrate docker-compose.yml run.toml
This creates a run.toml with:
Before: docker-compose.yml
version: '3'
services:
web:
build: .
ports:
- "8080:8080"
environment:
DATABASE_URL: postgres://db:5432/mydb
depends_on:
- db
db:
image: postgres:15
environment:
POSTGRES_PASSWORD: secret
After: run.toml
[package]
name = "my-app"
version = "1.0.0"
[[component]]
name = "web"
source = "src/lib.rs"
language = "rust"
wit = "wit/http.wit"
[component.web.env]
DATABASE_URL = "postgres://localhost:5432/mydb"
[bridge.postgres]
image = "postgres:15"
ports = { 5432 = 5432 }
env = { POSTGRES_PASSWORD = "secret" }
# Install cargo-component
cargo install cargo-component
# Initialize component
cargo component new web --lib
# Write code
cat > src/lib.rs <<'EOF'
wit_bindgen::generate!({
world: "http-handler",
exports: {
"wasi:http/handler": Handler,
},
});
struct Handler;
impl exports::wasi::http::handler::Guest for Handler {
fn handle(request: Request) -> Response {
Response::new(200, b"Hello from Run 2.0!")
}
}
EOF
# Build
cargo component build --release
# Install componentize-py
pip install componentize-py
# Write code
cat > app.py <<'EOF'
def handle_request(request):
return {
"status": 200,
"body": b"Hello from Run 2.0!"
}
EOF
# Build
componentize-py -d http.wit -o app.wasm app.py
# Install jco
npm install -g @bytecodealliance/jco
# Write code
cat > index.ts <<'EOF'
export function handleRequest(request: Request): Response {
return new Response("Hello from Run 2.0!", { status: 200 });
}
EOF
# Build
jco transpile index.ts -o app.wasm
# Start dev server
run v2 dev
# Output:
[run] Starting WASI components...
[web] OK Built in 8ms
[run] Starting Docker bridge...
[docker] postgres -> postgres:15
[run] All services ready:
[run] http://localhost:8080 (web)
# Test
curl http://localhost:8080
# Hello from Run 2.0!
# Production build
run v2 build --release --reproducible
# Deploy (examples)
run v2 deploy --target local
run v2 deploy --target edge --provider cloudflare
run v2 deploy --target registry
| Docker Command | Run 2.0 Equivalent | Notes |
|---|---|---|
docker-compose up |
run v2 dev |
<10ms startup for WASI |
docker-compose build |
run v2 build |
<10s builds |
docker-compose down |
run stop |
Stops all components |
docker-compose logs |
run v2 dev (shows logs) |
Unified logs |
docker-compose ps |
run v2 info |
Component status |
docker-compose exec |
run v2 exec |
Execute in component |
docker build |
run v2 build |
No Dockerfile needed |
docker run |
run v2 exec |
Direct execution |
docker push |
run v2 deploy --target registry |
WASI registry |
docker pull |
run v2 install |
Download components |
docker-compose.yml
|-- Service A (container)
| |-- Dockerfile
| |-- node_modules/
| `-- app.js
|-- Service B (container)
| |-- Dockerfile
| |-- venv/
| `-- app.py
`-- Database (container)
`-- postgres:15
Docker Daemon (required)
|-- Network bridge
|-- Volume management
`-- Container orchestration
Issues:
run.toml
|-- Component A (WASI) <10ms, 2MB
|-- Component B (WASI) <10ms, 3MB
`-- Database (Docker*) 5s, 128MB
Run Runtime (no daemon)
|-- Component Model (WASI 0.2)
|-- Capability security
`-- Direct host process
*Docker bridge optional
Benefits:
Before (Dockerfile):
FROM node:18
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
CMD ["node", "server.js"]
After (run.toml):
[[component]]
name = "api"
source = "src/lib.rs"
language = "rust"
wit = "wit/http.wit"
Before:
services:
app:
depends_on:
- db
environment:
DATABASE_URL: postgres://db:5432/mydb
db:
image: postgres:15
After:
[[component]]
name = "app"
source = "src/lib.rs"
env = { DATABASE_URL = "postgres://localhost:5432/mydb" }
[bridge.postgres]
image = "postgres:15"
ports = { 5432 = 5432 }
Before (docker-compose.yml):
services:
frontend:
build: ./frontend
ports: ["3000:3000"]
backend:
build: ./backend
ports: ["8080:8080"]
worker:
build: ./worker
After (run.toml):
[[component]]
name = "frontend"
source = "frontend/src/lib.rs"
[[component]]
name = "backend"
source = "backend/src/lib.rs"
[[component]]
name = "worker"
source = "worker/src/lib.rs"
All start in <10ms, no containers needed.
Before:
services:
app:
environment:
NODE_ENV: production
API_KEY: ${API_KEY}
After:
[[component]]
name = "app"
env = { NODE_ENV = "production", API_KEY = "${API_KEY}" }
[env.production]
NODE_ENV = "production"
LOG_LEVEL = "info"
If you see this error but have Docker installed:
# Check Docker is running
docker info
# Enable Docker bridge in run.toml
[bridge]
enabled = true
# Error: Port 8080 already in use
# Solution: Change port in run.toml
[[component]]
name = "web"
dev.port = 8081 # Changed from 8080
# Error: Cannot find module 'xyz'
# For Rust: Add to Cargo.toml
[dependencies]
xyz = "1.0"
# For Python: Add to requirements.txt
xyz==1.0.0
# For JS/TS: Add to package.json
{
"dependencies": {
"xyz": "^1.0.0"
}
}
Not all code can run in WASI yet. Use Docker bridge for:
libpq, openssl)# Keep these in Docker bridge
[bridge.legacy-service]
image = "my-legacy-app"
If WASI is slower than Docker:
# Enable release builds
run v2 build --release
# Verbose logs
run v2 dev --verbose
# Check component size
ls -lh target/wasm/*.wasm
# Optimize
[component.my-component]
opt_level = 3
strip_debug = true
docker-compose.yml with run v2 compose analyzerun.toml with run v2 compose migraterun v2 devBefore:
After:
Result: 100x smaller, 1000x faster startup
Before:
After:
Result: 66x smaller, 30x faster
Before:
After:
Result: 10x faster, verifiable
examples/v2/docker-hybrid/