Next.js Config

Configuration

The shared Next.js configuration every app extends.

Every app's next.config.ts is three lines:

apps/app/next.config.ts
import { config } from '@kreogen/next-config';

export default config;

config is a single shared object. Prefer createConfig(overrides), which returns a fresh one — apps/web used to push onto config.images.remotePatterns directly, so apps/app and apps/api silently inherited whatever it had done to the object all three pointed at. Whether that mattered depended on module evaluation order.

Standalone output

output: "standalone" emits a self-contained server bundle for the Docker runtime stage.

outputFileTracingRoot is set to the workspace root, and it is not optional in a monorepo: without it Next infers the root from the nearest lockfile, and if that resolves to the app rather than the workspace the standalone output lands at a path the Dockerfile does not expect.

outputFileTracingIncludes pulls in packages/database/generated, because Prisma's client is generated to a custom output path that Next's file tracing does not follow on its own.

Both are skipped when VERCEL is set, since Vercel builds its own output format and warns about standalone.

External packages

serverExternalPackages: ['@prisma/client', '@aws-sdk/client-s3'],

Both are Node libraries with native or dynamic requires. Bundling them into the server output either fails outright or produces something subtly broken at runtime.

Images

AVIF and WebP, with remotePatterns allowing the OAuth avatar CDNs — lh3.googleusercontent.com and avatars.githubusercontent.com — plus the host derived from S3_ENDPOINT when one is set.

That last one is worth knowing about. next/image refuses an unlisted host, so without it every image uploaded through @kreogen/storage fails to render — and the failure looks like a broken upload rather than a missing configuration entry. A malformed endpoint is ignored here rather than failing the build; that is the storage package's error to report.

PostHog proxy

Rewrites that route analytics through your own origin so ad blockers do not drop them:

PathProxies to
/ingest/static/:path*PostHog's static assets
/ingest/:path*PostHog's ingestion endpoint
/ingest/decidePostHog's feature flag endpoint

skipTrailingSlashRedirect is set alongside them, because PostHog sends some requests with a trailing slash and Next's default redirect turns those into a 307 the SDK does not follow. See web analytics.

Other defaults

  • poweredByHeader: false — server identity is not something to volunteer.
  • reactStrictMode: true.

Bundle analysis

withAnalyzer() wraps the config; see bundle analysis.