Blitz is in beta! 🎉 1.0 expected in May or June
Back to Documentation Menu

blitz.config.js

Topics

Jump to a Topic

You can customize advanced behavior of Blitz with blitz.config.js.

blitz.config.js is a regular Node.js module, not a JSON file. It gets used by the Blitz server and build phases, and it's not included in the browser build.

Take a look at the following blitz.config.js example:

module.exports = {
  /* config options here */
}

You can also use a function:

module.exports = (phase, {defaultConfig}) => {
  return {
    /* config options here */
  }
}

phase is the current context in which the configuration is loaded. You can see the available phases here. Phases can be imported from next/constants:

const {PHASE_DEVELOPMENT_SERVER} = require("next/constants")

module.exports = (phase, {defaultConfig}) => {
  if (phase === PHASE_DEVELOPMENT_SERVER) {
    return {
      /* development only config options here */
    }
  }

  return {
    /* config options for all phases except development here */
  }
}

The commented lines are the place where you can put the configs allowed by blitz.config.js, which are defined here.

However, none of the configs are required, and it's not necessary to understand what each config does, instead, search for the features you need to enable or modify in this section and they will show you what to do.

Avoid using new JavaScript features not available in your target Node.js version. blitz.config.js will not be parsed by Webpack, Babel or TypeScript.

Webpack Config

You can customize the Blitz webpack config. See our webpack documentation for details

Build Target

Blitz supports various build targets, each changing the way your application is built and run. We'll explain each of the targets below.

server target

Your application will be built and deployed as a monolith. This is the default target and no action is required on your part to opt-in.

serverless target

This target will output independent pages that don't require a monolithic server.

It's only compatible with Serverless deployment platforms (like Vercel) — you cannot use the custom server API.

To opt-into this target, set the following configuration in your blitz.config.js:

module.exports = {
  target: "serverless",
}

Deployments to Vercel will automatically enable this target. You should not opt-into it yourself.

Middleware

HTTP middleware can be added queries and mutations. See the middleware documentation for full details.

module.exports = {
  middleware: [
    (req, res, next) => {
      res.blitzCtx.referer = req.headers.referer
      return next()
    },
  ],

Logging

By default Blitz logs various things at runtime. You can adjust the verbosity using the log level setting.

  • Default: info
  • Options: trace | debug | info | warn | error | fatal
module.exports = {
  log: {
    level: "info",
  },
}

CLI

When you run blitz dev, the console gets cleared. You can disable it by setting the cli.clearConsoleOnBlitzDev to false:

module.exports = {
  cli: {
    clearConsoleOnBlitzDev: false,
  },
}

CDN Support with Asset Prefix

To set up a CDN, you can set up an asset prefix and configure your CDN's origin to resolve to the domain that Blitz is hosted on.

const isProd = process.env.NODE_ENV === "production"

module.exports = {
  // Use the CDN in production and localhost for development.
  assetPrefix: isProd ? "https://cdn.mydomain.com" : "",
}

Blitz will automatically use your prefix in the scripts it loads, but this has no effect whatsoever on the public folder; if you want to serve those assets over a CDN, you'll have to introduce the prefix yourself. One way of introducing a prefix that works inside your components and varies by environment is documented in this example.

Custom Page Extensions

Aimed at modules like @next/mdx, which adds support for pages ending with .mdx. You can configure the extensions looked for in the pages directory when resolving pages.

module.exports = {
  pageExtensions: ["mdx", "jsx", "js", "ts", "tsx"],
}

Static Optimization Indicator

When a page qualifies for Automatic Static Optimization we show an indicator to let you know.

This is helpful since automatic static optimization can be very beneficial and knowing immediately in development if the page qualifies can be useful.

In some cases this indicator might not be useful, like when working on electron applications.

module.exports = {
  devIndicators: {
    autoPrerender: false,
  },
}

Configuring onDemandEntries for Development

Blitz exposes some options that give you some control over how the server will dispose or keep in memory built pages in development.

module.exports = {
  onDemandEntries: {
    // period (in ms) where the server will keep pages in the buffer
    maxInactiveAge: 25 * 1000,
    // number of pages that should be kept simultaneously without being disposed
    pagesBufferLength: 2,
  },
}

Setting a custom build directory

You can specify a name to use for a custom build directory to use instead of .next.

module.exports = {
  distDir: "build",
}

Now if you run blitz build Blitz will use build instead of the default .next folder.

distDir should not leave your project directory. For example, ../build is an invalid directory.

Configuring the Build ID

Blitz uses a constant id generated at build time to identify which version of your application is being served. This can cause problems in multi-server deployments when blitz build is ran on every server. In order to keep a static build id between builds you can provide your own build id.

module.exports = {
  generateBuildId: async () => {
    // You can, for example, get the latest git commit hash here
    return "my-build-id"
  },
}

Compression

Blitz provides gzip compression to compress rendered content and static files. Compression only works with the server target. In general you will want to enable compression on a HTTP proxy like nginx, to offload load from the Node.js process.

module.exports = {
  compress: false,
}

Disabling ETag Generation

By default we generate etags for every page by default. You may want to disable etag generation for HTML pages depending on your cache strategy.

module.exports = {
  generateEtags: false,
}

Disabling x-powered-by

By default Blitz adds the x-powered-by header. To opt-out of it, disable the poweredByHeader config:

module.exports = {
  poweredByHeader: false,
}

Base Path

To deploy a Blitz application under a sub-path of a domain you can use the basePath config option.

basePath allows you to set a path prefix for the application. For example, to use /docs instead of / (the default), open blitz.config.js and add the basePath config:

module.exports = {
  basePath: "/docs",
}

Note: this value must be set at build time and can not be changed without re-building as the value is inlined in the client-side bundles.

When linking to other pages using Link and Router the basePath will be automatically applied.

For example using /about will automatically become /docs/about when basePath is set to /docs.

export default function HomePage() {
  return (
    <>
      <Link href={Routes.About()}>
        <a>About Page</a>
      </Link>
    </>
  )
}

Output html:

<a href="/docs/about">About Page</a>

This makes sure that you don't have to change all links in your application when changing the basePath value.

Rewrites

Rewrites allow you to map an incoming request path to a different destination path.

Rewrites are only available on the Node.js environment and do not affect client-side routing.

Rewrites are not able to override public files or routes in the pages directory as these have higher priority than rewrites. For example, if you have pages/index.js you are not able to rewrite / to another location unless you rename the pages/index.js file.

To use rewrites you can use the rewrites key in blitz.config.js:

module.exports = {
  async rewrites() {
    return [
      {
        source: "/about",
        destination: "/",
      },
    ]
  },
}

rewrites is an async function that expects an array to be returned holding objects with source and destination properties:

  • source is the incoming request path pattern.
  • destination is the path you want to route to.

Rewrite parameters

When using parameters in a rewrite the parameters will be passed in the query by default when none of the parameters are used in the destination.

module.exports = {
  async rewrites() {
    return [
      {
        source: "/old-about/:path*",
        destination: "/about", // The :path parameter isn't used here so will be automatically passed in the query
      },
    ]
  },
}

If a parameter is used in the destination none of the parameters will be automatically passed in the query.

module.exports = {
  async rewrites() {
    return [
      {
        source: "/docs/:path*",
        destination: "/:path*", // The :path parameter is used here so will not be automatically passed in the query
      },
    ]
  },
}

You can still pass the parameters manually in the query if one is already used in the destination by specifying the query in the destination.

module.exports = {
  async rewrites() {
    return [
      {
        source: "/:first/:second",
        destination: "/:first?second=:second",
        // Since the :first parameter is used in the destination the :second parameter
        // will not automatically be added in the query although we can manually add it
        // as shown above
      },
    ]
  },
}

Path Matching

Path matches are allowed, for example /blog/:slug will match /blog/hello-world (no nested paths):

module.exports = {
  async rewrites() {
    return [
      {
        source: "/blog/:slug",
        destination: "/news/:slug", // Matched parameters can be used in the destination
      },
    ]
  },
}

Wildcard Path Matching

To match a wildcard path you can use * after a parameter, for example /blog/:slug* will match /blog/a/b/c/d/hello-world:

module.exports = {
  async rewrites() {
    return [
      {
        source: "/blog/:slug*",
        destination: "/news/:slug*", // Matched parameters can be used in the destination
      },
    ]
  },
}

Regex Path Matching

To match a regex path you can wrap the regex in parenthesis after a parameter, for example /blog/:slug(\\d{1,}) will match /blog/123 but not /blog/abc:

module.exports = {
  async rewrites() {
    return [
      {
        source: "/old-blog/:post(\\d{1,})",
        destination: "/blog/:post", // Matched parameters can be used in the destination
      },
    ]
  },
}

Rewriting to an external URL

Rewrites allow you to rewrite to an external url. This is especially useful for incrementally adopting Next.js.

module.exports = {
  async rewrites() {
    return [
      {
        source: "/blog/:slug",
        destination: "https://example.com/blog/:slug", // Matched parameters can be used in the destination
      },
    ]
  },
}

Incremental adoption of Blitz

You can also make Blitz check the application routes before falling back to proxying to the previous website.

This way you don't have to change the rewrites configuration when migrating more pages to Blitz

module.exports = {
  async rewrites() {
    return [
      // we need to define a no-op rewrite to trigger checking
      // all pages/static files before we attempt proxying
      {
        source: "/:path*",
        destination: "/:path*",
      },
      {
        source: "/:path*",
        destination: `https://custom-routes-proxying-endpoint.vercel.app/:path*`,
      },
    ]
  },
}

Rewrites with basePath support

When leveraging basePath support with rewrites each source and destination is automatically prefixed with the basePath unless you add basePath: false to the rewrite:

module.exports = {
  basePath: "/docs",

  async rewrites() {
    return [
      {
        source: "/with-basePath", // automatically becomes /docs/with-basePath
        destination: "/another", // automatically becomes /docs/another
      },
      {
        // does not add /docs to /without-basePath since basePath: false is set
        // Note: this can not be used for internal rewrites e.g. `destination: '/another'`
        source: "/without-basePath",
        destination: "https://example.com",
        basePath: false,
      },
    ]
  },
}

Rewrites with i18n support

When leveraging i18n support with rewrites each source and destination is automatically prefixed to handle the configured locales unless you add locale: false to the rewrite. If locale: false is used you must prefix the source and destination with a locale for it to be matched correctly.

module.exports = {
  i18n: {
    locales: ["en", "fr", "de"],
    defaultLocale: "en",
  },

  async rewrites() {
    return [
      {
        source: "/with-locale", // automatically handles all locales
        destination: "/another", // automatically passes the locale on
      },
      {
        // does not handle locales automatically since locale: false is set
        source: "/nl/with-locale-manual",
        destination: "/nl/another",
        locale: false,
      },
      {
        // this matches '/' since `en` is the defaultLocale
        source: "/en",
        destination: "/en/another",
        locale: false,
      },
    ]
  },
}

Redirects

Redirects allow you to redirect an incoming request path to a different destination path.

Redirects are only available on the Node.js environment and do not affect client-side routing.

To use Redirects you can use the redirects key in blitz.config.js:

module.exports = {
  async redirects() {
    return [
      {
        source: "/about",
        destination: "/",
        permanent: true,
      },
    ]
  },
}

redirects is an async function that expects an array to be returned holding objects with source, destination, and permanent properties:

  • source is the incoming request path pattern.
  • destination is the path you want to route to.
  • permanent if the redirect is permanent or not.

Path Matching

Path matches are allowed, for example /old-blog/:slug will match /old-blog/hello-world (no nested paths):

module.exports = {
  async redirects() {
    return [
      {
        source: "/old-blog/:slug",
        destination: "/news/:slug", // Matched parameters can be used in the destination
        permanent: true,
      },
    ]
  },
}

Wildcard Path Matching

To match a wildcard path you can use * after a parameter, for example /blog/:slug* will match /blog/a/b/c/d/hello-world:

module.exports = {
  async redirects() {
    return [
      {
        source: "/blog/:slug*",
        destination: "/news/:slug*", // Matched parameters can be used in the destination
        permanent: true,
      },
    ]
  },
}

Regex Path Matching

To match a regex path you can wrap the regex in parenthesis after a parameter, for example /post/:slug(\\d{1,}) will match /post/123 but not /post/abc:

module.exports = {
  async redirects() {
    return [
      {
        source: "/post/:slug(\\d{1,})",
        destination: "/news/:slug", // Matched parameters can be used in the destination
        permanent: false,
      },
    ]
  },
}

Redirects with basePath support

When leveraging basePath support with redirects each source and destination is automatically prefixed with the basePath unless you add basePath: false to the redirect:

module.exports = {
  basePath: "/docs",

  async redirects() {
    return [
      {
        source: "/with-basePath", // automatically becomes /docs/with-basePath
        destination: "/another", // automatically becomes /docs/another
        permanent: false,
      },
      {
        // does not add /docs since basePath: false is set
        source: "/without-basePath",
        destination: "/another",
        basePath: false,
        permanent: false,
      },
    ]
  },
}

Redirects with i18n support

When leveraging i18n support with redirects each source and destination is automatically prefixed to handle the configured locales unless you add locale: false to the redirect. If locale: false is used you must prefix the source and destination with a locale for it to be matched correctly.

module.exports = {
  i18n: {
    locales: ["en", "fr", "de"],
    defaultLocale: "en",
  },

  async redirects() {
    return [
      {
        source: "/with-locale", // automatically handles all locales
        destination: "/another", // automatically passes the locale on
        permanent: false,
      },
      {
        // does not handle locales automatically since locale: false is set
        source: "/nl/with-locale-manual",
        destination: "/nl/another",
        locale: false,
        permanent: false,
      },
      {
        // this matches '/' since `en` is the defaultLocale
        source: "/en",
        destination: "/en/another",
        locale: false,
        permanent: false,
      },
    ]
  },
}

In some rare cases, you might need to assign a custom status code for older HTTP Clients to properly redirect. In these cases, you can use the statusCode property instead of the permanent property, but not both. Note: to ensure IE11 compatibility a Refresh header is automatically added for the 308 status code.

Headers

Headers allow you to set custom HTTP headers for an incoming request path.

To set custom HTTP headers you can use the headers key in blitz.config.js:

module.exports = {
  async headers() {
    return [
      {
        source: "/about",
        headers: [
          {
            key: "x-custom-header",
            value: "my custom header value",
          },
          {
            key: "x-another-custom-header",
            value: "my other custom header value",
          },
        ],
      },
    ]
  },
}

headers is an async function that expects an array to be returned holding objects with source and headers properties:

  • source is the incoming request path pattern.
  • headers is an array of header objects with the key and value properties.

Header Overriding Behavior

If two headers match the same path and set the same header key, the last header key will override the first. Using the below headers, the path /hello will result in the header x-hello being world due to the last header value set being world.

module.exports = {
  async headers() {
    return [
      {
        source: '/:path*',
        headers: [
          {
            key: 'x-hello',
            value: 'there',
          },
        ],
      },
      {
        source: '/hello',
        headers: [
          {
            key: 'x-hello',
            value: 'world',
          },
        ],
      },
    ],
  },
}

Path Matching

Path matches are allowed, for example /blog/:slug will match /blog/hello-world (no nested paths):

module.exports = {
  async headers() {
    return [
      {
        source: '/blog/:slug',
        headers: [
          {
            key: 'x-slug',
            value: ':slug', // Matched parameters can be used in the value
          },
          {
            key: 'x-slug-:slug', // Matched parameters can be used in the key
            value: 'my other custom header value',
          },
        ],
      },
    ],
  },
}

Wildcard Path Matching

To match a wildcard path you can use * after a parameter, for example /blog/:slug* will match /blog/a/b/c/d/hello-world:

module.exports = {
  async headers() {
    return [
      {
        source: '/blog/:slug*',
        headers: [
          {
            key: 'x-slug',
            value: ':slug*', // Matched parameters can be used in the value
          },
          {
            key: 'x-slug-:slug*', // Matched parameters can be used in the key
            value: 'my other custom header value',
          },
        ],
      },
    ],
  },
}

Regex Path Matching

To match a regex path you can wrap the regex in parenthesis after a parameter, for example /blog/:slug(\\d{1,}) will match /blog/123 but not /blog/abc:

module.exports = {
  async headers() {
    return [
      {
        source: '/blog/:post(\\d{1,})',
        headers: [
          {
            key: 'x-post',
            value: ':post',
          },
        ],
      },
    ],
  },
}

Headers with basePath support

When leveraging basePath support with headers each source is automatically prefixed with the basePath unless you add basePath: false to the header:

module.exports = {
  basePath: "/docs",

  async headers() {
    return [
      {
        source: "/with-basePath", // becomes /docs/with-basePath
        headers: [
          {
            key: "x-hello",
            value: "world",
          },
        ],
      },
      {
        source: "/without-basePath", // is not modified since basePath: false is set
        headers: [
          {
            key: "x-hello",
            value: "world",
          },
        ],
        basePath: false,
      },
    ]
  },
}

Headers with i18n support

When leveraging i18n support with headers each source is automatically prefixed to handle the configured locales unless you add locale: false to the header. If locale: false is used you must prefix the source with a locale for it to be matched correctly.

module.exports = {
  i18n: {
    locales: ["en", "fr", "de"],
    defaultLocale: "en",
  },

  async headers() {
    return [
      {
        source: "/with-locale", // automatically handles all locales
        headers: [
          {
            key: "x-hello",
            value: "world",
          },
        ],
      },
      {
        // does not handle locales automatically since locale: false is set
        source: "/nl/with-locale-manual",
        locale: false,
        headers: [
          {
            key: "x-hello",
            value: "world",
          },
        ],
      },
      {
        // this matches '/' since `en` is the defaultLocale
        source: "/en",
        locale: false,
        headers: [
          {
            key: "x-hello",
            value: "world",
          },
        ],
      },
    ]
  },
}

Cache-Control

Cache-Control headers set in blitz.config.js will be overwritten in production to ensure that static assets can be cached effectively. If you need to revalidate the cache of a page that has been statically generated, you can do so by setting revalidate in the page's getStaticProps function.

Export Path Map

exportPathMap allows you to specify a mapping of request paths to page destinations, to be used during export. Paths defined in exportPathMap will also be available when using blitz dev.

exportPathMap is an async function that receives 2 arguments: the first one is defaultPathMap, which is the default map used by Blitz. The second argument is an object with:

  • dev - true when exportPathMap is being called in development. false when running blitz export. In development exportPathMap is used to define routes.
  • dir - Absolute path to the project directory
  • outDir - Absolute path to the out/ directory (configurable with -o). When dev is true the value of outDir will be null.
  • distDir - Absolute path to the .next/ directory (configurable with the distDir config)
  • buildId - The generated build id

The returned object is a map of pages where the key is the pathname and the value is an object that accepts the following fields:

  • page: String - the page inside the pages directory to render
  • query: Object - the query object passed to getStaticProps when prerendering. Defaults to {}

The exported pathname can also be a filename (for example, /readme.md), but you may need to set the Content-Type header to text/html when serving its content if it is different than .html.

Example

Original pages:

  • pages/index.js
  • pages/about.js
  • pages/post.js

blitz.config.js:

module.exports = {
  exportPathMap: async function (
    defaultPathMap,
    {dev, dir, outDir, distDir, buildId},
  ) {
    return {
      "/": {page: "/"},
      "/about": {page: "/about"},
      "/p/hello-nextjs": {page: "/post", query: {title: "hello-nextjs"}},
      "/p/learn-nextjs": {page: "/post", query: {title: "learn-nextjs"}},
      "/p/deploy-nextjs": {
        page: "/post",
        query: {title: "deploy-nextjs"},
      },
    }
  },
}

Trailing Slash

By default Blitz will redirect urls with trailing slashes to their counterpart without a trailing slash. For example /about/ will redirect to /about. You can configure this behavior to act the opposite way, where urls without trailing slashes are redirected to their counterparts with trailing slashes.

Open blitz.config.js and add the trailingSlash config:

module.exports = {
  trailingSlash: true,
}

With this option set, urls like /about will redirect to /about/.

Experimental

These features aren't ready for production and could change at any time.

Isomorphic Resolver Imports

This enables isomorphic code imports from resolver files (for example exporting a zod schema from a mutation and being able to import that in client code).

  • Default: false
module.exports = {
  experimental: {
    isomorphicResolverImports: true,
  },
}

React Mode

By default Blitz uses React Concurrent Mode. You can disable it by changing experimental.reactMode to legacy.

  • Default: concurrent
  • Options: concurrent | legacy
module.exports = {
  experimental: {
    reactMode: "legacy",
  },
}

Idea for improving this page? Edit it on GitHub.