# syntax=docker/dockerfile:1 FROM node:20-alpine AS deps WORKDIR /app COPY package.json package-lock.json* ./ RUN npm ci --no-audit --no-fund FROM node:20-alpine AS builder WORKDIR /app COPY --from=deps /app/node_modules ./node_modules COPY . . # NEXT_PUBLIC_SITE_URL is baked into the client bundle at build time ARG NEXT_PUBLIC_SITE_URL=http://localhost:3000 ENV NEXT_PUBLIC_SITE_URL=$NEXT_PUBLIC_SITE_URL ENV PAYLOAD_SECRET=build-secret ENV DATABASE_URI=postgres://build:build@127.0.0.1:5432/build RUN npm run build FROM node:20-alpine AS runner WORKDIR /app ENV NODE_ENV=production RUN addgroup -S nodejs && adduser -S nextjs -G nodejs COPY --from=builder /app/public ./public # full node_modules: the standalone server plus payload CLI for migrate/seed COPY --from=builder --chown=nextjs:nodejs /app/node_modules ./node_modules COPY --from=builder --chown=nextjs:nodejs /app/.next ./.next COPY --from=builder --chown=nextjs:nodejs /app/package.json ./package.json COPY --from=builder --chown=nextjs:nodejs /app/next.config.mjs ./next.config.mjs COPY --from=builder --chown=nextjs:nodejs /app/tsconfig.json ./tsconfig.json # seed sources — `npx payload run src/seed.ts` (media dir is created by Payload on upload) COPY --from=builder --chown=nextjs:nodejs /app/src ./src # media upload dir must be writable by nextjs (mounted as volume in compose) RUN mkdir -p /app/media && chown nextjs:nodejs /app/media USER nextjs EXPOSE 3000 ENV PORT=3000 HOSTNAME=0.0.0.0 # Apply migrations, then start CMD ["sh", "-c", "npx payload migrate && npm run start"]