From 82977b6dd8f3c9f8c2dec02d4edef3290438454a Mon Sep 17 00:00:00 2001 From: Sean O'Connor Date: Fri, 26 Jun 2026 01:25:03 -0400 Subject: [PATCH] optimize build process for low mem --- .dockerignore | 2 ++ Dockerfile | 14 +++++++++++--- README.md | 2 ++ docs/ARCHITECTURE.md | 2 +- next.config.js | 17 ++++++++++++++++- 5 files changed, 32 insertions(+), 5 deletions(-) diff --git a/.dockerignore b/.dockerignore index 44820df..f9b132d 100644 --- a/.dockerignore +++ b/.dockerignore @@ -5,6 +5,8 @@ node_modules Dockerfile* docker-compose* README.md +docs +AGENTS.md *.log .DS_Store .env* diff --git a/Dockerfile b/Dockerfile index 9905f7d..b30892f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -13,9 +13,16 @@ COPY . . ARG NEXT_PUBLIC_APP_URL=http://localhost:3000 ARG BETTER_AUTH_URL=http://localhost:3000 -ENV NODE_ENV=production \ +# Low-memory Docker build profile: +# - disable React Compiler (saves compile RAM; prod image still runs fine without it) +# - skip eslint/tsc inside `next build` (run `bun run check` in CI instead) +# - cap Node heap at 2GB (raise Docker/Colima memory if this still OOMs) +ENV DOCKER_BUILD=1 \ + DISABLE_REACT_COMPILER=1 \ + NODE_ENV=production \ SKIP_ENV_VALIDATION=1 \ - NODE_OPTIONS=--max-old-space-size=4096 \ + NEXT_TELEMETRY_DISABLED=1 \ + NODE_OPTIONS=--max-old-space-size=2048 \ BETTER_AUTH_URL=${BETTER_AUTH_URL} \ NEXT_PUBLIC_APP_URL=${NEXT_PUBLIC_APP_URL} \ AUTH_SECRET=docker-build-placeholder-secret-do-not-use \ @@ -25,7 +32,8 @@ RUN bun run build FROM base AS release ENV NODE_ENV=production \ PORT=3000 \ - HOSTNAME=0.0.0.0 + HOSTNAME=0.0.0.0 \ + NEXT_TELEMETRY_DISABLED=1 COPY --from=build /usr/src/app/.next ./.next COPY --from=build /usr/src/app/public ./public diff --git a/README.md b/README.md index 3b9c7c9..5cf99a2 100644 --- a/README.md +++ b/README.md @@ -94,6 +94,8 @@ The production compose file runs the Next.js app and PostgreSQL. **Container startup** runs `bun migrate.ts && bun run start` (see `Dockerfile`). Drizzle only applies **pending** migrations — safe to run on every restart; already-applied migrations are skipped. +The Docker **build** uses a low-memory profile (React Compiler off, webpack memory optimizations, 2GB Node heap cap). Give Docker/Colima at least **3–4GB RAM** for builds. If it still OOMs, raise VM memory (`colima start --memory 6`) — avoid `--no-cache` unless debugging. + ### 1. Configure ```bash diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 55df6f0..40c3ffc 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -186,7 +186,7 @@ Validated in `src/env.js`. See `.env.example`. | `docker-compose.yml` | Deploy: `app` + `db` (Postgres internal); copy `.env.example` → `.env` | | `docker-compose.dev.yml` | Local dev: Postgres only, port `${POSTGRES_PORT:-5432}` | -App image built from `Dockerfile`. Container `CMD`: `bun migrate.ts && bun run start` (migrations then `next start` on port 3000). +App image built from `Dockerfile`. Container `CMD`: `bun migrate.ts && bun run start` (migrations then `next start` on port 3000). Docker builds disable React Compiler and use `experimental.webpackMemoryOptimizations` to reduce peak RAM. Set `BETTER_AUTH_URL` and `NEXT_PUBLIC_APP_URL` to the public hostname before deploy. Rebuild the image when changing `NEXT_PUBLIC_*` build-time vars. diff --git a/next.config.js b/next.config.js index 42f7609..5a46c89 100644 --- a/next.config.js +++ b/next.config.js @@ -4,10 +4,25 @@ */ import "./src/env.js"; +const isDockerBuild = process.env.DOCKER_BUILD === "1"; +const disableReactCompiler = process.env.DISABLE_REACT_COMPILER === "1"; + /** @type {import("next").NextConfig} */ const config = { - reactCompiler: true, + // React Compiler is helpful in dev/prod but adds compile-time memory pressure in Docker builds. + reactCompiler: !disableReactCompiler, + productionBrowserSourceMaps: false, serverExternalPackages: ["pg", "better-auth"], + experimental: { + webpackMemoryOptimizations: true, + }, + // Skip duplicate typecheck/eslint during Docker `next build` to lower peak memory. + ...(isDockerBuild + ? { + typescript: { ignoreBuildErrors: true }, + eslint: { ignoreDuringBuilds: true }, + } + : {}), }; export default config;