Skip to content

Upgrade Next.js & DB dependencies; optimize Docker image size#4106

Open
swoiow wants to merge 2 commits into
umami-software:masterfrom
pylab-me:patch-1
Open

Upgrade Next.js & DB dependencies; optimize Docker image size#4106
swoiow wants to merge 2 commits into
umami-software:masterfrom
pylab-me:patch-1

Conversation

@swoiow
Copy link
Copy Markdown

@swoiow swoiow commented Mar 24, 2026

Description

This PR focuses on modernizing the tech stack and significantly optimizing the containerization process, aligning with the efficient patterns seen in the pylab/umami community image.

Changes include:

  • Framework Upgrade: Bumped Next.js to the latest version for better performance and security.
  • Database Layer: Updated database connection dependencies to ensure compatibility with the latest environment.
  • Docker Optimization: Refactored the Dockerfile using multi-stage builds to strip away build-time bloat.

Performance Impact

The Docker image size has been drastically reduced, leading to faster CI/CD pipelines and lower storage overhead:

  • Original Size: ~1 GB
  • Optimized Size: ~300 MB 🚀
  • Docker Image: 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 pylab environment, and it's running smoothly. Please let me know if any further adjustments are needed to align with the roadmap.

@vercel
Copy link
Copy Markdown

vercel Bot commented Mar 24, 2026

@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-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Mar 24, 2026

Greptile Summary

This 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 package.json. While the image-size goal is worthwhile, the implementation has a critical regression and a reproducibility issue that need to be resolved before merging.

Key changes:

  • Dockerfile: adds a base stage, uses BuildKit cache mounts for pnpm, adopts the built-in node user, and switches to node server.js as the container entrypoint
  • package.json: loosens Prisma pins from ^6.18.0^6 and bumps Next.js from ^15.5.9^16

Issues found:

  • [P0 - Logic] CMD ["node", "server.js"] skips the entire start-docker startup sequence, meaning prisma migrate deploy (database schema migrations), the DB connectivity check, and the DB version check are never executed. This will break fresh installs and all upgrades that include schema changes.
  • [P1 - Logic] pnpm-lock.yaml is not copied into the deps stage and --frozen-lockfile is not used, making every build non-deterministic and potentially pulling different dependency versions across CI runs.
  • [P2 - Style] Several Dockerfile comments are written in Chinese, inconsistent with the project's English-language codebase.
  • [P2 - Style] corepack enable && corepack prepare is duplicated in both deps and builder stages; it could be moved to base.

Confidence Score: 1/5

  • Not safe to merge — the new CMD silently skips database migrations on every container start, which will corrupt or break any deployment that relies on schema upgrades.
  • The P0 regression (missing prisma migrate deploy at startup) is a silent data-layer failure: the container starts and appears healthy, but any schema migration is never applied. This would cause runtime SQL errors on fresh installs and after any version upgrade. The missing lockfile copy compounds the risk by making every build non-deterministic. Both issues must be fixed before this is safe to ship.
  • Dockerfile — the entrypoint change and missing lockfile copy are the primary blockers.

Important Files Changed

Filename Overview
Dockerfile Multi-stage Docker refactor that significantly reduces image size, but introduces two critical regressions: database migrations no longer run at startup (CMD changed from pnpm start-docker to node server.js), and pnpm-lock.yaml is not copied making builds non-deterministic. Also contains Chinese-language comments inconsistent with the project's language.
package.json Loosens Prisma version pins from ^6.18.0 to ^6 and bumps Next.js from ^15.5.9 to ^16. The looser Prisma ranges are a minor concern for reproducibility (mitigated by the lockfile when it's properly used), and the Next.js major bump should be validated for breaking changes.

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
Loading

Reviews (1): Last reviewed commit: "Update Prisma and Next.js dependencies t..." | Re-trigger Greptile

Comment thread Dockerfile
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)

Comment thread Dockerfile
Comment on lines +13 to +20
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 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

Comment thread Dockerfile
Comment on lines +14 to +55
# 如果你们有这些文件,也要一起 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
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

Comment thread Dockerfile
Comment on lines +11 to +23
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
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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant