Dockerfile Templates

For most apps, you don't need a Dockerfile — just set a supported runtime (Python, Node.js, Go, Bun, static) and PromptShip generates the build for you.

These templates are for advanced users who need full control over the build (e.g. custom system packages, multi-stage builds, or unsupported runtimes like Rust or Java). Place the Dockerfile in your repo root (or in the root_dir you configured) and set runtime: "dockerfile".

Important: Your app must listen on the port specified by the PORT environment variable. Bind to 0.0.0.0:$PORT. All templates below are configured for this.

Python (Flask / FastAPI)

With requirements.txt

FROM python:3.12-slim

WORKDIR /app

# Install dependencies first for better layer caching
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

EXPOSE $PORT

# Flask
CMD gunicorn --bind 0.0.0.0:$PORT app:app

# FastAPI (uncomment and replace the line above)
# CMD uvicorn main:app --host 0.0.0.0 --port $PORT

With pyproject.toml

FROM python:3.12-slim

WORKDIR /app

COPY pyproject.toml .
RUN pip install --no-cache-dir .

COPY . .

EXPOSE $PORT
CMD gunicorn --bind 0.0.0.0:$PORT app:app

Django

FROM python:3.12-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

# Collect static files at build time
RUN python manage.py collectstatic --noinput

EXPOSE $PORT
CMD gunicorn --bind 0.0.0.0:$PORT myproject.wsgi:application

Node.js

Express / Fastify

FROM node:22-slim

WORKDIR /app

# Install dependencies first for better layer caching
COPY package*.json ./
RUN npm ci --omit=dev

COPY . .

EXPOSE $PORT
CMD ["npm", "start"]

npm ci requires a package-lock.json. Run npm install locally first to generate it.

Make sure your app listens on process.env.PORT:

// server.js
const port = process.env.PORT || 8080;
app.listen(port, '0.0.0.0');

Next.js

FROM node:22-slim AS builder

WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:22-slim
WORKDIR /app
COPY --from=builder /app/.next .next
COPY --from=builder /app/node_modules node_modules
COPY --from=builder /app/package.json .
COPY --from=builder /app/public public

EXPOSE $PORT
ENV PORT=8080
CMD ["npm", "start"]

Go

FROM golang:1.23 AS builder

WORKDIR /app
COPY go.* ./
RUN go mod download

COPY . .
RUN CGO_ENABLED=0 go build -o server .

FROM alpine:3.21

COPY --from=builder /app/server /server

EXPOSE $PORT
CMD ["/server"]

Make sure your Go app reads the port from the PORT environment variable:

port := os.Getenv("PORT")
if port == "" {
    port = "8080"
}
http.ListenAndServe(":"+port, router)

Static Site / WASM

For static files, single-page apps, or WASM games. Uses nginx to serve files with SPA fallback routing.

FROM nginx:alpine

# Copy your static files
COPY . /usr/share/nginx/html

# nginx config template — $PORT is substituted at container start
RUN printf 'server {\n\
    listen ${PORT};\n\
    root /usr/share/nginx/html;\n\
    index index.html;\n\
    location / {\n\
        try_files $uri $uri/ /index.html;\n\
    }\n\
}\n' > /etc/nginx/conf.d/default.conf.template

EXPOSE $PORT
ENV PORT=8080
CMD ["/bin/sh", "-c", "envsubst '${PORT}' < /etc/nginx/conf.d/default.conf.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'"]

Monorepo tip: If your static files are in a subdirectory (e.g. game/), set root_dir to that directory using configure_app. You can run multiple apps from the same repo — one for your API, one for your static site.

Rust

FROM rust:1.83 AS builder

WORKDIR /app
COPY Cargo.toml Cargo.lock ./
# Cache dependency build
RUN mkdir src && echo "fn main() {}" > src/main.rs && cargo build --release && rm -rf src

COPY . .
RUN cargo build --release

FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y ca-certificates && rm -rf /var/lib/apt/lists/*

COPY --from=builder /app/target/release/app /app

EXPOSE $PORT
CMD ["/app"]

Tips