1- FROM oven/bun:1.3 AS base
2- WORKDIR /var/www/api
1+ # ─── Stage 1: Dependencies ────────────────────────────────────────────────────
2+ FROM oven/bun:1-alpine AS deps
33
4- # -----------------------------
5- # deps stage - cache dependencies
6- # -----------------------------
7- FROM base AS deps
4+ WORKDIR /app
85
6+ # Copy package manifests
97COPY package.json bun.lock* ./
10- COPY prisma ./prisma
8+
9+ # Install production dependencies only
1110RUN bun install --frozen-lockfile
12- RUN bunx prisma generate
11+ # ─── Stage 2: Builder ─────────────────────────────────────────────────────────
12+ FROM oven/bun:1-alpine AS builder
1313
14- # -----------------------------
15- # build stage - compile TypeScript to JavaScript
16- # -----------------------------
17- FROM deps AS build
14+ WORKDIR /app
1815
16+ # Copy all source files
1917COPY . .
20- RUN bun build src/server.ts --target=bun --production --outdir dist
2118
22- # -----------------------------
23- # development stage
24- # -----------------------------
25- FROM deps AS development
26- COPY . .
27- EXPOSE 3000
28- CMD ["bun" , "src/server.ts" ]
29-
30- # -----------------------------
31- # production stage
32- # -----------------------------
19+ # Install all deps (including dev) for Prisma client generation
20+ RUN bun install --frozen-lockfile
3321
34-
35- FROM oven/bun:1-slim AS production
22+ # prisma generate doesn't connect to the DB, but prisma.config.ts uses env("DATABASE_URL")
23+ # which throws at config-load time if the var is absent. Satisfy it with a dummy placeholder.
24+ # The real DATABASE_URL is injected at runtime via env_file / --env-file / -e flags.
25+ ARG DATABASE_URL=postgresql://placeholder:placeholder@localhost:5432/placeholder
26+ ENV DATABASE_URL=${DATABASE_URL}
3627
37- WORKDIR /var/www/api
38- RUN groupadd -g 1001 nodejs && useradd -u 1001 -g nodejs -m bunjs
28+ # Generate Prisma client
29+ RUN bunx prisma generate
3930
40- COPY --from=build --chown=bunjs:nodejs /var/www/api/dist ./dist
41- COPY --from=deps --chown=bunjs:nodejs /var/www/api/src/generated ./dist/generated
31+ # Unset the dummy URL so it doesn't leak into downstream stages via ENV
32+ ENV DATABASE_URL=
4233
34+ # ─── Stage 3: Production runner
35+ FROM oven/bun:1-alpine AS runner
4336
44- RUN chown -R bunjs:nodejs /var/www/api
45- USER bunjs
37+ WORKDIR /app
4638
4739ENV NODE_ENV=production
48- ENV PORT=3000
4940
50- EXPOSE 3000
41+ # Create a non-root user for security
42+ RUN addgroup --system --gid 1001 cocgroup && \
43+ adduser --system --uid 1001 cocuser
44+
45+ # Copy production node_modules from deps stage
46+ COPY --from=deps --chown=cocuser:cocgroup /app/node_modules ./node_modules
47+
48+ # Copy application source
49+ COPY --chown=cocuser:cocgroup . .
5150
52- HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
53- CMD wget -qO- http://localhost:3000/health || exit 1
51+ COPY --from=builder --chown=cocuser:cocgroup /app/src/generated/prisma ./src/generated/prisma
52+
53+ USER cocuser
54+
55+ EXPOSE 3000
5456
55- CMD ["bun" , "./dist/server.js" ]
57+ # Run Prisma migrations then start the server
58+ CMD ["sh" , "-c" , "bunx prisma migrate deploy && bun src/server.ts" ]
0 commit comments