Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 42 additions & 48 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,66 +1,60 @@
ARG NODE_IMAGE_VERSION="22-alpine"
# syntax=docker/dockerfile:1.7

# Install dependencies only when needed
FROM node:${NODE_IMAGE_VERSION} AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN npm install -g pnpm
RUN pnpm install --frozen-lockfile
ARG NODE_VERSION=24-alpine
ARG PNPM_VERSION=10.32.1

# Rebuild the source code only when needed
FROM node:${NODE_IMAGE_VERSION} AS builder
FROM node:${NODE_VERSION} AS base
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
COPY docker/middleware.ts ./src
ENV NEXT_TELEMETRY_DISABLED=1

ARG BASE_PATH
FROM base AS deps
RUN corepack enable && corepack prepare pnpm@${PNPM_VERSION} --activate

ENV BASE_PATH=$BASE_PATH
ENV NEXT_TELEMETRY_DISABLED=1
ENV DATABASE_URL="postgresql://user:pass@localhost:5432/dummy"
COPY package.json ./
# 如果你们有这些文件,也要一起 copy,避免依赖层失真
# COPY .npmrc pnpm-workspace.yaml ./
# COPY patches ./patches

RUN npm run build-docker
RUN --mount=type=cache,id=pnpm,target=/pnpm/store \
pnpm config set store-dir /pnpm/store && \
pnpm install
Comment on lines +13 to +20
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 pnpm-lock.yaml is not copied — non-deterministic builds

The deps stage copies only package.json and runs pnpm install without --frozen-lockfile. The original Dockerfile explicitly copied pnpm-lock.yaml to pin exact dependency versions. Without the lockfile:

  • Each build may resolve different (potentially incompatible) transitive dependency versions
  • The ^16 range for next and the loose ^6 ranges for Prisma packages mean any patch/minor could be pulled in at any build
  • This also means the cache mount provides no real determinism guarantee
Suggested change
COPY package.json ./
# 如果你们有这些文件,也要一起 copy,避免依赖层失真
# COPY .npmrc pnpm-workspace.yaml ./
# COPY patches ./patches
RUN npm run build-docker
RUN --mount=type=cache,id=pnpm,target=/pnpm/store \
pnpm config set store-dir /pnpm/store && \
pnpm install
COPY package.json pnpm-lock.yaml ./
RUN --mount=type=cache,id=pnpm,target=/pnpm/store \
pnpm config set store-dir /pnpm/store && \
pnpm install --frozen-lockfile


# Production image, copy all the files and run next
FROM node:${NODE_IMAGE_VERSION} AS runner
WORKDIR /app
FROM base AS builder
RUN corepack enable && corepack prepare pnpm@${PNPM_VERSION} --activate
Comment on lines +11 to +23
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Duplicate corepack setup in deps and builder

Both the deps and builder stages run corepack enable && corepack prepare pnpm@${PNPM_VERSION} --activate, even though both already inherit from base. Moving this setup into the base stage would deduplicate it and save a small layer in each derived stage.

Suggested change
RUN corepack enable && corepack prepare pnpm@${PNPM_VERSION} --activate
ENV BASE_PATH=$BASE_PATH
ENV NEXT_TELEMETRY_DISABLED=1
ENV DATABASE_URL="postgresql://user:pass@localhost:5432/dummy"
COPY package.json ./
# 如果你们有这些文件,也要一起 copy,避免依赖层失真
# COPY .npmrc pnpm-workspace.yaml ./
# COPY patches ./patches
RUN npm run build-docker
RUN --mount=type=cache,id=pnpm,target=/pnpm/store \
pnpm config set store-dir /pnpm/store && \
pnpm install
# Production image, copy all the files and run next
FROM node:${NODE_IMAGE_VERSION} AS runner
WORKDIR /app
FROM base AS builder
RUN corepack enable && corepack prepare pnpm@${PNPM_VERSION} --activate
FROM node:${NODE_VERSION} AS base
WORKDIR /app
ENV NEXT_TELEMETRY_DISABLED=1
RUN corepack enable && corepack prepare pnpm@${PNPM_VERSION} --activate

Then remove the RUN corepack ... lines from both deps and builder.


ARG PRISMA_VERSION="6.19.0"
ARG NODE_OPTIONS
COPY --from=deps /app/node_modules ./node_modules
COPY . .
COPY docker/middleware.ts ./src/middleware.ts

ARG BASE_PATH
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
ENV NODE_OPTIONS=$NODE_OPTIONS

RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
RUN set -x \
&& apk add --no-cache curl \
&& npm install -g pnpm
RUN --mount=type=cache,id=pnpm,target=/pnpm/store \
BASE_PATH="${BASE_PATH}" \
DATABASE_URL="postgresql://user:pass@localhost:5432/dummy" \
pnpm run build-docker

# Script dependencies
RUN pnpm --allow-build='@prisma/engines' add npm-run-all dotenv chalk semver \
prisma@${PRISMA_VERSION} \
@prisma/adapter-pg@${PRISMA_VERSION}
FROM base AS runner
ENV NODE_ENV=production
ENV HOSTNAME=0.0.0.0
ENV PORT=3000

COPY --from=builder --chown=nextjs:nodejs /app/public ./public
COPY --from=builder /app/prisma ./prisma
COPY --from=builder /app/scripts ./scripts
COPY --from=builder /app/generated ./generated
# 用官方 node 镜像自带的 node 用户即可,少一层自建用户逻辑
COPY --from=builder --chown=node:node /app/public ./public

# Automatically leverage output traces to reduce image size
# https://nextjs.org/docs/advanced-features/output-file-tracing
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
# Next 运行时缓存/ISR 目录
RUN mkdir .next && chown node:node .next

USER nextjs
# standalone 最小运行集
COPY --from=builder --chown=node:node /app/.next/standalone ./
COPY --from=builder --chown=node:node /app/.next/static ./.next/static

EXPOSE 3000
# 只有当运行时真的需要这些文件时才复制
# COPY --from=builder --chown=node:node /app/prisma ./prisma
# COPY --from=builder --chown=node:node /app/generated ./generated
# COPY --from=builder --chown=node:node /app/scripts ./scripts
Comment on lines +14 to +55
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Chinese-language comments in an English-language project

Several comments in this Dockerfile are written in Chinese (e.g., lines 14, 42, 45, 52). The rest of the repository and all existing Dockerfile comments are in English. Please translate these to English so all contributors can understand the rationale without a translation tool.

For example, line 14 (# 如果你们有这些文件,也要一起 copy,避免依赖层失真) could read:

# If these files exist, copy them too to avoid lockfile/workspace drift

Line 42 (# 用官方 node 镜像自带的 node 用户即可,少一层自建用户逻辑) could read:

# Use the built-in 'node' user from the official image to avoid creating a custom user


ENV HOSTNAME=0.0.0.0
ENV PORT=3000
USER node
EXPOSE 3000

CMD ["pnpm", "start-docker"]
CMD ["node", "server.js"]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P0 Database migrations no longer run at container startup

The original CMD ran pnpm start-docker, which resolves to npm-run-all check-db update-tracker start-server. The check-db step executes scripts/check-db.js, which:

  1. Validates DATABASE_URL is set
  2. Tests the database connection
  3. Verifies the DB version meets the minimum (9.4.0)
  4. Runs prisma migrate deploy to apply pending schema migrations

By replacing the command with the bare node server.js, all of this is skipped. On a fresh install, the database will have no schema. On an upgrade, any new migrations will never be applied, causing the application to crash with schema mismatch errors.

The /app/scripts and /app/generated directories are also commented out of the runner stage, so even restoring the old CMD would require un-commenting those lines first.

Suggested change
CMD ["node", "server.js"]
CMD ["node", "scripts/start-docker.js"]

Alternatively, restore the previous CMD and un-comment the COPY lines for prisma, generated, and scripts:

COPY --from=builder --chown=node:node /app/prisma ./prisma
COPY --from=builder --chown=node:node /app/generated ./generated
COPY --from=builder --chown=node:node /app/scripts ./scripts

CMD ["pnpm", "start-docker"]

(and add pnpm back to the runner stage dependencies if using that approach)

8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@
"@dicebear/core": "^9.2.3",
"@fontsource/inter": "^5.2.8",
"@hello-pangea/dnd": "^17.0.0",
"@prisma/adapter-pg": "^6.18.0",
"@prisma/client": "^6.18.0",
"@prisma/adapter-pg": "^6",
"@prisma/client": "^6",
"@prisma/extension-read-replicas": "^0.4.1",
"@react-spring/web": "^10.0.3",
"@svgr/cli": "^8.1.0",
Expand Down Expand Up @@ -102,12 +102,12 @@
"kafkajs": "^2.1.0",
"lucide-react": "^0.543.0",
"maxmind": "^5.0.0",
"next": "^15.5.9",
"next": "^16",
"node-fetch": "^3.2.8",
"npm-run-all": "^4.1.5",
"papaparse": "^5.5.3",
"pg": "^8.16.3",
"prisma": "^6.18.0",
"prisma": "^6",
"pure-rand": "^7.0.1",
"react": "^19.2.3",
"react-dom": "^19.2.3",
Expand Down