From f35de3b03cc966b74d97d3c3c414ac76e1e158c9 Mon Sep 17 00:00:00 2001 From: Sean O'Connor Date: Thu, 10 Sep 2026 12:18:41 -0400 Subject: [PATCH] Reduce shared-server build concurrency and memory pressure --- Dockerfile | 2 ++ apps/web/next.config.ts | 4 ++++ docs/build-safety.md | 12 ++++++++++++ 3 files changed, 18 insertions(+) create mode 100644 docs/build-safety.md diff --git a/Dockerfile b/Dockerfile index a636deb..e709bc4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,6 +15,8 @@ COPY . . FROM source AS builder ARG NEXT_PUBLIC_APP_URL ENV NEXT_PUBLIC_APP_URL=$NEXT_PUBLIC_APP_URL NEXT_TELEMETRY_DISABLED=1 +# Build-only resource controls for the shared Coolify VM; not runtime settings. +ENV NEXT_BUILD_CPUS=2 RAYON_NUM_THREADS=2 UV_THREADPOOL_SIZE=2 MALLOC_ARENA_MAX=2 NODE_OPTIONS=--max-old-space-size=1536 # Build-only placeholders; never copy production secrets into image layers. RUN DATABASE_URL=postgres://build:build@127.0.0.1:5432/build BETTER_AUTH_SECRET=build-only-placeholder-secret-not-for-runtime BETTER_AUTH_URL=$NEXT_PUBLIC_APP_URL bun run --filter @album/web build diff --git a/apps/web/next.config.ts b/apps/web/next.config.ts index 686a304..f13c79c 100644 --- a/apps/web/next.config.ts +++ b/apps/web/next.config.ts @@ -2,6 +2,10 @@ import type { NextConfig } from "next"; const nextConfig: NextConfig = { output: "standalone", + experimental: { + cpus: process.env.NEXT_BUILD_CPUS ? Math.max(1, Math.min(2, Number(process.env.NEXT_BUILD_CPUS) || 2)) : 2, + memoryBasedWorkersCount: false, + }, poweredByHeader: false, images: { qualities: [75, 85] }, async redirects() { diff --git a/docs/build-safety.md b/docs/build-safety.md new file mode 100644 index 0000000..d97e4bc --- /dev/null +++ b/docs/build-safety.md @@ -0,0 +1,12 @@ +# Shared-server build safety + +- Keep Coolify server concurrent builds at **1** (previously 2). +- Do not run manual Docker builds on the production VM alongside deployments. + Validate locally first; then push once and let the webhook build finish. +- The Docker builder caps Next page-generation workers and Rayon/libuv pools at + two. Node subprocesses have a 1536 MiB old-space ceiling. These are not a hard + total-memory limit: Bun, native allocations, and separate processes add overhead. +- Build controls are restricted to the builder stage; application runtime is + unchanged. The final image must pass the Sharp WebP smoke test. +- If memory pressure remains high, move builds to a separate builder rather than + increasing concurrency or running more diagnostic builds on the live VM.