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.
You can customize the Blitz webpack config. See our webpack documentation for details
Blitz supports various build targets, each changing the way your application is built and run. We'll explain each of the targets below.
server
targetYour 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
targetThis 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.
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()
},
],
By default Blitz logs various things at runtime. You can adjust the verbosity using the log level setting.
info
trace
| debug
| info
| warn
| error
| fatal
module.exports = {
log: {
level: "info",
},
}
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,
},
}
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.
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"],
}
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,
},
}
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,
},
}
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.
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"
},
}
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,
}
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,
}
By default Blitz adds the x-powered-by
header. To opt-out of it, disable
the poweredByHeader
config:
module.exports = {
poweredByHeader: false,
}
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 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.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 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
},
]
},
}
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
},
]
},
}
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
},
]
},
}
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
},
]
},
}
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*`,
},
]
},
}
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,
},
]
},
}
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 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 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,
},
]
},
}
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,
},
]
},
}
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,
},
]
},
}
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,
},
]
},
}
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 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.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 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',
},
],
},
],
},
}
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',
},
],
},
],
},
}
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',
},
],
},
],
},
}
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,
},
]
},
}
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 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.
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 directoryoutDir
- 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 idThe 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 renderquery
: 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 theContent-Type
header totext/html
when serving its content if it is different than.html
.
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" },
},
}
},
}
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/
.
These features aren't ready for production and could change at any time.
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).
false
module.exports = {
experimental: {
isomorphicResolverImports: true,
},
}
By default Blitz uses
React Concurrent Mode.
You can disable it by changing experimental.reactMode
to legacy
.
concurrent
concurrent
| legacy
module.exports = {
experimental: {
reactMode: "legacy",
},
}