What this prompt does
This prompt generates a production-grade multi-stage Dockerfile for your [language]/[framework] app, which builds with [build_tool] and serves on port [port]. It separates dependencies, build, and production into three distinct stages so the final image carries only what it must, keeping it both cheaper to run and a smaller attack surface.
The structure works because each stage has exactly one job. The dependencies stage installs with [package_manager] using a lockfile-only strategy for reproducible builds, and copies the lockfile before the source code so Docker layer caching keeps dependency installs cached across builds. The build stage compiles with [build_command] and excludes dev dependencies and test files from the final artifact. The production stage uses [base_image] as a minimal runtime, copies only the compiled output, and sets up a non-root user with UID 1001. On top of that it adds a [health_endpoint] health check with sensible interval, timeout, and retries, configures proper SIGTERM signal handling for graceful shutdown, sets security labels and metadata, and provides a .dockerignore excluding [ignore_patterns], all targeting a final image under [target_size]. Ordering layers around the lockfile so installs stay cached is the habit that saves the most CI minutes.
When to use it
- You are shipping a containerized app to production and want a lean, hardened image.
- Your current image is bloated with dev dependencies, tests, or build tooling.
- You want layer caching ordered around the lockfile to save CI minutes.
- You need a non-root runtime user and a real, lightweight health check.
- You want graceful shutdown via correct SIGTERM handling.
- You want a
.dockerignorethat keeps the build context small.
Example output
Expect a complete multi-stage Dockerfile. You get a dependencies stage that copies the lockfile first and installs with [package_manager], a build stage running [build_command], and a production stage on [base_image] with a UID 1001 non-root user. It also includes a HEALTHCHECK hitting [health_endpoint], signal-handling configuration for graceful shutdown, security labels and metadata, and a .dockerignore listing your [ignore_patterns]. The output usually notes how the staging and base-image choices keep the final image under [target_size], so you understand the size budget rather than just inheriting it.
Pro tips
- Copy the lockfile before the source so dependency installs stay cached, since this is the single habit that saves the most CI time.
- Match
[base_image]to your runtime needs, because Alpine is small but can hit musl versus glibc issues with some native modules. - Keep
[ignore_patterns]thorough, covering node_modules, .git, .env files, and tests, so both build context and image stay lean. - Make
[health_endpoint]a real but lightweight check, since a health check that does heavy work can trigger false restarts. - Treat
[target_size]as a goal rather than a guarantee, because actual size depends on your dependencies and base image. - Keep the non-root user and SIGTERM handling, since they are small additions that materially reduce attack surface and improve shutdown.