Upgrade Next.js & DB dependencies; optimize Docker image size#4106
Upgrade Next.js & DB dependencies; optimize Docker image size#4106swoiow wants to merge 2 commits into
Conversation
|
@swoiow is attempting to deploy a commit to the Umami Software Team on Vercel. A member of the Team first needs to authorize it. |
Greptile SummaryThis PR refactors the Dockerfile into a lean multi-stage build (targeting ~300 MB vs the original ~1 GB) and loosens several dependency version pins in Key changes:
Issues found:
Confidence Score: 1/5
Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
subgraph "Old Startup Flow (start-docker)"
A[Container Starts] --> B[check-db.js]
B --> C{DATABASE_URL set?}
C -- No --> FAIL1[Exit 1]
C -- Yes --> D[Test DB connection]
D --> E[Check DB version >= 9.4]
E --> F[prisma migrate deploy]
F --> G[update-tracker.js]
G --> H[node server.js]
end
subgraph "New Startup Flow (this PR)"
A2[Container Starts] --> H2[node server.js]
end
style FAIL1 fill:#f55,color:#fff
style F fill:#f90,color:#fff
style H fill:#6c6,color:#fff
style H2 fill:#6c6,color:#fff
style B fill:#f90,color:#fff
Reviews (1): Last reviewed commit: "Update Prisma and Next.js dependencies t..." | Re-trigger Greptile |
| EXPOSE 3000 | ||
|
|
||
| CMD ["pnpm", "start-docker"] | ||
| CMD ["node", "server.js"] |
There was a problem hiding this comment.
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:
- Validates
DATABASE_URLis set - Tests the database connection
- Verifies the DB version meets the minimum (
9.4.0) - Runs
prisma migrate deployto 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.
| 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)
| 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 |
There was a problem hiding this comment.
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
^16range fornextand the loose^6ranges 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
| 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 |
| # 如果你们有这些文件,也要一起 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 | ||
|
|
||
| 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 |
There was a problem hiding this comment.
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
| 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 |
There was a problem hiding this comment.
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.
| 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.
Description
This PR focuses on modernizing the tech stack and significantly optimizing the containerization process, aligning with the efficient patterns seen in the
pylab/umamicommunity image.Changes include:
Performance Impact
The Docker image size has been drastically reduced, leading to faster CI/CD pipelines and lower storage overhead:
pylab/umami(Available for verification)Questions
I'd like to ask if there are current plans to merge these core dependency updates? I've tested the build locally and against the
pylabenvironment, and it's running smoothly. Please let me know if any further adjustments are needed to align with the roadmap.