Overview

Ship Conduit with its bundled Dockerfile

The three stages#

deps installs dependencies with bun install --frozen-lockfile against package.json and bun.lock, cached separately from the rest of the build so dependency installs aren't repeated on every code change.

builder copies the installed node_modules, brings in the full source, runs bun run prisma generate, then bun run build. Every environment variable from Environment Variables gets an ENV line here with a ${VAR:-default} fallback — real secrets aren't required for the build to succeed, only for the app to work once it's running.

runner is the image that actually ships. It runs as the non-root bun user (UID/GID 1000) that the base image provides, listens on port 3000, and starts with:

bun run prisma migrate deploy && bun run start

Every deploy applies pending Prisma migrations before the server starts — you don't run migrations as a separate step in production.

Written for Coolify#

The Dockerfile's own comments call out that it's built around how Coolify injects build arguments — as ARG KEY=value lines appended right after each FROM. The comments warn against redeclaring those same ARGs inside a stage, since a later no-value ARG KEY would shadow the injected value and silently reset it to empty. If you're adapting this Dockerfile for a different platform, keep that ordering constraint in mind.

What to configure at the platform level#

Set the variables from Environment Variables as runtime environment variables on whatever platform you deploy to. DATABASE_URL needs to point at a reachable Postgres instance before the container's prisma migrate deploy step can succeed.

Related: Environment Variables for what each variable does, Architecture for how the scan service fits alongside this container, or back to the documentation overview.

Updated

Was this page helpful?