Home/Learn/Next.js/next.config and Build Configuration

next.config and Build Configuration

Intermediate
Production

One file controls redirects, headers, image hosts, rewrites and the experimental flags. Most of what belongs here is infrastructure, and most of what does not is business logic.

Overview

Almost every Next application needs a handful of the same configuration: which remote image hosts are allowed, which old URLs redirect where, what security headers to send, and occasionally a rewrite that proxies an API. Beyond that the file collects experimental flags, which is where it becomes risky — a flag copied from a blog post can change caching or rendering behaviour in ways that only appear in production. The discipline is to keep it small, comment why each entry exists, and treat an experimental flag as a decision rather than a default.

What Belongs Here

The entries nearly every project ends up with.

images, redirects, headers, rewrites
// next.config.js
/** @type {import('next').NextConfig} */
module.exports = {
  reactStrictMode: true,

  images: {
    remotePatterns: [
      { protocol: 'https', hostname: '**.supabase.co', pathname: '/storage/**' },
    ],
    formats: ['image/avif', 'image/webp'],
  },

  async redirects() {
    return [
      // moved 2026-08 — keep until the old links stop appearing in logs
      { source: '/old-problems', destination: '/dsa/problems', permanent: true },
    ]
  },

  async headers() {
    return [{ source: '/:path*', headers: SECURITY_HEADERS }]
  },

  async rewrites() {
    // proxy the API so cookies stay first-party
    return [{ source: '/api/:path*', destination: `${process.env.API_URL}/:path*` }]
  },

  // Trim large barrel-file libraries
  experimental: { optimizePackageImports: ['lucide-react', 'date-fns'] },
}

// redirect  — the URL changes, the browser sees the new one (301/308)
// rewrite   — the URL stays, different content is served (a proxy)

What Does Not

Two settings that hide failures, and one that surprises.

Never ignore build errors; justify every flag
// Never ship these:
typescript: { ignoreBuildErrors: true }
eslint: { ignoreDuringBuilds: true }
// They convert a build-time failure into a runtime one. If the build
// is slow, run tsc and eslint as separate CI steps — do not silence.

// Experimental flags change real behaviour. Each one is a decision:
experimental: {
  ppr: 'incremental',              // changes how routes render
  staleTimes: { dynamic: 30 },     // changes client cache freshness
  serverActions: { bodySizeLimit: '2mb' },
}
// Write down why each is enabled. A flag nobody can explain is a flag
// that will be blamed for the next unexplained bug.

// trailingSlash changes every URL you have — decide once, early:
trailingSlash: false               // /problems  (the default)
// Changing it later means redirecting every indexed URL.

// basePath, if the app is served under a subpath — it affects every
// link, asset and API route:
basePath: '/app'

// And keep business logic out. A redirect that depends on the user
// belongs in middleware; one that depends on data belongs in a page.

Environment-Aware Config

Differing by environment without duplicating the file.

noindex previews; the config is build-time
const isProd = process.env.NODE_ENV === 'production'
const isPreview = process.env.VERCEL_ENV === 'preview'

module.exports = {
  // keep source maps for the error tracker but do not serve them
  productionBrowserSourceMaps: false,

  // block preview deployments from search engines
  async headers() {
    return isPreview
      ? [{ source: '/:path*', headers: [{ key: 'X-Robots-Tag', value: 'noindex' }] }]
      : [{ source: '/:path*', headers: SECURITY_HEADERS }]
  },

  compiler: {
    removeConsole: isProd ? { exclude: ['error', 'warn'] } : false,
  },
}
// The noindex on previews matters: a preview URL indexed by Google
// competes with production for the same content.

// The config runs at BUILD time, so process.env here is the build
// environment — not the runtime one. A value read here is frozen into
// the build, exactly like NEXT_PUBLIC_.

// Changing this file requires a rebuild and a redeploy. Anything that
// must change without one belongs in a server-read environment
// variable or a database row.

Key Points to Remember

  • 1Image hosts, redirects, security headers and rewrites are what nearly every project configures here
  • 2A redirect changes the URL; a rewrite keeps it and serves different content
  • 3ignoreBuildErrors and ignoreDuringBuilds convert build failures into runtime failures — never ship them
  • 4Every experimental flag changes behaviour, so record why it is enabled
  • 5The config is evaluated at build time, so values read from the environment are frozen into the build

Interview Questions

Sign in to ask Aria
1

What is the difference between a redirect and a rewrite?

Easy
2

Why is ignoreBuildErrors dangerous?

Medium
3

Why should preview deployments send X-Robots-Tag: noindex?

Medium

Ask Aria about next.config and Build Configuration

Your personal AI tutor — ask anything about this concept

Revision Status

Personal Notes

Sign in to save personal notes for this topic.

Discussion

Sign in to join the discussion.

Loading discussion…