1- FROM node:22-slim
1+ # Use an ARG to allow for easy version upgrades
2+ ARG NODE_VERSION=22
23
3- # 🛠 Install OpenSSL 1.1 (needed by Prisma) and other required packages
4- RUN apt-get update && apt-get install -y \
5- openssl \
6- libssl-dev \
7- libstdc++6 \
8- zlib1g \
9- bash \
10- && rm -rf /var/lib/apt/lists/*
4+ # =================================================================================================
5+ # 1. Builder Stage: Installs all dependencies, builds the source code, and prunes dev dependencies.
6+ # =================================================================================================
7+ FROM node:${NODE_VERSION}-slim AS builder
118
12- RUN npm install -g pnpm@9.9.0
9+ # Set environment variables for pnpm
10+ ENV PNPM_HOME="/pnpm"
11+ ENV PATH="$PNPM_HOME:$PATH"
12+ # Use corepack to install pnpm, which is the recommended method since Node.js v16.13
13+ RUN corepack enable && corepack prepare pnpm@9.9.0 --activate
1314
1415WORKDIR /usr/src/app
1516
16- COPY ./packages ./packages
17- COPY ./pnpm-lock.yaml ./pnpm-lock.yaml
18- COPY ./pnpm-workspace.yaml ./pnpm-workspace.yaml
17+ # 🛠 Install OpenSSL and build tools needed for native modules (like Prisma)
18+ RUN apt-get update && apt-get install -y --no-install-recommends \
19+ openssl \
20+ libssl-dev \
21+ pkg-config \
22+ build-essential \
23+ python3 \
24+ && rm -rf /var/lib/apt/lists/*
1925
20- COPY ./package.json ./package.json
21- COPY ./tsconfig.json ./tsconfig.json
22- COPY ./turbo.json ./turbo.json
26+ # Copy only the files required to install dependencies.
27+ # This maximizes layer caching. The install step will only re-run if these files change.
28+ COPY pnpm-lock.yaml pnpm-workspace.yaml ./
29+ COPY package.json tsconfig.json turbo.json ./
30+ COPY packages/ packages/
31+ COPY apps/api/package.json apps/api/
2332
24- COPY ./apps/api ./apps/api
33+ # Use `pnpm fetch` to download dependencies into a shared content-addressable store.
34+ # This creates a highly cacheable layer.
35+ RUN pnpm fetch
2536
26- RUN pnpm install --frozen-lockfile
37+ # Copy the rest of the source code
38+ COPY . .
2739
28- # Generate Prisma client
40+ # Install dependencies using the fetched packages (offline) and generate Prisma client
41+ RUN pnpm install --frozen-lockfile --offline
2942RUN pnpm db:generate
3043
44+ # Build the specific 'api' application
3145RUN pnpm build --filter=api
3246
47+ # Prune development dependencies to reduce the size of the node_modules folder
48+ RUN pnpm prune --prod
49+
50+ # =================================================================================================
51+ # 2. Production Stage: Creates the final, small, and secure image.
52+ # =================================================================================================
53+ FROM node:${NODE_VERSION}-slim AS production
54+
55+ # Set the environment to production
56+ ENV NODE_ENV=production
57+
58+ WORKDIR /usr/src/app
59+
60+ # Install only the runtime dependency for Prisma (OpenSSL)
61+ RUN apt-get update && apt-get install -y --no-install-recommends \
62+ openssl \
63+ && rm -rf /var/lib/apt/lists/*
64+
65+ # Create a non-root user and group for security
66+ RUN addgroup --system --gid 1001 nodejs
67+ RUN adduser --system --uid 1001 nodejs
68+
69+ # Copy pruned dependencies, built code, and necessary package files from the builder stage
70+ # --chown sets the correct permissions for our non-root user
71+ COPY --from=builder --chown=nodejs:nodejs /usr/src/app/node_modules ./node_modules
72+ COPY --from=builder --chown=nodejs:nodejs /usr/src/app/pnpm-lock.yaml ./pnpm-lock.yaml
73+ COPY --from=builder --chown=nodejs:nodejs /usr/src/app/apps/api/dist ./apps/api/dist
74+ COPY --from=builder --chown=nodejs:nodejs /usr/src/app/apps/api/package.json ./apps/api/package.json
75+ # Prisma client also needs access to the schema file at runtime
76+ COPY --from=builder --chown=nodejs:nodejs /usr/src/app/apps/api/prisma ./apps/api/prisma
77+
78+ # Switch to the non-root user
79+ USER nodejs
80+
81+ # Change to the app-specific directory
3382WORKDIR /usr/src/app/apps/api
3483
35- CMD ["pnpm", "start"]
84+ # Expose the port your app runs on (replace 3000 if different)
85+ EXPOSE 3000
86+
87+ # Start the application directly with node, avoiding the need for pnpm in the final image.
88+ # Assumes your start script runs `node dist/main.js` or similar.
89+ CMD ["node", "dist/main.js"]
0 commit comments