Recipe-app main

This commit is contained in:
2026-04-09 09:14:39 +02:00
commit 962f4e4be5
10015 changed files with 2445177 additions and 0 deletions
@@ -0,0 +1,79 @@
---
title: adapterPath
description: Configure a custom adapter for Next.js to hook into the build process.
---
Next.js provides a built-in adapters API. It allows deployment platforms or build systems to integrate with the Next.js build process.
For a full reference implementation, see the [`nextjs/adapter-vercel`](https://github.com/nextjs/adapter-vercel) adapter.
## Configuration
To use an adapter, specify the path to your adapter module in `adapterPath`:
```js filename="next.config.js"
/** @type {import('next').NextConfig} */
const nextConfig = {
adapterPath: require.resolve('./my-adapter.js'),
}
module.exports = nextConfig
```
Alternatively `NEXT_ADAPTER_PATH` can be set to enable zero-config usage in deployment platforms.
## Adapters
For full adapter implementation details, use the dedicated Adapters section:
- [Configuration](/docs/app/api-reference/adapters/configuration)
- [Creating an Adapter](/docs/app/api-reference/adapters/creating-an-adapter)
- [API Reference](/docs/app/api-reference/adapters/api-reference)
- [Testing Adapters](/docs/app/api-reference/adapters/testing-adapters)
- [Routing with `@next/routing`](/docs/app/api-reference/adapters/routing-with-next-routing)
- [Implementing PPR in an Adapter](/docs/app/api-reference/adapters/implementing-ppr-in-an-adapter)
- [Runtime Integration](/docs/app/api-reference/adapters/runtime-integration)
- [Invoking Entrypoints](/docs/app/api-reference/adapters/invoking-entrypoints)
- [Output Types](/docs/app/api-reference/adapters/output-types)
- [Routing Information](/docs/app/api-reference/adapters/routing-information)
- [Use Cases](/docs/app/api-reference/adapters/use-cases)
## Creating an Adapter
See [Creating an Adapter](/docs/app/api-reference/adapters/creating-an-adapter).
## API Reference
See [API Reference](/docs/app/api-reference/adapters/api-reference).
## Testing Adapters
See [Testing Adapters](/docs/app/api-reference/adapters/testing-adapters).
## Routing with `@next/routing`
See [Routing with `@next/routing`](/docs/app/api-reference/adapters/routing-with-next-routing).
## Implementing PPR in an Adapter
See [Implementing PPR in an Adapter](/docs/app/api-reference/adapters/implementing-ppr-in-an-adapter).
## Runtime Integration
See [Runtime Integration](/docs/app/api-reference/adapters/runtime-integration).
## Invoking Entrypoints
See [Invoking Entrypoints](/docs/app/api-reference/adapters/invoking-entrypoints).
## Output Types
See [Output Types](/docs/app/api-reference/adapters/output-types).
## Routing Information
See [Routing Information](/docs/app/api-reference/adapters/routing-information).
## Use Cases
See [Use Cases](/docs/app/api-reference/adapters/use-cases).
@@ -0,0 +1,18 @@
---
title: allowedDevOrigins
description: Use `allowedDevOrigins` to configure additional origins that can request the dev server.
---
{/* The content of this doc is shared between the app and pages router. You can use the `<PagesOnly>Content</PagesOnly>` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}
Next.js blocks cross-origin requests to dev-only assets and endpoints during development by default to prevent unauthorized access.
To configure a Next.js application to allow requests from origins other than the hostname the server was initialized with (`localhost` by default), use the `allowedDevOrigins` config option.
`allowedDevOrigins` lets you set additional origins that can request the dev server in development mode. For example, to use `local-origin.dev` instead of only `localhost`, open `next.config.js` and add the `allowedDevOrigins` config:
```js filename="next.config.js"
module.exports = {
allowedDevOrigins: ['local-origin.dev', '*.local-origin.dev'],
}
```
@@ -0,0 +1,11 @@
---
title: appDir
description: Enable the App Router to use layouts, streaming, and more.
version: legacy
---
> **Good to know**: This option is **no longer** needed as of Next.js 13.4. The App Router is now stable.
The App Router ([`app` directory](/docs/app)) enables support for [layouts](/docs/app/api-reference/file-conventions/layout), [Server Components](/docs/app/getting-started/server-and-client-components), [streaming](/docs/app/api-reference/file-conventions/loading), and [colocated data fetching](/docs/app/getting-started/fetching-data).
Using the `app` directory will automatically enable [React Strict Mode](https://react.dev/reference/react/StrictMode). Learn how to [incrementally adopt `app`](/docs/app/guides/migrating/app-router-migration#migrating-from-pages-to-app).
@@ -0,0 +1,76 @@
---
title: assetPrefix
description: Learn how to use the assetPrefix config option to configure your CDN.
---
{/* The content of this doc is shared between the app and pages router. You can use the `<PagesOnly>Content</PagesOnly>` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}
<AppOnly>
> **Attention**: [Deploying to Vercel](/docs/app/getting-started/deploying) automatically configures a global CDN for your Next.js project.
> You do not need to manually setup an Asset Prefix.
</AppOnly>
<PagesOnly>
> **Attention**: [Deploying to Vercel](/docs/pages/getting-started/deploying) automatically configures a global CDN for your Next.js project.
> You do not need to manually setup an Asset Prefix.
</PagesOnly>
> **Good to know**: Next.js 9.5+ added support for a customizable [Base Path](/docs/app/api-reference/config/next-config-js/basePath), which is better
> suited for hosting your application on a sub-path like `/docs`.
> We do not suggest you use a custom Asset Prefix for this use case.
## Set up a CDN
To set up a [CDN](https://en.wikipedia.org/wiki/Content_delivery_network), you can set up an asset prefix and configure your CDN's origin to resolve to the domain that Next.js is hosted on.
Open `next.config.mjs` and add the `assetPrefix` config based on the [phase](/docs/app/api-reference/config/next-config-js#async-configuration):
```js filename="next.config.mjs"
// @ts-check
import { PHASE_DEVELOPMENT_SERVER } from 'next/constants'
export default (phase) => {
const isDev = phase === PHASE_DEVELOPMENT_SERVER
/**
* @type {import('next').NextConfig}
*/
const nextConfig = {
assetPrefix: isDev ? undefined : 'https://cdn.mydomain.com',
}
return nextConfig
}
```
Next.js will automatically use your asset prefix for the JavaScript and CSS files it loads from the `/_next/` path (`.next/static/` folder). For example, with the above configuration, the following request for a JS chunk:
```
/_next/static/chunks/4b9b41aaa062cbbfeff4add70f256968c51ece5d.4d708494b3aed70c04f0.js
```
Would instead become:
```
https://cdn.mydomain.com/_next/static/chunks/4b9b41aaa062cbbfeff4add70f256968c51ece5d.4d708494b3aed70c04f0.js
```
The exact configuration for uploading your files to a given CDN will depend on your CDN of choice. The only folder you need to host on your CDN is the contents of `.next/static/`, which should be uploaded as `_next/static/` as the above URL request indicates. **Do not upload the rest of your `.next/` folder**, as you should not expose your server code and other configuration to the public.
While `assetPrefix` covers requests to `_next/static`, it does not influence the following paths:
<AppOnly>
- Files in the [public](/docs/app/api-reference/file-conventions/public-folder) folder; if you want to serve those assets over a CDN, you'll have to introduce the prefix yourself
</AppOnly>
<PagesOnly>
- Files in the [public](/docs/pages/api-reference/file-conventions/public-folder) folder; if you want to serve those assets over a CDN, you'll have to introduce the prefix yourself
- `/_next/data/` requests for `getServerSideProps` pages. These requests will always be made against the main domain since they're not static.
- `/_next/data/` requests for `getStaticProps` pages. These requests will always be made against the main domain to support [Incremental Static Generation](/docs/pages/guides/incremental-static-regeneration), even if you're not using it (for consistency).
</PagesOnly>
@@ -0,0 +1,33 @@
---
title: authInterrupts
description: Learn how to enable the experimental `authInterrupts` configuration option to use `forbidden` and `unauthorized`.
version: canary
related:
links:
- app/api-reference/functions/forbidden
- app/api-reference/functions/unauthorized
- app/api-reference/file-conventions/forbidden
- app/api-reference/file-conventions/unauthorized
---
The `authInterrupts` configuration option allows you to use [`forbidden`](/docs/app/api-reference/functions/forbidden) and [`unauthorized`](/docs/app/api-reference/functions/unauthorized) APIs in your application. While these functions are experimental, you must enable the `authInterrupts` option in your `next.config.js` file to use them:
```ts filename="next.config.ts" switcher
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
experimental: {
authInterrupts: true,
},
}
export default nextConfig
```
```js filename="next.config.js" switcher
module.exports = {
experimental: {
authInterrupts: true,
},
}
```
@@ -0,0 +1,79 @@
---
title: basePath
description: Use `basePath` to deploy a Next.js application under a sub-path of a domain.
---
{/* The content of this doc is shared between the app and pages router. You can use the `<PagesOnly>Content</PagesOnly>` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}
To deploy a Next.js 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 `''` (an empty string, the default), open `next.config.js` and add the `basePath` config:
```js filename="next.config.js"
module.exports = {
basePath: '/docs',
}
```
> **Good to know**: This value must be set at build time and cannot be changed without re-building as the value is inlined in the client-side bundles.
### Links
When linking to other pages using `next/link` and `next/router` the `basePath` will be automatically applied.
For example, using `/about` will automatically become `/docs/about` when `basePath` is set to `/docs`.
```js
export default function HomePage() {
return (
<>
<Link href="/about">About Page</Link>
</>
)
}
```
Output html:
```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.
### Images
<AppOnly>
When using the [`next/image`](/docs/app/api-reference/components/image) component, you will need to add the `basePath` in front of `src`.
</AppOnly>
<PagesOnly>
When using the [`next/image`](/docs/pages/api-reference/components/image) component, you will need to add the `basePath` in front of `src`.
</PagesOnly>
For example, using `/docs/me.png` will properly serve your image when `basePath` is set to `/docs`.
```jsx
import Image from 'next/image'
function Home() {
return (
<>
<h1>My Homepage</h1>
<Image
src="/docs/me.png"
alt="Picture of the author"
width={500}
height={500}
/>
<p>Welcome to my homepage!</p>
</>
)
}
export default Home
```
@@ -0,0 +1,52 @@
---
title: cacheComponents
description: Learn how to enable the cacheComponents flag in Next.js.
---
The `cacheComponents` flag is a feature in Next.js that causes data fetching operations in the App Router to be excluded from prerenders unless they are explicitly cached. This can be useful for optimizing the performance of uncached data fetching in Server Components.
It is useful if your application requires fresh data fetching during runtime rather than serving from a prerendered cache.
It is expected to be used in conjunction with [`use cache`](/docs/app/api-reference/directives/use-cache) so that your data fetching happens at runtime by default unless you define specific parts of your application to be cached with `use cache` at the page, function, or component level.
## Usage
To enable the `cacheComponents` flag, set it to `true` in your `next.config.ts` file:
```ts filename="next.config.ts"
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
cacheComponents: true,
}
export default nextConfig
```
When `cacheComponents` is enabled, you can use the following cache functions and configurations:
- The [`use cache` directive](/docs/app/api-reference/directives/use-cache)
- The [`cacheLife` function](/docs/app/api-reference/config/next-config-js/cacheLife) with `use cache`
- The [`cacheTag` function](/docs/app/api-reference/functions/cacheTag)
## Navigation with Activity
When `cacheComponents` is enabled, Next.js uses React's [`<Activity>`](https://react.dev/reference/react/Activity) component to preserve component state during client-side navigation.
Rather than unmounting the previous route when you navigate away, Next.js sets the Activity mode to [`"hidden"`](https://react.dev/reference/react/Activity#activity). This means:
- Component state is preserved when navigating between routes
- When you navigate back, the previous route reappears with its state intact
- Effects are cleaned up when a route is hidden, and recreated when it becomes visible again
This behavior improves the navigation experience by maintaining UI state (form inputs, or expanded sections) when users navigate back and forth between routes.
> **Good to know**: Next.js uses heuristics to keep a few recently visited routes `"hidden"`, while older routes are removed from the DOM to prevent excessive growth.
Some UI patterns behave differently when components stay mounted instead of unmounting. See the [Preserving UI state guide](/docs/app/guides/preserving-ui-state) for handling common patterns like dropdowns, dialogs, and testing.
## Version History
| Version | Change |
| ------- | --------------------------------------------------------------------------------------------------------------------------------- |
| 16.0.0 | `cacheComponents` introduced. This flag controls the `ppr`, `useCache`, and `dynamicIO` flags as a single, unified configuration. |
@@ -0,0 +1,509 @@
---
title: cacheHandlers
description: Configure custom cache handlers for use cache directives in Next.js.
related:
title: Related
description: View related API references.
links:
- app/api-reference/directives/use-cache
- app/api-reference/directives/use-cache-remote
- app/api-reference/directives/use-cache-private
- app/api-reference/config/next-config-js/cacheLife
---
The `cacheHandlers` configuration allows you to define custom cache storage implementations for [`'use cache'`](/docs/app/api-reference/directives/use-cache) and [`'use cache: remote'`](/docs/app/api-reference/directives/use-cache-remote). This enables you to store cached components and functions in external services or customize the caching behavior. [`'use cache: private'`](/docs/app/api-reference/directives/use-cache-private) is not configurable.
## When to use custom cache handlers
**Most applications don't need custom cache handlers.** The default in-memory cache works well in the typical use case.
Custom cache handlers are for advanced scenarios where you need to either share cache across multiple instances or change where the cache is stored. For example, you can configure a custom `remote` handler for external storage (like a key-value store), then use `'use cache'` in your code for in-memory caching and `'use cache: remote'` for the external storage, allowing different caching strategies within the same application.
**Sharing cache across instances**
The default in-memory cache is isolated to each Next.js process. If you're running multiple servers or containers, each instance will have its own cache that isn't shared with others and is lost on restart.
Custom handlers let you integrate with shared storage systems (like Redis, Memcached, or DynamoDB) that all your Next.js instances can access.
**Changing storage type**
You might want to store cache differently than the default in-memory approach. You can implement a custom handler to store cache on disk, in a database, or in an external caching service. Reasons include: persistence across restarts, reducing memory usage, or integrating with existing infrastructure.
## Usage
To configure custom cache handlers:
1. Define your cache handler in a separate file, see [examples](#examples) for implementation details.
2. Reference the file path in your Next config file
```ts filename="next.config.ts" switcher
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
cacheHandlers: {
default: require.resolve('./cache-handlers/default-handler.js'),
remote: require.resolve('./cache-handlers/remote-handler.js'),
},
}
export default nextConfig
```
```js filename="next.config.js" switcher
module.exports = {
cacheHandlers: {
default: require.resolve('./cache-handlers/default-handler.js'),
remote: require.resolve('./cache-handlers/remote-handler.js'),
},
}
```
### Handler types
- **`default`**: Used by the `'use cache'` directive
- **`remote`**: Used by the `'use cache: remote'` directive
If you don't configure `cacheHandlers`, Next.js uses an in-memory LRU (Least Recently Used) cache for both `default` and `remote`. You can view the [default implementation](https://github.com/vercel/next.js/blob/canary/packages/next/src/server/lib/cache-handlers/default.ts) as a reference.
You can also define additional named handlers (e.g., `sessions`, `analytics`) and reference them with `'use cache: <name>'`.
Note that `'use cache: private'` does not use cache handlers and cannot be customized.
## API Reference
A cache handler must implement the [`CacheHandler`](https://github.com/vercel/next.js/blob/canary/packages/next/src/server/lib/cache-handlers/types.ts) interface with the following methods:
### `get()`
Retrieve a cache entry for the given cache key.
```ts
get(cacheKey: string, softTags: string[]): Promise<CacheEntry | undefined>
```
| Parameter | Type | Description |
| ---------- | ---------- | ------------------------------------------------------------------------------------------- |
| `cacheKey` | `string` | The unique key for the cache entry. |
| `softTags` | `string[]` | Implicit tags derived from the route path. See [Soft Tags](#soft-tags) for how to use them. |
Returns a `CacheEntry` object if found, or `undefined` if not found or expired.
Your `get` method should retrieve the cache entry from storage, check if it has expired based on the `revalidate` time, and return `undefined` for missing or expired entries.
```js
const cacheHandler = {
async get(cacheKey, softTags) {
const entry = cache.get(cacheKey)
if (!entry) return undefined
// Check if expired
const now = Date.now()
if (now > entry.timestamp + entry.revalidate * 1000) {
return undefined
}
return entry
},
}
```
### `set()`
Store a cache entry for the given cache key.
```ts
set(cacheKey: string, pendingEntry: Promise<CacheEntry>): Promise<void>
```
| Parameter | Type | Description |
| -------------- | --------------------- | ------------------------------------------- |
| `cacheKey` | `string` | The unique key to store the entry under. |
| `pendingEntry` | `Promise<CacheEntry>` | A promise that resolves to the cache entry. |
The entry may still be pending when this is called (i.e., its value stream may still be written to). Your handler should await the promise before processing the entry.
Returns `Promise<void>`.
Your `set` method must await the `pendingEntry` promise before storing it, since the cache entry may still be generating when this method is called. Once resolved, store the entry in your cache system.
```js
const cacheHandler = {
async set(cacheKey, pendingEntry) {
// Wait for the entry to be ready
const entry = await pendingEntry
// Store in your cache system
cache.set(cacheKey, entry)
},
}
```
### `refreshTags()`
Called periodically before starting a new request to sync with external tag services.
```ts
refreshTags(): Promise<void>
```
This is useful if you're coordinating cache invalidation across multiple instances or services. For in-memory caches, this can be a no-op.
Returns `Promise<void>`.
For in-memory caches, this can be a no-op. For distributed caches, use this to sync tag state from an external service or database before processing requests.
```js
const cacheHandler = {
async refreshTags() {
// For in-memory cache, no action needed
// For distributed cache, sync tag state from external service
},
}
```
### `getExpiration()`
Get the maximum revalidation timestamp for a set of tags.
```ts
getExpiration(tags: string[]): Promise<number>
```
| Parameter | Type | Description |
| --------- | ---------- | -------------------------------------- |
| `tags` | `string[]` | Array of tags to check expiration for. |
Returns:
- `0` if none of the tags were ever revalidated
- A timestamp (in milliseconds) representing the most recent revalidation
- `Infinity` to indicate soft tags should be checked in the `get` method instead
If you're not tracking tag revalidation timestamps, return `0`. Otherwise, find the most recent revalidation timestamp across all the provided tags. Return `Infinity` if you prefer to handle soft tag checking in the `get` method.
```js
const cacheHandler = {
async getExpiration(tags) {
// Return 0 if not tracking tag revalidation
return 0
// Or return the most recent revalidation timestamp
// return Math.max(...tags.map(tag => tagTimestamps.get(tag) || 0));
},
}
```
### `updateTags()`
Called when tags are revalidated or expired.
```ts
updateTags(tags: string[], durations?: { expire?: number }): Promise<void>
```
| Parameter | Type | Description |
| ----------- | --------------------- | ---------------------------------------- |
| `tags` | `string[]` | Array of tags to update. |
| `durations` | `{ expire?: number }` | Optional expiration duration in seconds. |
Your handler should update its internal state to mark these tags as invalidated.
Returns `Promise<void>`.
When tags are revalidated, your handler should invalidate all cache entries that have any of those tags. Iterate through your cache and remove entries whose tags match the provided list.
```js
const cacheHandler = {
async updateTags(tags, durations) {
// Invalidate all cache entries with matching tags
for (const [key, entry] of cache.entries()) {
if (entry.tags.some((tag) => tags.includes(tag))) {
cache.delete(key)
}
}
},
}
```
## CacheEntry Type
The [`CacheEntry`](https://github.com/vercel/next.js/blob/canary/packages/next/src/server/lib/cache-handlers/types.ts) object has the following structure:
```ts
interface CacheEntry {
value: ReadableStream<Uint8Array>
tags: string[]
stale: number
timestamp: number
expire: number
revalidate: number
}
```
| Property | Type | Description |
| ------------ | ---------------------------- | ------------------------------------------------------------ |
| `value` | `ReadableStream<Uint8Array>` | The cached data as a stream. |
| `tags` | `string[]` | Cache tags (excluding soft tags). |
| `stale` | `number` | Duration in seconds for client-side staleness. |
| `timestamp` | `number` | When the entry was created (timestamp in milliseconds). |
| `expire` | `number` | How long the entry is allowed to be used (in seconds). |
| `revalidate` | `number` | How long until the entry should be revalidated (in seconds). |
> **Good to know**:
>
> - The `value` is a [`ReadableStream`](https://developer.mozilla.org/docs/Web/API/ReadableStream). Use [`.tee()`](https://developer.mozilla.org/docs/Web/API/ReadableStream/tee) if you need to read and store the stream data.
> - If the stream errors with partial data, your handler must decide whether to keep the partial cache or discard it.
## Examples
### Basic in-memory cache handler
Here's a minimal implementation using a `Map` for storage. This example demonstrates the core concepts, but for a production-ready implementation with LRU eviction, error handling, and tag management, see the [default cache handler](https://github.com/vercel/next.js/blob/canary/packages/next/src/server/lib/cache-handlers/default.ts).
```js filename="cache-handlers/memory-handler.js"
const cache = new Map()
const pendingSets = new Map()
module.exports = {
async get(cacheKey, softTags) {
// Wait for any pending set operation to complete
const pendingPromise = pendingSets.get(cacheKey)
if (pendingPromise) {
await pendingPromise
}
const entry = cache.get(cacheKey)
if (!entry) {
return undefined
}
// Check if entry has expired
const now = Date.now()
if (now > entry.timestamp + entry.revalidate * 1000) {
return undefined
}
return entry
},
async set(cacheKey, pendingEntry) {
// Create a promise to track this set operation
let resolvePending
const pendingPromise = new Promise((resolve) => {
resolvePending = resolve
})
pendingSets.set(cacheKey, pendingPromise)
try {
// Wait for the entry to be ready
const entry = await pendingEntry
// Store the entry in the cache
cache.set(cacheKey, entry)
} finally {
resolvePending()
pendingSets.delete(cacheKey)
}
},
async refreshTags() {
// No-op for in-memory cache
},
async getExpiration(tags) {
// Return 0 to indicate no tags have been revalidated
return 0
},
async updateTags(tags, durations) {
// Implement tag-based invalidation
for (const [key, entry] of cache.entries()) {
if (entry.tags.some((tag) => tags.includes(tag))) {
cache.delete(key)
}
}
},
}
```
### External storage pattern
For durable storage like Redis or a database, you'll need to serialize the cache entries. Here's a simple Redis example:
```js filename="cache-handlers/redis-handler.js"
const { createClient } = require('redis')
const client = createClient({ url: process.env.REDIS_URL })
client.connect()
module.exports = {
async get(cacheKey, softTags) {
// Retrieve from Redis
const stored = await client.get(cacheKey)
if (!stored) return undefined
// Deserialize the entry
const data = JSON.parse(stored)
// Reconstruct the ReadableStream from stored data
return {
value: new ReadableStream({
start(controller) {
controller.enqueue(Buffer.from(data.value, 'base64'))
controller.close()
},
}),
tags: data.tags,
stale: data.stale,
timestamp: data.timestamp,
expire: data.expire,
revalidate: data.revalidate,
}
},
async set(cacheKey, pendingEntry) {
const entry = await pendingEntry
// Read the stream to get the data
const reader = entry.value.getReader()
const chunks = []
try {
while (true) {
const { done, value } = await reader.read()
if (done) break
chunks.push(value)
}
} finally {
reader.releaseLock()
}
// Combine chunks and serialize for Redis storage
const data = Buffer.concat(chunks.map((chunk) => Buffer.from(chunk)))
await client.set(
cacheKey,
JSON.stringify({
value: data.toString('base64'),
tags: entry.tags,
stale: entry.stale,
timestamp: entry.timestamp,
expire: entry.expire,
revalidate: entry.revalidate,
}),
{ EX: entry.expire } // Use Redis TTL for automatic expiration
)
},
async refreshTags() {
// No-op for basic Redis implementation
// Could sync with external tag service if needed
},
async getExpiration(tags) {
// Return 0 to indicate no tags have been revalidated
// Could query Redis for tag expiration timestamps if tracking them
return 0
},
async updateTags(tags, durations) {
// Implement tag-based invalidation if needed
// Could iterate over keys with matching tags and delete them
},
}
```
## Distributed Tag Coordination
When running multiple Next.js instances, tag invalidation must be coordinated across instances. The default in-memory handler only tracks tags locally, so calling `revalidateTag()` on one instance does not affect others.
To coordinate tags across instances:
1. **`updateTags()`** is called when `revalidateTag()` is invoked. Your handler should write the invalidation timestamp to shared storage.
2. **`refreshTags()`** is called before each request. Your handler should read recent invalidation events from shared storage and update its local tag state.
3. **`getExpiration()`** returns the most recent revalidation timestamp across all provided tags. The default implementation returns `Math.max(...timestamps, 0)`.
Here's an example using Redis for distributed tag coordination:
```js filename="cache-handlers/distributed-tags.js"
const { createClient } = require('redis')
const client = createClient({ url: process.env.REDIS_URL })
client.connect()
// Local cache of tag timestamps, synced via refreshTags
const localTagTimestamps = new Map()
module.exports = {
// ... get() and set() methods ...
async refreshTags() {
// Sync tag invalidation timestamps from Redis
// Using a dedicated set to track tag keys avoids scanning the keyspace
const tagKeys = await client.sMembers('revalidated-tags')
if (tagKeys.length > 0) {
const values = await client.mGet(tagKeys.map((k) => `tag:${k}`))
for (let i = 0; i < tagKeys.length; i++) {
localTagTimestamps.set(tagKeys[i], Number(values[i]))
}
}
},
async getExpiration(tags) {
const timestamps = tags.map((tag) => localTagTimestamps.get(tag) || 0)
return Math.max(...timestamps, 0)
},
async updateTags(tags, durations) {
const now = Date.now()
const pipeline = client.multi()
for (const tag of tags) {
pipeline.set(`tag:${tag}`, String(now))
pipeline.sAdd('revalidated-tags', tag)
localTagTimestamps.set(tag, now)
}
await pipeline.exec()
},
}
```
For a full explanation of the tag architecture (including soft tags and multi-instance considerations), see [How Revalidation Works](/docs/app/guides/how-revalidation-works).
## Soft Tags
Soft tags are implicit tags that Next.js automatically generates based on the route path. For example, the route `/blog/hello` generates soft tags for `/`, `/blog`, `/blog/hello`, and their corresponding layout entries. These tags are prefixed internally with `_N_T_`.
Soft tags enable [`revalidatePath()`](/docs/app/api-reference/functions/revalidatePath) to work through the same tag-based cache system. When `revalidatePath('/blog/hello')` is called, it invalidates all cache entries associated with that path's soft tags.
In the cache handler API, soft tags are passed to the [`get()`](#get) method as the `softTags` parameter. Your handler should check whether any soft tag has been invalidated (via `getExpiration()` or direct timestamp comparison) after the cache entry's `timestamp`. If a soft tag was invalidated more recently than the entry was created, the entry should be treated as stale.
## Handling Streams
The `CacheEntry.value` is a [`ReadableStream<Uint8Array>`](https://developer.mozilla.org/docs/Web/API/ReadableStream). When implementing a cache handler that stores entries externally, keep in mind:
- **Use `.tee()`** if you need to both store and return the stream. One branch goes to storage, the other is returned to the caller.
- **Memory implications**: large pages produce large cache entries. For S3-like storage backends, consider streaming directly to storage without buffering the entire entry in memory.
- **Partial writes**: the stream may error partway through rendering. Your handler should decide whether to keep partial entries or discard them. Discarding is safer, as partial entries can produce incomplete pages.
## Error Handling
Cache operations should be implemented defensively:
- **`set()` failure**: the response is still served to the user because `set()` is called asynchronously after the response stream is already flowing. The cache entry is lost, and the next request triggers a fresh render.
- **`get()` failure**: your handler should catch internal errors and return `undefined` (the "cache miss" signal). The framework does not wrap `get()` in a try/catch, so an unhandled exception from `get()` will propagate as a render error.
- **Partial writes**: if a cache entry is partially written and then read, the behavior is undefined. Use atomic writes or a write-then-rename pattern to avoid serving partial entries.
## Platform Support
| Deployment Option | Supported |
| ------------------------------------------------------------------- | ----------------- |
| [Node.js server](/docs/app/getting-started/deploying#nodejs-server) | Yes |
| [Docker container](/docs/app/getting-started/deploying#docker) | Yes |
| [Static export](/docs/app/getting-started/deploying#static-export) | No |
| [Adapters](/docs/app/getting-started/deploying#adapters) | Platform-specific |
## Version History
| Version | Changes |
| --------- | --------------------------- |
| `v16.0.0` | `cacheHandlers` introduced. |
@@ -0,0 +1,81 @@
---
title: cacheLife
description: Learn how to set up cacheLife configurations in Next.js.
related:
title: Related
description: View related API references.
links:
- app/api-reference/directives/use-cache
- app/api-reference/config/next-config-js/cacheHandlers
- app/api-reference/functions/cacheLife
---
The `cacheLife` option allows you to define **custom cache profiles** when using the [`cacheLife`](/docs/app/api-reference/functions/cacheLife) function inside components or functions, and within the scope of the [`use cache` directive](/docs/app/api-reference/directives/use-cache).
## Usage
To define a profile, enable the [`cacheComponents` flag](/docs/app/api-reference/config/next-config-js/cacheComponents) and add the cache profile in the `cacheLife` object in the `next.config.js` file. For example, a `blog` profile:
```ts filename="next.config.ts" switcher
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
cacheComponents: true,
cacheLife: {
blog: {
stale: 3600, // 1 hour
revalidate: 900, // 15 minutes
expire: 86400, // 1 day
},
},
}
export default nextConfig
```
```js filename="next.config.js" switcher
module.exports = {
cacheComponents: true,
cacheLife: {
blog: {
stale: 3600, // 1 hour
revalidate: 900, // 15 minutes
expire: 86400, // 1 day
},
},
}
```
You can now use this custom `blog` configuration in your component or function as follows:
```tsx filename="app/actions.ts" highlight={4,5} switcher
import { cacheLife } from 'next/cache'
export async function getCachedData() {
'use cache'
cacheLife('blog')
const data = await fetch('/api/data')
return data
}
```
```jsx filename="app/actions.js" highlight={4,5} switcher
import { cacheLife } from 'next/cache'
export async function getCachedData() {
'use cache'
cacheLife('blog')
const data = await fetch('/api/data')
return data
}
```
## Reference
The configuration object has key values with the following format:
| **Property** | **Value** | **Description** | **Requirement** |
| ------------ | --------- | --------------------------------------------------------------------------------------------------------- | ------------------------------------------- |
| `stale` | `number` | Duration the client should cache a value without checking the server. | Optional |
| `revalidate` | `number` | Frequency at which the cache should refresh on the server; stale values may be served while revalidating. | Optional |
| `expire` | `number` | Maximum duration for which a value can remain stale before switching to dynamic. | Optional - Must be longer than `revalidate` |
@@ -0,0 +1,22 @@
---
title: compress
description: Next.js provides gzip compression to compress rendered content and static files, it only works with the server target. Learn more about it here.
---
{/* The content of this doc is shared between the app and pages router. You can use the `<PagesOnly>Content</PagesOnly>` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}
By default, Next.js uses `gzip` to compress rendered content and static files when using `next start` or a custom server. This is an optimization for applications that do not have compression configured. If compression is _already_ configured in your application via a custom server, Next.js will not add compression.
You can check if compression is enabled and which algorithm is used by looking at the [`Accept-Encoding`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Encoding) (browser accepted options) and [`Content-Encoding`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding) (currently used) headers in the response.
## Disabling compression
To disable **compression**, set the `compress` config option to `false`:
```js filename="next.config.js"
module.exports = {
compress: false,
}
```
We **do not recommend disabling compression** unless you have compression configured on your server, as compression reduces bandwidth usage and improves the performance of your application. For example, you're using [nginx](https://nginx.org/) and want to switch to `brotli`, set the `compress` option to `false` to allow nginx to handle compression.
@@ -0,0 +1,19 @@
---
title: crossOrigin
description: Use the `crossOrigin` option to add a crossOrigin tag on the `script` tags generated by `next/script`.
---
{/* The content of this doc is shared between the app and pages router. You can use the `<PagesOnly>Content</PagesOnly>` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}
Use the `crossOrigin` option to add a [`crossOrigin` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/crossorigin) in all `<script>` tags generated by the <AppOnly>[`next/script`](/docs/app/guides/scripts) component</AppOnly> <PagesOnly>[`next/script`](/docs/pages/guides/scripts) and [`next/head`](/docs/pages/api-reference/components/head)components</PagesOnly>, and define how cross-origin requests should be handled.
```js filename="next.config.js"
module.exports = {
crossOrigin: 'anonymous',
}
```
## Options
- `'anonymous'`: Adds [`crossOrigin="anonymous"`](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/crossorigin#anonymous) attribute.
- `'use-credentials'`: Adds [`crossOrigin="use-credentials"`](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/crossorigin#use-credentials).
@@ -0,0 +1,42 @@
---
title: cssChunking
description: Use the `cssChunking` option to control how CSS files are chunked in your Next.js application.
version: experimental
---
CSS Chunking is a strategy used to improve the performance of your web application by splitting and re-ordering CSS files into chunks. This allows you to load only the CSS that is needed for a specific route, instead of loading all the application's CSS at once.
You can control how CSS files are chunked using the `experimental.cssChunking` option in your `next.config.js` file:
```tsx filename="next.config.ts" switcher
import type { NextConfig } from 'next'
const nextConfig = {
experimental: {
cssChunking: true, // default
},
} satisfies NextConfig
export default nextConfig
```
```js filename="next.config.js" switcher
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
cssChunking: true, // default
},
}
module.exports = nextConfig
```
## Options
- **`true` (default)**: Next.js will try to merge CSS files whenever possible, determining explicit and implicit dependencies between files from import order to reduce the number of chunks and therefore the number of requests.
- **`false`**: Next.js will not attempt to merge or re-order your CSS files.
- **`'strict'`**: Next.js will load CSS files in the correct order they are imported into your files, which can lead to more chunks and requests.
You may consider using `'strict'` if you run into unexpected CSS behavior. For example, if you import `a.css` and `b.css` in different files using a different `import` order (`a` before `b`, or `b` before `a`), `true` will merge the files in any order and assume there are no dependencies between them. However, if `b.css` depends on `a.css`, you may want to use `'strict'` to prevent the files from being merged, and instead, load them in the order they are imported - which can result in more chunks and requests.
For most applications, we recommend `true` as it leads to fewer requests and better performance.
@@ -0,0 +1,80 @@
---
title: deploymentId
description: Configure a deployment identifier used for version skew protection and cache busting.
---
{/* The content of this doc is shared between the app and pages router. You can use the `<PagesOnly>Content</PagesOnly>` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}
The `deploymentId` option allows you to set an identifier for your deployment. This identifier is used for [version skew](/docs/app/guides/self-hosting#version-skew) protection and cache busting during rolling deployments.
```js filename="next.config.js"
module.exports = {
deploymentId: 'my-deployment-id',
}
```
You can also set the deployment ID using the `NEXT_DEPLOYMENT_ID` environment variable:
```bash
NEXT_DEPLOYMENT_ID=my-deployment-id next build
```
> **Good to know:** If both are set, the `deploymentId` value in `next.config.js` takes precedence over the `NEXT_DEPLOYMENT_ID` environment variable.
## How it works
When a `deploymentId` is configured, Next.js:
1. Appends `?dpl=<deploymentId>` to static asset URLs (JavaScript, CSS, images)
2. Adds an `x-deployment-id` header to client-side navigation requests
3. Adds an `x-nextjs-deployment-id` header to navigation responses
4. Injects a `data-dpl-id` attribute on the `<html>` element
When the client detects a mismatch between its deployment ID and the server's (via the response header), it triggers a hard navigation (full page reload) instead of a client-side navigation. This ensures users always receive assets <AppOnly>and Server Functions</AppOnly> from a consistent deployment version.
> **Good to know:** Next.js does not read the `?dpl=` query parameter on incoming requests. The query parameter is for cache busting (ensuring browsers and CDNs fetch fresh assets), not for routing. If you need version-aware routing, consult your hosting provider or CDN's documentation for implementing deployment-based routing.
## Use cases
### Rolling deployments
During a rolling deployment, some server instances may be running the new version while others are still running the old version. Without a deployment ID, users might receive a mix of old and new assets, causing errors.
Setting a consistent `deploymentId` per deployment ensures:
<AppOnly>
- Clients always request assets from a matching deployment version
- Mismatches trigger a full reload to fetch the correct assets
- Server Functions work correctly across deployment boundaries
</AppOnly>
<PagesOnly>
- Clients always request assets from a matching deployment version
- Mismatches trigger a full reload to fetch the correct assets
</PagesOnly>
### Multi-server environments
When running multiple instances of your Next.js application behind a load balancer, all instances for the same deployment should use the same `deploymentId`.
```js filename="next.config.js"
module.exports = {
deploymentId: process.env.DEPLOYMENT_VERSION || process.env.GIT_SHA,
}
```
## Version History
| Version | Changes |
| ---------- | ----------------------------------------------------- |
| `v14.1.4` | `deploymentId` stabilized as top-level config option. |
| `v13.4.10` | `experimental.deploymentId` introduced. |
## Related
- [Self-Hosting - Version Skew](/docs/app/guides/self-hosting#version-skew)
- [generateBuildId](/docs/app/api-reference/config/next-config-js/generateBuildId)
@@ -0,0 +1,59 @@
---
title: devIndicators
description: Configuration options for the on-screen indicator that gives context about the current route you're viewing during development.
---
`devIndicators` allows you to configure the on-screen indicator that gives context about the current route you're viewing during development.
```ts filename="Types"
devIndicators: false | {
position?: 'bottom-right'
| 'bottom-left'
| 'top-right'
| 'top-left', // defaults to 'bottom-left',
},
```
Setting `devIndicators` to `false` will hide the indicator, however Next.js will continue to surface any build or runtime errors that were encountered.
## Troubleshooting
### Indicator not marking a route as static
If you expect a route to be static and the indicator has marked it as dynamic, it's likely the route has opted out of prerendering.
You can confirm if a route is [prerendered](/docs/app/glossary#prerendering) or [dynamically rendered](/docs/app/glossary#dynamic-rendering) by building your application using `next build --debug`, and checking the output in your terminal. Static (or prerendered) routes will display a `` symbol, whereas dynamic routes will display a `ƒ` symbol. For example:
```bash filename="Build Output"
Route (app)
┌ ○ /_not-found
└ ƒ /products/[id]
○ (Static) prerendered as static content
ƒ (Dynamic) server-rendered on demand
```
<AppOnly>
There are two reasons a route might opt out of prerendering:
- The presence of [Request-time APIs](/docs/app/glossary#request-time-apis) which rely on request information.
- An [uncached data request](/docs/app/getting-started/fetching-data), like a call to an ORM or database driver.
Check your route for any of these conditions, and if you are not able to statically render the route, then consider using [`loading.js`](/docs/app/api-reference/file-conventions/loading) or [`<Suspense />`](https://react.dev/reference/react/Suspense) to leverage [streaming](/docs/app/getting-started/linking-and-navigating#streaming).
</AppOnly>
<PagesOnly>
When exporting [`getServerSideProps`](/docs/pages/building-your-application/data-fetching/get-server-side-props) or [`getInitialProps`](/docs/pages/api-reference/functions/get-initial-props) from a page, it will be marked as dynamic.
</PagesOnly>
## Version History
| Version | Changes |
| --------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| `v16.0.0` | `appIsrStatus`, `buildActivity`, and `buildActivityPosition` options have been removed. |
| `v15.2.0` | Improved on-screen indicator with new `position` option. `appIsrStatus`, `buildActivity`, and `buildActivityPosition` options have been deprecated. |
| `v15.0.0` | Static on-screen indicator added with `appIsrStatus` option. |
@@ -0,0 +1,20 @@
---
title: distDir
description: Set a custom build directory to use instead of the default .next directory.
---
{/* The content of this doc is shared between the app and pages router. You can use the `<PagesOnly>Content</PagesOnly>` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}
You can specify a name to use for a custom build directory to use instead of `.next`.
Open `next.config.js` and add the `distDir` config:
```js filename="next.config.js"
module.exports = {
distDir: 'build',
}
```
Now if you run `next build` Next.js will use `build` instead of the default `.next` folder.
> `distDir` **should not** leave your project directory. For example, `../build` is an **invalid** directory.
@@ -0,0 +1,65 @@
---
title: env
description: Learn to add and access environment variables in your Next.js application at build time.
version: legacy
---
{/* The content of this doc is shared between the app and pages router. You can use the `<PagesOnly>Content</PagesOnly>` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}
<AppOnly>
> Since the release of [Next.js 9.4](https://nextjs.org/blog/next-9-4) we now have a more intuitive and ergonomic experience for [adding environment variables](/docs/app/guides/environment-variables). Give it a try!
</AppOnly>
<PagesOnly>
> Since the release of [Next.js 9.4](https://nextjs.org/blog/next-9-4) we now have a more intuitive and ergonomic experience for [adding environment variables](/docs/pages/guides/environment-variables). Give it a try!
</PagesOnly>
<AppOnly>
> **Good to know**: environment variables specified in this way will **always** be included in the JavaScript bundle, prefixing the environment variable name with `NEXT_PUBLIC_` only has an effect when specifying them [through the environment or .env files](/docs/app/guides/environment-variables).
</AppOnly>
<PagesOnly>
> **Good to know**: environment variables specified in this way will **always** be included in the JavaScript bundle, prefixing the environment variable name with `NEXT_PUBLIC_` only has an effect when specifying them [through the environment or .env files](/docs/pages/guides/environment-variables).
</PagesOnly>
To add environment variables to the JavaScript bundle, open `next.config.js` and add the `env` config:
```js filename="next.config.js"
module.exports = {
env: {
customKey: 'my-value',
},
}
```
Now you can access `process.env.customKey` in your code. For example:
```jsx
function Page() {
return <h1>The value of customKey is: {process.env.customKey}</h1>
}
export default Page
```
Next.js will replace `process.env.customKey` with `'my-value'` at build time. Trying to destructure `process.env` variables won't work due to the nature of webpack [DefinePlugin](https://webpack.js.org/plugins/define-plugin/).
For example, the following line:
```jsx
return <h1>The value of customKey is: {process.env.customKey}</h1>
```
Will end up being:
```jsx
return <h1>The value of customKey is: {'my-value'}</h1>
```
@@ -0,0 +1,21 @@
---
title: expireTime
description: Customize stale-while-revalidate expire time for ISR enabled pages.
---
{/* The content of this doc is shared between the app and pages router. You can use the `<PagesOnly>Content</PagesOnly>` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}
You can specify a custom `stale-while-revalidate` expire time for CDNs to consume in the `Cache-Control` header for ISR enabled pages.
Open `next.config.js` and add the `expireTime` config:
```js filename="next.config.js"
module.exports = {
// one hour in seconds
expireTime: 3600,
}
```
Now when sending the `Cache-Control` header the expire time will be calculated depending on the specific revalidate period.
For example, if you have a revalidate of 15 minutes on a path and the expire time is one hour the generated `Cache-Control` header will be `s-maxage=900, stale-while-revalidate=2700` so that it can stay stale for 15 minutes less than the configured expire time.
@@ -0,0 +1,87 @@
---
title: exportPathMap
description: Customize the pages that will be exported as HTML files when using `next export`.
version: legacy
---
{/* The content of this doc is shared between the app and pages router. You can use the `<PagesOnly>Content</PagesOnly>` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}
> This feature is exclusive to `next export` and currently **deprecated** in favor of `getStaticPaths` with `pages` or `generateStaticParams` with `app`.
`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 [`next dev`](/docs/app/api-reference/cli/next#next-dev-options).
Let's start with an example, to create a custom `exportPathMap` for an app with the following pages:
- `pages/index.js`
- `pages/about.js`
- `pages/post.js`
Open `next.config.js` and add the following `exportPathMap` config:
```js filename="next.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' } },
}
},
}
```
> **Good to know**: the `query` field in `exportPathMap` cannot be used with [automatically statically optimized pages](/docs/pages/building-your-application/rendering/automatic-static-optimization) or [`getStaticProps` pages](/docs/pages/building-your-application/data-fetching/get-static-props) as they are rendered to HTML files at build-time and additional query information cannot be provided during `next export`.
The pages will then be exported as HTML files, for example, `/about` will become `/about.html`.
`exportPathMap` is an `async` function that receives 2 arguments: the first one is `defaultPathMap`, which is the default map used by Next.js. The second argument is an object with:
- `dev` - `true` when `exportPathMap` is being called in development. `false` when running `next 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`](#customizing-the-output-directory)). When `dev` is `true` the value of `outDir` will be `null`.
- `distDir` - Absolute path to the `.next/` directory (configurable with the [`distDir`](/docs/pages/api-reference/config/next-config-js/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 `getInitialProps` 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`.
## Adding a trailing slash
It is possible to configure Next.js to export pages as `index.html` files and require trailing slashes, `/about` becomes `/about/index.html` and is routable via `/about/`. This was the default behavior prior to Next.js 9.
To switch back and add a trailing slash, open `next.config.js` and enable the `trailingSlash` config:
```js filename="next.config.js"
module.exports = {
trailingSlash: true,
}
```
## Customizing the output directory
<AppOnly>
[`next export`](/docs/app/guides/static-exports) will use `out` as the default output directory, you can customize this using the `-o` argument, like so:
</AppOnly>
<PagesOnly>
[`next export`](/docs/pages/guides/static-exports) will use `out` as the default output directory, you can customize this using the `-o` argument, like so:
</PagesOnly>
```bash filename="Terminal"
next export -o outdir
```
> **Warning**: Using `exportPathMap` is deprecated and is overridden by `getStaticPaths` inside `pages`. We don't recommend using them together.
@@ -0,0 +1,19 @@
---
title: generateBuildId
description: Configure the build id, which is used to identify the current build in which your application is being served.
---
{/* The content of this doc is shared between the app and pages router. You can use the `<PagesOnly>Content</PagesOnly>` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}
Next.js generates an ID during `next build` to identify which version of your application is being served. The same build should be used and boot up multiple containers.
If you are rebuilding for each stage of your environment, you will need to generate a consistent build ID to use between containers. Use the `generateBuildId` command in `next.config.js`:
```jsx filename="next.config.js"
module.exports = {
generateBuildId: async () => {
// This could be anything, using the latest git hash
return process.env.GIT_HASH
},
}
```
@@ -0,0 +1,16 @@
---
title: generateEtags
description: Next.js will generate etags for every page by default. Learn more about how to disable etag generation here.
---
{/* The content of this doc is shared between the app and pages router. You can use the `<PagesOnly>Content</PagesOnly>` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}
Next.js will generate [etags](https://en.wikipedia.org/wiki/HTTP_ETag) for every page by default. You may want to disable etag generation for HTML pages depending on your cache strategy.
Open `next.config.js` and disable the `generateEtags` option:
```js filename="next.config.js"
module.exports = {
generateEtags: false,
}
```
@@ -0,0 +1,592 @@
---
title: headers
description: Add custom HTTP headers to your Next.js app.
---
{/* The content of this doc is shared between the app and pages router. You can use the `<PagesOnly>Content</PagesOnly>` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}
Headers allow you to set custom HTTP headers on the response to an incoming request on a given path.
To set custom HTTP headers you can use the `headers` key in `next.config.js`:
```js filename="next.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 response header objects, with `key` and `value` properties.
- `basePath`: `false` or `undefined` - if false the basePath won't be included when matching, can be used for external rewrites only.
- `locale`: `false` or `undefined` - whether the locale should not be included when matching.
- `has` is an array of [has objects](#header-cookie-and-query-matching) with the `type`, `key` and `value` properties.
- `missing` is an array of [missing objects](#header-cookie-and-query-matching) with the `type`, `key` and `value` properties.
Headers are checked before the filesystem which includes pages and `/public` files.
## 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`.
```js filename="next.config.js"
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/first-post` (no nested paths):
```js filename="next.config.js"
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',
},
],
},
]
},
}
```
The pattern `/blog/:slug` matches `/blog/first-post` and `/blog/post-1` but not a nested path like `/blog/a/b`. Patterns are anchored to the start, `/blog/:slug` will not match `/archive/blog/first-post`.
You can use modifiers on parameters: `*` (zero or more), `+` (one or more), `?` (zero or one). For example, `/blog/:slug*` matches `/blog`, `/blog/a`, and `/blog/a/b/c`.
Read more details on [path-to-regexp](https://github.com/pillarjs/path-to-regexp) documentation.
### 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`:
```js filename="next.config.js"
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`:
```js filename="next.config.js"
module.exports = {
async headers() {
return [
{
source: '/blog/:post(\\d{1,})',
headers: [
{
key: 'x-post',
value: ':post',
},
],
},
]
},
}
```
The following characters `(`, `)`, `{`, `}`, `:`, `*`, `+`, `?` are used for regex path matching, so when used in the `source` as non-special values they must be escaped by adding `\\` before them:
```js filename="next.config.js"
module.exports = {
async headers() {
return [
{
// this will match `/english(default)/something` being requested
source: '/english\\(default\\)/:slug',
headers: [
{
key: 'x-header',
value: 'value',
},
],
},
]
},
}
```
## Header, Cookie, and Query Matching
To only apply a header when header, cookie, or query values also match the `has` field or don't match the `missing` field can be used. Both the `source` and all `has` items must match and all `missing` items must not match for the header to be applied.
`has` and `missing` items can have the following fields:
- `type`: `String` - must be either `header`, `cookie`, `host`, or `query`.
- `key`: `String` - the key from the selected type to match against.
- `value`: `String` or `undefined` - the value to check for, if undefined any value will match. A regex like string can be used to capture a specific part of the value, e.g. if the value `first-(?<paramName>.*)` is used for `first-second` then `second` will be usable in the destination with `:paramName`.
```js filename="next.config.js"
module.exports = {
async headers() {
return [
// if the header `x-add-header` is present,
// the `x-another-header` header will be applied
{
source: '/:path*',
has: [
{
type: 'header',
key: 'x-add-header',
},
],
headers: [
{
key: 'x-another-header',
value: 'hello',
},
],
},
// if the header `x-no-header` is not present,
// the `x-another-header` header will be applied
{
source: '/:path*',
missing: [
{
type: 'header',
key: 'x-no-header',
},
],
headers: [
{
key: 'x-another-header',
value: 'hello',
},
],
},
// if the source, query, and cookie are matched,
// the `x-authorized` header will be applied
{
source: '/specific/:path*',
has: [
{
type: 'query',
key: 'page',
// the page value will not be available in the
// header key/values since value is provided and
// doesn't use a named capture group e.g. (?<page>home)
value: 'home',
},
{
type: 'cookie',
key: 'authorized',
value: 'true',
},
],
headers: [
{
key: 'x-authorized',
value: ':authorized',
},
],
},
// if the header `x-authorized` is present and
// contains a matching value, the `x-another-header` will be applied
{
source: '/:path*',
has: [
{
type: 'header',
key: 'x-authorized',
value: '(?<authorized>yes|true)',
},
],
headers: [
{
key: 'x-another-header',
value: ':authorized',
},
],
},
// if the host is `example.com`,
// this header will be applied
{
source: '/:path*',
has: [
{
type: 'host',
value: 'example.com',
},
],
headers: [
{
key: 'x-another-header',
value: ':authorized',
},
],
},
]
},
}
```
## Headers with basePath support
When leveraging [`basePath` support](/docs/app/api-reference/config/next-config-js/basePath) with headers each `source` is automatically prefixed with the `basePath` unless you add `basePath: false` to the header:
```js filename="next.config.js"
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
<AppOnly>
When leveraging [`i18n` support](/docs/app/guides/internationalization) 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.
</AppOnly>
<PagesOnly>
When leveraging [`i18n` support](/docs/pages/guides/internationalization) 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.
</PagesOnly>
```js filename="next.config.js"
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',
},
],
},
{
// this gets converted to /(en|fr|de)/(.*) so will not match the top-level
// `/` or `/fr` routes like /:path* would
source: '/(.*)',
headers: [
{
key: 'x-hello',
value: 'world',
},
],
},
]
},
}
```
## Cache-Control
Next.js sets the `Cache-Control` header of `public, max-age=31536000, immutable` for truly immutable assets. It cannot be overridden. These immutable files contain a SHA-hash in the file name, so they can be safely cached indefinitely. For example, [Static Image Imports](/docs/app/getting-started/images#local-images). You cannot set `Cache-Control` headers in `next.config.js` for these assets.
However, you can set `Cache-Control` headers for other responses or data.
<AppOnly>
Learn more about [caching](/docs/app/getting-started/caching) with the App Router.
</AppOnly>
<PagesOnly>
If you need to revalidate the cache of a page that has been [statically generated](/docs/pages/building-your-application/rendering/static-site-generation), you can do so by setting the `revalidate` prop in the page's [`getStaticProps`](/docs/pages/building-your-application/data-fetching/get-static-props) function.
To cache the response from an [API Route](/docs/pages/building-your-application/routing/api-routes), you can use `res.setHeader`:
```ts filename="pages/api/hello.ts" switcher
import type { NextApiRequest, NextApiResponse } from 'next'
type ResponseData = {
message: string
}
export default function handler(
req: NextApiRequest,
res: NextApiResponse<ResponseData>
) {
res.setHeader('Cache-Control', 's-maxage=86400')
res.status(200).json({ message: 'Hello from Next.js!' })
}
```
```js filename="pages/api/hello.js" switcher
export default function handler(req, res) {
res.setHeader('Cache-Control', 's-maxage=86400')
res.status(200).json({ message: 'Hello from Next.js!' })
}
```
You can also use caching headers (`Cache-Control`) inside `getServerSideProps` to cache dynamic responses. For example, using [`stale-while-revalidate`](https://web.dev/stale-while-revalidate/).
```ts filename="pages/index.tsx" switcher
import { GetStaticProps, GetStaticPaths, GetServerSideProps } from 'next'
// This value is considered fresh for ten seconds (s-maxage=10).
// If a request is repeated within the next 10 seconds, the previously
// cached value will still be fresh. If the request is repeated before 59 seconds,
// the cached value will be stale but still render (stale-while-revalidate=59).
//
// In the background, a revalidation request will be made to populate the cache
// with a fresh value. If you refresh the page, you will see the new value.
export const getServerSideProps = (async (context) => {
context.res.setHeader(
'Cache-Control',
'public, s-maxage=10, stale-while-revalidate=59'
)
return {
props: {},
}
}) satisfies GetServerSideProps
```
```js filename="pages/index.js" switcher
// This value is considered fresh for ten seconds (s-maxage=10).
// If a request is repeated within the next 10 seconds, the previously
// cached value will still be fresh. If the request is repeated before 59 seconds,
// the cached value will be stale but still render (stale-while-revalidate=59).
//
// In the background, a revalidation request will be made to populate the cache
// with a fresh value. If you refresh the page, you will see the new value.
export async function getServerSideProps({ req, res }) {
res.setHeader(
'Cache-Control',
'public, s-maxage=10, stale-while-revalidate=59'
)
return {
props: {},
}
}
```
</PagesOnly>
## Options
### CORS
[Cross-Origin Resource Sharing (CORS)](https://developer.mozilla.org/docs/Web/HTTP/CORS) is a security feature that allows you to control which sites can access your resources. You can set the `Access-Control-Allow-Origin` header to allow a specific origin to access your <PagesOnly>API Endpoints</PagesOnly><AppOnly>Route Handlers</AppOnly>.
```js
async headers() {
return [
{
source: "/api/:path*",
headers: [
{
key: "Access-Control-Allow-Origin",
value: "*", // Set your origin
},
{
key: "Access-Control-Allow-Methods",
value: "GET, POST, PUT, DELETE, OPTIONS",
},
{
key: "Access-Control-Allow-Headers",
value: "Content-Type, Authorization",
},
],
},
];
},
```
### X-DNS-Prefetch-Control
[This header](https://developer.mozilla.org/docs/Web/HTTP/Headers/X-DNS-Prefetch-Control) controls DNS prefetching, allowing browsers to proactively perform domain name resolution on external links, images, CSS, JavaScript, and more. This prefetching is performed in the background, so the [DNS](https://developer.mozilla.org/docs/Glossary/DNS) is more likely to be resolved by the time the referenced items are needed. This reduces latency when the user clicks a link.
```js
{
key: 'X-DNS-Prefetch-Control',
value: 'on'
}
```
### Strict-Transport-Security
[This header](https://developer.mozilla.org/docs/Web/HTTP/Headers/Strict-Transport-Security) informs browsers it should only be accessed using HTTPS, instead of using HTTP. Using the configuration below, all present and future subdomains will use HTTPS for a `max-age` of 2 years. This blocks access to pages or subdomains that can only be served over HTTP.
```js
{
key: 'Strict-Transport-Security',
value: 'max-age=63072000; includeSubDomains; preload'
}
```
### X-Frame-Options
[This header](https://developer.mozilla.org/docs/Web/HTTP/Headers/X-Frame-Options) indicates whether the site should be allowed to be displayed within an `iframe`. This can prevent against clickjacking attacks.
**This header has been superseded by CSP's `frame-ancestors` option**, which has better support in modern browsers (see [Content Security Policy](/docs/app/guides/content-security-policy) for configuration details).
```js
{
key: 'X-Frame-Options',
value: 'SAMEORIGIN'
}
```
### Permissions-Policy
[This header](https://developer.mozilla.org/docs/Web/HTTP/Headers/Permissions-Policy) allows you to control which features and APIs can be used in the browser. It was previously named `Feature-Policy`.
```js
{
key: 'Permissions-Policy',
value: 'camera=(), microphone=(), geolocation=(), browsing-topics=()'
}
```
### X-Content-Type-Options
[This header](https://developer.mozilla.org/docs/Web/HTTP/Headers/X-Content-Type-Options) prevents the browser from attempting to guess the type of content if the `Content-Type` header is not explicitly set. This can prevent XSS exploits for websites that allow users to upload and share files.
For example, a user trying to download an image, but having it treated as a different `Content-Type` like an executable, which could be malicious. This header also applies to downloading browser extensions. The only valid value for this header is `nosniff`.
```js
{
key: 'X-Content-Type-Options',
value: 'nosniff'
}
```
### Referrer-Policy
[This header](https://developer.mozilla.org/docs/Web/HTTP/Headers/Referrer-Policy) controls how much information the browser includes when navigating from the current website (origin) to another.
```js
{
key: 'Referrer-Policy',
value: 'origin-when-cross-origin'
}
```
### Content-Security-Policy
Learn more about adding a [Content Security Policy](/docs/app/guides/content-security-policy) to your application.
## Version History
| Version | Changes |
| --------- | ---------------- |
| `v13.3.0` | `missing` added. |
| `v10.2.0` | `has` added. |
| `v9.5.0` | Headers added. |
@@ -0,0 +1,75 @@
---
title: htmlLimitedBots
description: Specify a list of user agents that should receive blocking metadata.
---
The `htmlLimitedBots` config allows you to specify a list of user agents that should receive blocking metadata instead of [streaming metadata](/docs/app/api-reference/functions/generate-metadata#streaming-metadata).
```ts filename="next.config.ts" switcher
import type { NextConfig } from 'next'
const config: NextConfig = {
htmlLimitedBots: /MySpecialBot|MyAnotherSpecialBot|SimpleCrawler/,
}
export default config
```
```js filename="next.config.js" switcher
module.exports = {
htmlLimitedBots: /MySpecialBot|MyAnotherSpecialBot|SimpleCrawler/,
}
```
## Default list
Next.js includes a default list of HTML limited bots, including:
- Google crawlers (e.g. Mediapartners-Google, AdsBot-Google, Google-PageRenderer)
- Bingbot
- Twitterbot
- Slackbot
See the full list [here](https://github.com/vercel/next.js/blob/canary/packages/next/src/shared/lib/router/utils/html-bots.ts).
Specifying a `htmlLimitedBots` config will override the Next.js' default list. However, this is advanced behavior, and the default should be sufficient for most cases.
```ts filename="next.config.ts" switcher
const config: NextConfig = {
htmlLimitedBots: /MySpecialBot|MyAnotherSpecialBot|SimpleCrawler/,
}
export default config
```
```js filename="next.config.js" switcher
module.exports = {
htmlLimitedBots: /MySpecialBot|MyAnotherSpecialBot|SimpleCrawler/,
}
```
## Disabling
To fully disable streaming metadata:
```ts filename="next.config.ts"
import type { NextConfig } from 'next'
const config: NextConfig = {
htmlLimitedBots: /.*/,
}
export default config
```
```js filename="next.config.js" switcher
module.exports = {
htmlLimitedBots: /.*/,
}
```
## Version History
| Version | Changes |
| ------- | ------------------------------------ |
| 15.2.0 | `htmlLimitedBots` option introduced. |
@@ -0,0 +1,18 @@
---
title: httpAgentOptions
description: Next.js will automatically use HTTP Keep-Alive by default. Learn more about how to disable HTTP Keep-Alive here.
---
{/* The content of this doc is shared between the app and pages router. You can use the `<PagesOnly>Content</PagesOnly>` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}
In Node.js versions prior to 18, Next.js automatically polyfills `fetch()` with [undici](/docs/architecture/supported-browsers#polyfills) and enables [HTTP Keep-Alive](https://developer.mozilla.org/docs/Web/HTTP/Headers/Keep-Alive) by default.
To disable HTTP Keep-Alive for all `fetch()` calls on the server-side, open `next.config.js` and add the `httpAgentOptions` config:
```js filename="next.config.js"
module.exports = {
httpAgentOptions: {
keepAlive: false,
},
}
```
@@ -0,0 +1,271 @@
---
title: images
description: Custom configuration for the next/image loader
---
{/* The content of this doc is shared between the app and pages router. You can use the `<PagesOnly>Content</PagesOnly>` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}
If you want to use a cloud provider to optimize images instead of using the Next.js built-in Image Optimization API, you can configure `next.config.js` with the following:
```js filename="next.config.js"
module.exports = {
images: {
loader: 'custom',
loaderFile: './my/image/loader.js',
},
}
```
This `loaderFile` must point to a file relative to the root of your Next.js application. The file must export a default function that returns a string, for example:
<AppOnly>
```js filename="my/image/loader.js"
'use client'
export default function myImageLoader({ src, width, quality }) {
return `https://example.com/${src}?w=${width}&q=${quality || 75}`
}
```
Alternatively, you can use the [`loader` prop](/docs/app/api-reference/components/image#loader) to pass the function to each instance of `next/image`.
> **Good to know**: Customizing the image loader file, which accepts a function, requires using [Client Components](/docs/app/getting-started/server-and-client-components) to serialize the provided function.
To learn more about configuring the behavior of the built-in [Image Optimization API](/docs/app/api-reference/components/image) and the [Image Component](/docs/app/api-reference/components/image), see [Image Configuration Options](/docs/app/api-reference/components/image#configuration-options) for available options.
</AppOnly>
<PagesOnly>
```js filename="my/image/loader.js"
export default function myImageLoader({ src, width, quality }) {
return `https://example.com/${src}?w=${width}&q=${quality || 75}`
}
```
Alternatively, you can use the [`loader` prop](/docs/pages/api-reference/components/image#loader) to pass the function to each instance of `next/image`.
To learn more about configuring the behavior of the built-in [Image Optimization API](/docs/pages/api-reference/components/image) and the [Image Component](/docs/pages/api-reference/components/image), see [Image Configuration Options](/docs/pages/api-reference/components/image#configuration-options) for available options.
</PagesOnly>
## Example Loader Configuration
- [Akamai](#akamai)
- [AWS CloudFront](#aws-cloudfront)
- [Cloudinary](#cloudinary)
- [Cloudflare](#cloudflare)
- [Contentful](#contentful)
- [Fastly](#fastly)
- [Gumlet](#gumlet)
- [ImageEngine](#imageengine)
- [Imgix](#imgix)
- [PixelBin](#pixelbin)
- [Sanity](#sanity)
- [Sirv](#sirv)
- [Supabase](#supabase)
- [Thumbor](#thumbor)
- [Imagekit](#imagekitio)
- [Nitrogen AIO](#nitrogen-aio)
### Akamai
```js
// Docs: https://techdocs.akamai.com/ivm/reference/test-images-on-demand
export default function akamaiLoader({ src, width, quality }) {
return `https://example.com/${src}?imwidth=${width}`
}
```
### AWS CloudFront
```js
// Docs: https://aws.amazon.com/developer/application-security-performance/articles/image-optimization
export default function cloudfrontLoader({ src, width, quality }) {
const url = new URL(`https://example.com${src}`)
url.searchParams.set('format', 'auto')
url.searchParams.set('width', width.toString())
url.searchParams.set('quality', (quality || 75).toString())
return url.href
}
```
### Cloudinary
```js
// Demo: https://res.cloudinary.com/demo/image/upload/w_300,c_limit,q_auto/turtles.jpg
export default function cloudinaryLoader({ src, width, quality }) {
const params = ['f_auto', 'c_limit', `w_${width}`, `q_${quality || 'auto'}`]
return `https://example.com/${params.join(',')}${src}`
}
```
### Cloudflare
```js
// Docs: https://developers.cloudflare.com/images/transform-images
export default function cloudflareLoader({ src, width, quality }) {
const params = [`width=${width}`, `quality=${quality || 75}`, 'format=auto']
return `https://example.com/cdn-cgi/image/${params.join(',')}/${src}`
}
```
### Contentful
```js
// Docs: https://www.contentful.com/developers/docs/references/images-api/
export default function contentfulLoader({ src, width, quality }) {
const url = new URL(`https://example.com${src}`)
url.searchParams.set('fm', 'webp')
url.searchParams.set('w', width.toString())
url.searchParams.set('q', (quality || 75).toString())
return url.href
}
```
### Fastly
```js
// Docs: https://developer.fastly.com/reference/io/
export default function fastlyLoader({ src, width, quality }) {
const url = new URL(`https://example.com${src}`)
url.searchParams.set('auto', 'webp')
url.searchParams.set('width', width.toString())
url.searchParams.set('quality', (quality || 75).toString())
return url.href
}
```
### Gumlet
```js
// Docs: https://docs.gumlet.com/reference/image-transform-size
export default function gumletLoader({ src, width, quality }) {
const url = new URL(`https://example.com${src}`)
url.searchParams.set('format', 'auto')
url.searchParams.set('w', width.toString())
url.searchParams.set('q', (quality || 75).toString())
return url.href
}
```
### ImageEngine
```js
// Docs: https://support.imageengine.io/hc/en-us/articles/360058880672-Directives
export default function imageengineLoader({ src, width, quality }) {
const compression = 100 - (quality || 50)
const params = [`w_${width}`, `cmpr_${compression}`)]
return `https://example.com${src}?imgeng=/${params.join('/')`
}
```
### Imgix
```js
// Demo: https://static.imgix.net/daisy.png?format=auto&fit=max&w=300
export default function imgixLoader({ src, width, quality }) {
const url = new URL(`https://example.com${src}`)
const params = url.searchParams
params.set('auto', params.getAll('auto').join(',') || 'format')
params.set('fit', params.get('fit') || 'max')
params.set('w', params.get('w') || width.toString())
params.set('q', (quality || 50).toString())
return url.href
}
```
### PixelBin
```js
// Doc (Resize): https://www.pixelbin.io/docs/transformations/basic/resize/#width-w
// Doc (Optimise): https://www.pixelbin.io/docs/optimizations/quality/#image-quality-when-delivering
// Doc (Auto Format Delivery): https://www.pixelbin.io/docs/optimizations/format/#automatic-format-selection-with-f_auto-url-parameter
export default function pixelBinLoader({ src, width, quality }) {
const name = '<your-cloud-name>'
const opt = `t.resize(w:${width})~t.compress(q:${quality || 75})`
return `https://cdn.pixelbin.io/v2/${name}/${opt}/${src}?f_auto=true`
}
```
### Sanity
```js
// Docs: https://www.sanity.io/docs/image-urls
export default function sanityLoader({ src, width, quality }) {
const prj = 'zp7mbokg'
const dataset = 'production'
const url = new URL(`https://cdn.sanity.io/images/${prj}/${dataset}${src}`)
url.searchParams.set('auto', 'format')
url.searchParams.set('fit', 'max')
url.searchParams.set('w', width.toString())
if (quality) {
url.searchParams.set('q', quality.toString())
}
return url.href
}
```
### Sirv
```js
// Docs: https://sirv.com/help/articles/dynamic-imaging/
export default function sirvLoader({ src, width, quality }) {
const url = new URL(`https://example.com${src}`)
const params = url.searchParams
params.set('format', params.getAll('format').join(',') || 'optimal')
params.set('w', params.get('w') || width.toString())
params.set('q', (quality || 85).toString())
return url.href
}
```
### Supabase
```js
// Docs: https://supabase.com/docs/guides/storage/image-transformations#nextjs-loader
export default function supabaseLoader({ src, width, quality }) {
const url = new URL(`https://example.com${src}`)
url.searchParams.set('width', width.toString())
url.searchParams.set('quality', (quality || 75).toString())
return url.href
}
```
### Thumbor
```js
// Docs: https://thumbor.readthedocs.io/en/latest/
export default function thumborLoader({ src, width, quality }) {
const params = [`${width}x0`, `filters:quality(${quality || 75})`]
return `https://example.com${params.join('/')}${src}`
}
```
### ImageKit.io
```js
// Docs: https://imagekit.io/docs/image-transformation
export default function imageKitLoader({ src, width, quality }) {
const params = [`w-${width}`, `q-${quality || 80}`]
return `https://ik.imagekit.io/your_imagekit_id/${src}?tr=${params.join(',')}`
}
```
### Nitrogen AIO
```js
// Docs: https://docs.n7.io/aio/intergrations/
export default function aioLoader({ src, width, quality }) {
const url = new URL(src, window.location.href)
const params = url.searchParams
const aioParams = params.getAll('aio')
aioParams.push(`w-${width}`)
if (quality) {
aioParams.push(`q-${quality.toString()}`)
}
params.set('aio', aioParams.join(';'))
return url.href
}
```
@@ -0,0 +1,103 @@
---
title: Custom Next.js Cache Handler
nav_title: cacheHandler
description: Configure the Next.js cache used for storing and revalidating data to use any external service like Redis, Memcached, or others.
---
You can configure the Next.js cache location if you want to persist cached pages and data to durable storage, or share the cache across multiple containers or instances of your Next.js application.
> **Good to know**: The `cacheHandler` (singular) configuration is specifically used by Next.js for server cache operations such as storing and revalidating ISR, route handler responses, and optimized images. It is **not** used by `'use cache'` directives. For `'use cache'` directives, use [`cacheHandlers`](/docs/app/api-reference/config/next-config-js/cacheHandlers) (plural) instead.
```js filename="next.config.js"
module.exports = {
cacheHandler: require.resolve('./cache-handler.js'),
cacheMaxMemorySize: 0, // disable default in-memory caching
}
```
View an example of a [custom cache handler](/docs/app/guides/self-hosting#configuring-caching) and learn more about the implementation.
## API Reference
The cache handler can implement the following methods: `get`, `set`, `revalidateTag`, and `resetRequestCache`.
### `get()`
| Parameter | Type | Description |
| --------- | -------- | --------------------------------------- |
| `key` | `string` | The key to the cached value. |
| `ctx` | `object` | Context including the cache entry kind. |
The `ctx` parameter contains a `kind` property that indicates the type of cache entry being retrieved. Possible values include `'APP_PAGE'`, `'APP_ROUTE'`, `'PAGES'`, `'FETCH'`, and `'IMAGE'`.
Returns the cached value or `null` if not found.
### `set()`
| Parameter | Type | Description |
| --------- | -------------- | -------------------------------- |
| `key` | `string` | The key to store the data under. |
| `data` | Data or `null` | The data to be cached. |
| `ctx` | `{ tags: [] }` | The cache tags provided. |
The `data` object contains a `kind` property that indicates the type of cache entry. For image optimization, `kind` will be `'IMAGE'` and the data will include properties like `buffer`, `etag`, `extension`, and `revalidate`.
Returns `Promise<void>`.
### `revalidateTag()`
| Parameter | Type | Description |
| --------- | ---------------------- | ----------------------------- |
| `tag` | `string` or `string[]` | The cache tags to revalidate. |
Returns `Promise<void>`. Learn more about [revalidating data](/docs/app/guides/incremental-static-regeneration) or the [`revalidateTag()`](/docs/app/api-reference/functions/revalidateTag) function.
### `resetRequestCache()`
This method resets the temporary in-memory cache for a single request before the next request.
Returns `void`.
**Good to know:**
- `revalidatePath` is a convenience layer on top of cache tags. Calling `revalidatePath` will call your `revalidateTag` function, which you can then choose if you want to tag cache keys based on the path.
## Image Optimization Caching
The `cacheHandler` can also be used for caching optimized images from `next/image`. To enable this, set `images.customCacheHandler` to `true` in your `next.config.js`:
```js filename="next.config.js"
module.exports = {
cacheHandler: require.resolve('./cache-handler.js'),
images: {
customCacheHandler: true,
},
}
```
> **Good to know**: This opt-in flag will become the default behavior in the next major version. Setting it now allows you to prepare your cache handler for image optimization entries.
You can use the `kind` property to differentiate between cache entry types and handle images separately if needed, for example to implement an eviction policy or store images in a different location.
When handling image cache entries, the `kind` will be `'IMAGE'` and the data will include `buffer`, `etag`, `extension`, and `revalidate` properties.
## Platform Support
| Deployment Option | Supported |
| ------------------------------------------------------------------- | ----------------- |
| [Node.js server](/docs/app/getting-started/deploying#nodejs-server) | Yes |
| [Docker container](/docs/app/getting-started/deploying#docker) | Yes |
| [Static export](/docs/app/getting-started/deploying#static-export) | No |
| [Adapters](/docs/app/getting-started/deploying#adapters) | Platform-specific |
Learn how to [configure ISR](/docs/app/guides/self-hosting#caching-and-isr) when self-hosting Next.js.
## Version History
| Version | Changes |
| --------- | ------------------------------------------------------------ |
| `v16.2.0` | `cacheHandler` support for image optimization caching. |
| `v14.1.0` | Renamed to `cacheHandler` and became stable. |
| `v13.4.0` | `incrementalCacheHandlerPath` support for `revalidateTag`. |
| `v13.4.0` | `incrementalCacheHandlerPath` support for standalone output. |
| `v12.2.0` | Experimental `incrementalCacheHandlerPath` added. |
@@ -0,0 +1,146 @@
---
title: next.config.js
description: Learn how to configure your application with next.config.js.
---
{/* The content of this doc is shared between the app and pages router. You can use the `<PagesOnly>Content</PagesOnly>` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}
Next.js can be configured through a `next.config.js` file in the root of your project directory (for example, by `package.json`) with a default export.
```js filename="next.config.js"
// @ts-check
/** @type {import('next').NextConfig} */
const nextConfig = {
/* config options here */
}
module.exports = nextConfig
```
## ECMAScript Modules
`next.config.js` is a regular Node.js module, not a JSON file. It gets used by the Next.js server and build phases, and it's not included in the browser build.
If you need [ECMAScript modules](https://nodejs.org/api/esm.html), you can use `next.config.mjs`:
```js filename="next.config.mjs"
// @ts-check
/**
* @type {import('next').NextConfig}
*/
const nextConfig = {
/* config options here */
}
export default nextConfig
```
> **Good to know**: `next.config` with the `.cjs` or `.cts` extensions are currently **not** supported.
## Configuration as a Function
You can also use a function:
```js filename="next.config.mjs"
// @ts-check
export default (phase, { defaultConfig }) => {
/**
* @type {import('next').NextConfig}
*/
const nextConfig = {
/* config options here */
}
return nextConfig
}
```
### Async Configuration
Since Next.js 12.1.0, you can use an async function:
```js filename="next.config.js"
// @ts-check
module.exports = async (phase, { defaultConfig }) => {
/**
* @type {import('next').NextConfig}
*/
const nextConfig = {
/* config options here */
}
return nextConfig
}
```
### Phase
`phase` is the current context in which the configuration is loaded. You can see the [available phases](https://github.com/vercel/next.js/blob/5e6b008b561caf2710ab7be63320a3d549474a5b/packages/next/shared/lib/constants.ts#L19-L23). Phases can be imported from `next/constants`:
```js filename="next.config.js"
// @ts-check
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 */
}
}
```
## TypeScript
If you are using TypeScript in your project, you can use `next.config.ts` to use TypeScript in your configuration:
```ts filename="next.config.ts"
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
/* config options here */
}
export default nextConfig
```
The commented lines are the place where you can put the configs allowed by `next.config.js`, which are [defined in this file](https://github.com/vercel/next.js/blob/canary/packages/next/src/server/config-shared.ts).
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. `next.config.js` will not be parsed by Webpack or Babel.
This page documents all the available configuration options:
## Unit Testing (experimental)
Starting in Next.js 15.1, the `next/experimental/testing/server` package contains utilities to help unit test `next.config.js` files.
The `unstable_getResponseFromNextConfig` function runs the [`headers`](/docs/app/api-reference/config/next-config-js/headers), [`redirects`](/docs/app/api-reference/config/next-config-js/redirects), and [`rewrites`](/docs/app/api-reference/config/next-config-js/rewrites) functions from `next.config.js` with the provided request information and returns `NextResponse` with the results of the routing.
> The response from `unstable_getResponseFromNextConfig` only considers `next.config.js` fields and does not consider proxy or filesystem routes, so the result in production may be different than the unit test.
```js
import {
getRedirectUrl,
unstable_getResponseFromNextConfig,
} from 'next/experimental/testing/server'
const response = await unstable_getResponseFromNextConfig({
url: 'https://nextjs.org/test',
nextConfig: {
async redirects() {
return [{ source: '/test', destination: '/test2', permanent: false }]
},
},
})
expect(response.status).toEqual(307)
expect(getRedirectUrl(response)).toEqual('https://nextjs.org/test2')
```
@@ -0,0 +1,72 @@
---
title: inlineCss
description: Enable inline CSS support.
version: experimental
---
## Usage
Experimental support for inlining CSS in the `<head>`. When this flag is enabled, all places where we normally generate a `<link>` tag will instead have a generated `<style>` tag.
```ts filename="next.config.ts" switcher
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
experimental: {
inlineCss: true,
},
}
export default nextConfig
```
```js filename="next.config.js" switcher
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
inlineCss: true,
},
}
module.exports = nextConfig
```
## Trade-Offs
- **Enable** if you use atomic CSS (like Tailwind) and want to optimize first-load performance for new visitors
- **Skip** if returning visitors are common and you want them to benefit from cached stylesheets
### When Inline CSS Helps
Normally, the browser must download HTML, parse it, discover CSS `<link>` tags, then request stylesheets before it can render. Inlining [eliminates this request waterfall](https://web.dev/learn/performance/optimize-resource-loading#inline_critical_css), so that styles arrive with the HTML, so the browser can render immediately.
This benefit is strongest with:
- **First-time visitors**: Since CSS files are render-blocking, inlining eliminates the initial download delay that first-time visitors experience. Returning visitors with cached stylesheets won't see this benefit.
- **Performance metrics**: By removing additional network requests for CSS files, inlining can significantly improve [First Contentful Paint (FCP)](https://web.dev/articles/fcp) and [Largest Contentful Paint (LCP)](https://web.dev/articles/lcp).
- **Slow connections**: For users on high-latency networks, each additional request adds delay. Inlining reduces round trips, which matters most when connections are slow.
- **Atomic CSS (Tailwind)**: Utility-first frameworks generate only the classes you use, keeping CSS small. The styles for a page don't grow proportionally with page complexity—they're typically compact regardless of how much UI you build. This makes inlining practical since you get the performance benefit without significantly bloating HTML.
### When External CSS is Better
Inlined styles cannot be cached separately from HTML. Every page load re-downloads the same CSS.
This trade-off matters most with:
- **Returning visitors**: Users who visit your site repeatedly would benefit from cached external stylesheets. With inlining, they re-download styles on every visit.
- **Large CSS bundles**: External stylesheets cache independently and load efficiently on modern infrastructure. Inlined CSS arrives with every HTML response, increasing [Time to First Byte (TTFB)](https://web.dev/articles/ttfb) and preventing browsers from caching styles separately. This trade-off works for small CSS (atomic frameworks like Tailwind), but adds overhead for larger bundles (component libraries like Bootstrap or Material UI).
- **Many pages sharing styles**: External stylesheets cached on one page speed up navigation to other pages. Inlined styles provide no cross-page caching benefit.
> **Good to know**:
>
> This feature is currently experimental and has some known limitations:
>
> - CSS inlining is applied globally and cannot be configured on a per-page basis
> - Styles are duplicated during initial page load - once within `<style>` tags for SSR and once in the RSC payload
> - When navigating to prerendered pages, styles will use `<link>` tags instead of inline CSS to avoid duplication
> - This feature is not available in development mode and only works in production builds
@@ -0,0 +1,189 @@
---
title: logging
description: Configure logging behavior in the terminal when running Next.js in development mode, including fetch logging, incoming requests, and forwarding browser console logs to the terminal.
---
{/* The content of this doc is shared between the app and pages router. You can use the `<PagesOnly>Content</PagesOnly>` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}
## Options
<AppOnly>
### Fetching
You can configure the logging level and whether the full URL is logged to the console when running Next.js in development mode.
```js filename="next.config.js"
module.exports = {
logging: {
fetches: {
fullUrl: true,
},
},
}
```
Any `fetch` requests that are restored from the [Server Components HMR cache](/docs/app/api-reference/config/next-config-js/serverComponentsHmrCache) are not logged by default. However, this can be enabled by setting `logging.fetches.hmrRefreshes` to `true`.
```js filename="next.config.js"
module.exports = {
logging: {
fetches: {
hmrRefreshes: true,
},
},
}
```
### Server Functions
[Server Function](https://react.dev/reference/rsc/server-functions) invocations are logged by default during development. You can disable this by setting `logging.serverFunctions` to `false`.
```js filename="next.config.js"
module.exports = {
logging: {
serverFunctions: false,
},
}
```
When enabled, the terminal displays each Server Function call with its function name, arguments, and duration:
```bash filename="Terminal"
POST /
└─ ƒ myAction(arg1, arg2) in 5ms app/actions.ts
```
</AppOnly>
### Incoming Requests
By default all the incoming requests will be logged in the console during development. You can use the `incomingRequests` option to decide which requests to ignore.
Since this is only logged in development, this option doesn't affect production builds.
```js filename="next.config.js"
module.exports = {
logging: {
incomingRequests: {
ignore: [/\api\/v1\/health/],
},
},
}
```
Or you can disable incoming request logging by setting `incomingRequests` to `false`.
```js filename="next.config.js"
module.exports = {
logging: {
incomingRequests: false,
},
}
```
### Browser Console Logs
You can forward browser console logs (such as `console.log`, `console.warn`, `console.error`) to the terminal during development. This is useful for debugging client-side code without needing to check the browser's developer tools.
```js filename="next.config.js"
module.exports = {
logging: {
browserToTerminal: true,
},
}
```
#### Options
The `browserToTerminal` option accepts the following values:
| Value | Description |
| --------- | --------------------------------------------------- |
| `'warn'` | Forward only warnings and errors, by default |
| `'error'` | Forward only errors |
| `true` | Forward all console output (log, info, warn, error) |
| `false` | Disable browser log forwarding |
```js filename="next.config.js"
module.exports = {
logging: {
browserToTerminal: 'warn',
},
}
```
#### Source Location
When enabled, browser logs include source location information (file path and line number) by default. For example:
<AppOnly>
```tsx filename="app/page.tsx" highlight={8}
'use client'
export default function Home() {
return (
<button
type="button"
onClick={() => {
console.log('Hello World')
}}
>
Click me
</button>
)
}
```
Clicking the button prints this message to the terminal:
```bash filename="Terminal"
[browser] Hello World (app/page.tsx:8:17)
```
</AppOnly>
<PagesOnly>
```tsx filename="pages/index.tsx" highlight={6}
export default function Home() {
return (
<button
type="button"
onClick={() => {
console.log('Hello World')
}}
>
Click me
</button>
)
}
```
Clicking the button prints this message to the terminal:
```bash filename="Terminal"
[browser] Hello World (pages/index.tsx:6:17)
```
</PagesOnly>
### Disabling Logging
In addition, you can disable the development logging by setting `logging` to `false`.
```js filename="next.config.js"
module.exports = {
logging: false,
}
```
## Version History
| Version | Changes |
| --------- | -------------------------------------------------------------------------------- |
| `v16.2.0` | `browserToTerminal` added (moved from `experimental.browserDebugInfoInTerminal`) |
| `v15.4.0` | `experimental.browserDebugInfoInTerminal` introduced |
| `v15.2.0` | `incomingRequests` added |
| `v15.0.0` | `logging: false` option added, `fetches.hmrRefreshes` added for App Router |
| `v14.0.0` | `logging.fetches` moved to stable for App Router |
@@ -0,0 +1,21 @@
---
title: mdxRs
description: Use the new Rust compiler to compile MDX files in the App Router.
version: experimental
---
For experimental use with `@next/mdx`. Compiles MDX files using the new Rust compiler.
```js filename="next.config.js"
const withMDX = require('@next/mdx')()
/** @type {import('next').NextConfig} */
const nextConfig = {
pageExtensions: ['ts', 'tsx', 'mdx'],
experimental: {
mdxRs: true,
},
}
module.exports = withMDX(nextConfig)
```
@@ -0,0 +1,21 @@
---
title: onDemandEntries
description: Configure how Next.js will dispose and keep in memory pages created in development.
---
{/* The content of this doc is shared between the app and pages router. You can use the `<PagesOnly>Content</PagesOnly>` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}
Next.js exposes some options that give you some control over how the server will dispose or keep in memory built pages in development.
To change the defaults, open `next.config.js` and add the `onDemandEntries` config:
```js filename="next.config.js"
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,
},
}
```
@@ -0,0 +1,49 @@
---
title: optimizePackageImports
description: API Reference for optimizePackageImports Next.js Config Option
version: experimental
---
{/* The content of this doc is shared between the app and pages router. You can use the `<PagesOnly>Content</PagesOnly>` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}
Some packages can export hundreds or thousands of modules, which can cause performance issues in development and production.
Adding a package to `experimental.optimizePackageImports` will only load the modules you are actually using, while still giving you the convenience of writing import statements with many named exports.
```js filename="next.config.js"
module.exports = {
experimental: {
optimizePackageImports: ['package-name'],
},
}
```
The following libraries are optimized by default:
- `lucide-react`
- `date-fns`
- `lodash-es`
- `ramda`
- `antd`
- `react-bootstrap`
- `ahooks`
- `@ant-design/icons`
- `@headlessui/react`
- `@headlessui-float/react`
- `@heroicons/react/20/solid`
- `@heroicons/react/24/solid`
- `@heroicons/react/24/outline`
- `@visx/visx`
- `@tremor/react`
- `rxjs`
- `@mui/material`
- `@mui/icons-material`
- `recharts`
- `react-use`
- `@material-ui/core`
- `@material-ui/icons`
- `@tabler/icons-react`
- `mui-core`
- `react-icons/*`
- `effect`
- `@effect/*`
@@ -0,0 +1,158 @@
---
title: output
description: Next.js automatically traces which files are needed by each page to allow for easy deployment of your application. Learn how it works here.
---
{/* The content of this doc is shared between the app and pages router. You can use the `<PagesOnly>Content</PagesOnly>` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}
During a build, Next.js will automatically trace each page and its dependencies to determine all of the files that are needed for deploying a production version of your application.
This feature helps reduce the size of deployments drastically. Previously, when deploying with Docker you would need to have all files from your package's `dependencies` installed to run `next start`. Starting with Next.js 12, you can leverage Output File Tracing in the `.next/` directory to only include the necessary files.
Furthermore, this removes the need for the deprecated `serverless` target which can cause various issues and also creates unnecessary duplication.
## How it Works
During `next build`, Next.js will use [`@vercel/nft`](https://github.com/vercel/nft) to statically analyze `import`, `require`, and `fs` usage to determine all files that a page might load.
Next.js' production server is also traced for its needed files and output at `.next/next-server.js.nft.json` which can be leveraged in production.
To leverage the `.nft.json` files emitted to the `.next` output directory, you can read the list of files in each trace that are relative to the `.nft.json` file and then copy them to your deployment location.
## Automatically Copying Traced Files
Next.js can automatically create a `standalone` folder that copies only the necessary files for a production deployment including select files in `node_modules`.
To leverage this automatic copying you can enable it in your `next.config.js`:
```js filename="next.config.js"
module.exports = {
output: 'standalone',
}
```
This will create a folder at `.next/standalone` which can then be deployed on its own without installing `node_modules`.
Additionally, a minimal `server.js` file is also output which can be used instead of `next start`. This minimal server does not copy the `public` or `.next/static` folders by default as these should ideally be handled by a CDN instead, although these folders can be copied to the `standalone/public` and `standalone/.next/static` folders manually, after which `server.js` file will serve these automatically.
To copy these manually, you can use the `cp` command-line tool after you `next build`:
```bash filename="Terminal"
cp -r public .next/standalone/ && cp -r .next/static .next/standalone/.next/
```
To start your minimal `server.js` file locally, run the following command:
```bash filename="Terminal"
node .next/standalone/server.js
```
<AppOnly>
> **Good to know**:
>
> - If your project needs to listen to a specific port or hostname, you can define `PORT` or `HOSTNAME` environment variables before running `server.js`. For example, run `PORT=8080 HOSTNAME=0.0.0.0 node server.js` to start the server on `http://0.0.0.0:8080`.
</AppOnly>
<PagesOnly>
> **Good to know**:
>
> - `next.config.js` is read during `next build` and serialized into the `server.js` output file.
> - If your project needs to listen to a specific port or hostname, you can define `PORT` or `HOSTNAME` environment variables before running `server.js`. For example, run `PORT=8080 HOSTNAME=0.0.0.0 node server.js` to start the server on `http://0.0.0.0:8080`.
</PagesOnly>
## Caveats
- While tracing in monorepo setups, the project directory is used for tracing by default. For `next build packages/web-app`, `packages/web-app` would be the tracing root and any files outside of that folder will not be included. To include files outside of this folder you can set `outputFileTracingRoot` in your `next.config.js`.
```js filename="packages/web-app/next.config.js"
const path = require('path')
module.exports = {
// this includes files from the monorepo base two directories up
outputFileTracingRoot: path.join(__dirname, '../../'),
}
```
- There are some cases in which Next.js might fail to include required files, or might incorrectly include unused files. In those cases, you can leverage `outputFileTracingExcludes` and `outputFileTracingIncludes` respectively in `next.config.js`. Each option accepts an object whose keys are **route globs** (matched with [picomatch](https://www.npmjs.com/package/picomatch#basic-globbing) against the route path, e.g. `/api/hello`) and whose values are **glob patterns resolved from the project root** that specify files to include or exclude in the trace.
> **Good to know**:
> In a monorepo, `project root` refers to the Next.js project root (the folder containing next.config.js, e.g., packages/web-app), not necessarily the monorepo root.
```js filename="next.config.js"
module.exports = {
outputFileTracingExcludes: {
'/api/hello': ['./un-necessary-folder/**/*'],
},
outputFileTracingIncludes: {
'/api/another': ['./necessary-folder/**/*'],
'/api/login/\\[\\[\\.\\.\\.slug\\]\\]': [
'./node_modules/aws-crt/dist/bin/**/*',
],
},
}
```
Using a `src/` directory does not change how you write these options:
- **Keys** still match the route path (`'/api/hello'`, `'/products/[id]'`, etc.).
- **Values** can reference paths under `src/` since they are resolved relative to the project root.
```js filename="next.config.js"
module.exports = {
outputFileTracingIncludes: {
'/products/*': ['src/lib/payments/**/*'],
'/*': ['src/config/runtime/**/*.json'],
},
outputFileTracingExcludes: {
'/api/*': ['src/temp/**/*', 'public/large-logs/**/*'],
},
}
```
You can also target all routes using a global key like `'/*'`:
```js filename="next.config.js"
module.exports = {
outputFileTracingIncludes: {
'/*': ['src/i18n/locales/**/*.json'],
},
}
```
These options are applied to server traces and do not affect routes that do not produce a server trace file:
- Edge Runtime routes are not affected.
- Fully static pages are not affected.
In monorepos or when you need to include files outside the app folder, combine `outputFileTracingRoot` with includes:
```js filename="next.config.js"
const path = require('path')
module.exports = {
// Trace from the monorepo root
outputFileTracingRoot: path.join(__dirname, '../../'),
outputFileTracingIncludes: {
'/route1': ['../shared/assets/**/*'],
},
}
```
> **Good to know**:
>
> - Prefer forward slashes (`/`) in patterns for cross-platform compatibility.
> - Keep patterns as narrow as possible to avoid oversized traces (avoid `**/*` at the repo root).
Common include patterns for native/runtime assets:
```js filename="next.config.js"
module.exports = {
outputFileTracingIncludes: {
'/*': ['node_modules/sharp/**/*', 'node_modules/aws-crt/dist/bin/**/*'],
},
}
```
@@ -0,0 +1,57 @@
---
title: pageExtensions
description: Extend the default page extensions used by Next.js when resolving pages in the Pages Router.
---
{/* The content of this doc is shared between the app and pages router. You can use the `<PagesOnly>Content</PagesOnly>` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}
<AppOnly>
By default, Next.js accepts files with the following extensions: `.tsx`, `.ts`, `.jsx`, `.js`. This can be modified to allow other extensions like markdown (`.md`, `.mdx`).
```js filename="next.config.js"
const withMDX = require('@next/mdx')()
/** @type {import('next').NextConfig} */
const nextConfig = {
pageExtensions: ['js', 'jsx', 'ts', 'tsx', 'md', 'mdx'],
}
module.exports = withMDX(nextConfig)
```
</AppOnly>
<PagesOnly>
You can extend the default Page extensions (`.tsx`, `.ts`, `.jsx`, `.js`) used by Next.js. Inside `next.config.js`, add the `pageExtensions` config:
```js filename="next.config.js"
module.exports = {
pageExtensions: ['mdx', 'md', 'jsx', 'js', 'tsx', 'ts'],
}
```
Changing these values affects _all_ Next.js pages, including the following:
- [`proxy.js`](/docs/pages/api-reference/file-conventions/proxy)
- [`instrumentation.js`](/docs/pages/guides/instrumentation)
- `pages/_document.js`
- `pages/_app.js`
- `pages/api/`
For example, if you reconfigure `.ts` page extensions to `.page.ts`, you would need to rename pages like `proxy.page.ts`, `instrumentation.page.ts`, `_app.page.ts`.
## Including non-page files in the `pages` directory
You can colocate test files or other files used by components in the `pages` directory. Inside `next.config.js`, add the `pageExtensions` config:
```js filename="next.config.js"
module.exports = {
pageExtensions: ['page.tsx', 'page.ts', 'page.jsx', 'page.js'],
}
```
Then, rename your pages to have a file extension that includes `.page` (e.g. rename `MyPage.tsx` to `MyPage.page.tsx`). Ensure you rename _all_ Next.js pages, including the files mentioned above.
</PagesOnly>
@@ -0,0 +1,14 @@
---
title: poweredByHeader
description: Next.js will add the `x-powered-by` header by default. Learn to opt-out of it here.
---
{/* The content of this doc is shared between the app and pages router. You can use the `<PagesOnly>Content</PagesOnly>` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}
By default Next.js will add the `x-powered-by` header. To opt-out of it, open `next.config.js` and disable the `poweredByHeader` config:
```js filename="next.config.js"
module.exports = {
poweredByHeader: false,
}
```
@@ -0,0 +1,21 @@
---
title: productionBrowserSourceMaps
description: Enables browser source map generation during the production build.
---
{/* The content of this doc is shared between the app and pages router. You can use the `<PagesOnly>Content</PagesOnly>` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}
Source Maps are enabled by default during development. During production builds, they are disabled to prevent you leaking your source on the client, unless you specifically opt-in with the configuration flag.
Next.js provides a configuration flag you can use to enable browser source map generation during the production build:
```js filename="next.config.js"
module.exports = {
productionBrowserSourceMaps: true,
}
```
When the `productionBrowserSourceMaps` option is enabled, the source maps will be output in the same directory as the JavaScript files. Next.js will automatically serve these files when requested.
- Adding source maps can increase `next build` time
- Increases memory usage during `next build`
@@ -0,0 +1,118 @@
---
title: proxyClientMaxBodySize
description: Configure the maximum request body size when using proxy.
version: experimental
---
When proxy is used, Next.js automatically clones the request body and buffers it in memory to enable multiple reads - both in proxy and the underlying route handler. To prevent excessive memory usage, this configuration option sets a size limit on the buffered body.
By default, the maximum body size is **10MB**. If a request body exceeds this limit, the body will only be buffered up to the limit, and a warning will be logged indicating which route exceeded the limit.
## Options
### String format (recommended)
Specify the size using a human-readable string format:
```ts filename="next.config.ts" switcher
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
experimental: {
proxyClientMaxBodySize: '1mb',
},
}
export default nextConfig
```
```js filename="next.config.js" switcher
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
proxyClientMaxBodySize: '1mb',
},
}
module.exports = nextConfig
```
Supported units: `b`, `kb`, `mb`, `gb`
### Number format
Alternatively, specify the size in bytes as a number:
```ts filename="next.config.ts" switcher
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
experimental: {
proxyClientMaxBodySize: 1048576, // 1MB in bytes
},
}
export default nextConfig
```
```js filename="next.config.js" switcher
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
proxyClientMaxBodySize: 1048576, // 1MB in bytes
},
}
module.exports = nextConfig
```
## Behavior
When a request body exceeds the configured limit:
1. Next.js will buffer only the first N bytes (up to the limit)
2. A warning will be logged to the console indicating the route that exceeded the limit
3. The request will continue processing normally, but only the partial body will be available
4. The request will **not** fail or return an error to the client
If your application needs to process the full request body, you should either:
- Increase the `proxyClientMaxBodySize` limit
- Handle the partial body gracefully in your application logic
## Example
```ts filename="proxy.ts"
import { NextRequest, NextResponse } from 'next/server'
export async function proxy(request: NextRequest) {
// Next.js automatically buffers the body with the configured size limit
// You can read the body in proxy...
const body = await request.text()
// If the body exceeded the limit, only partial data will be available
console.log('Body size:', body.length)
return NextResponse.next()
}
```
```ts filename="app/api/upload/route.ts"
import { NextRequest, NextResponse } from 'next/server'
export async function POST(request: NextRequest) {
// ...and the body is still available in your route handler
const body = await request.text()
console.log('Body in route handler:', body.length)
return NextResponse.json({ received: body.length })
}
```
## Good to know
- This setting only applies when proxy is used in your application
- The default limit of 10MB is designed to balance memory usage and typical use cases
- The limit applies per-request, not globally across all concurrent requests
- For applications handling large file uploads, consider increasing the limit accordingly
@@ -0,0 +1,98 @@
---
title: reactCompiler
description: Enable the React Compiler to automatically optimize component rendering.
---
Next.js includes support for the [React Compiler](https://react.dev/learn/react-compiler/introduction), a tool designed to improve performance by automatically optimizing component rendering. This reduces the need for manual memoization using `useMemo` and `useCallback`.
Next.js includes a custom performance optimization written in SWC that makes the React Compiler more efficient. Instead of running the compiler on every file, Next.js analyzes your project and only applies the React Compiler to relevant files. This avoids unnecessary work and leads to faster builds compared to using the Babel plugin on its own.
## How It Works
The React Compiler runs through a Babel plugin. To keep builds fast, Next.js uses a custom SWC optimization that only applies the React Compiler to relevant files—like those with JSX or React Hooks.
This avoids compiling everything and keeps the performance cost minimal. You may still see slightly slower builds compared to the default Rust-based compiler, but the impact is small and localized.
To use it, install the `babel-plugin-react-compiler`:
```bash package="pnpm"
pnpm add -D babel-plugin-react-compiler
```
```bash package="npm"
npm install -D babel-plugin-react-compiler
```
```bash package="yarn"
yarn add -D babel-plugin-react-compiler
```
```bash package="bun"
bun add -D babel-plugin-react-compiler
```
Then, add `reactCompiler` option in `next.config.js`:
```ts filename="next.config.ts" switcher
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
reactCompiler: true,
}
export default nextConfig
```
```js filename="next.config.js" switcher
/** @type {import('next').NextConfig} */
const nextConfig = {
reactCompiler: true,
}
module.exports = nextConfig
```
## Annotations
You can configure the compiler to run in "opt-in" mode as follows:
```ts filename="next.config.ts" switcher
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
reactCompiler: {
compilationMode: 'annotation',
},
}
export default nextConfig
```
```js filename="next.config.js" switcher
/** @type {import('next').NextConfig} */
const nextConfig = {
reactCompiler: {
compilationMode: 'annotation',
},
}
module.exports = nextConfig
```
Then, you can annotate specific components or hooks with the `"use memo"` directive from React to opt-in:
```ts filename="app/page.tsx" switcher
export default function Page() {
'use memo'
// ...
}
```
```js filename="app/page.js" switcher
export default function Page() {
'use memo'
// ...
}
```
> **Note:** You can also use the `"use no memo"` directive from React for the opposite effect, to opt-out a component or hook.
@@ -0,0 +1,16 @@
---
title: reactMaxHeadersLength
description: The maximum length of the headers that are emitted by React and added to the response.
---
During prerendering, React can emit headers that can be added to the response. These can be used to improve performance by allowing the browser to preload resources like fonts, scripts, and stylesheets. The default value is `6000`, but you can override this value by configuring the `reactMaxHeadersLength` option in `next.config.js`:
```js filename="next.config.js"
module.exports = {
reactMaxHeadersLength: 1000,
}
```
> **Good to know**: This option is only available in App Router.
Depending on the type of proxy between the browser and the server, the headers can be truncated. For example, if you are using a reverse proxy that doesn't support long headers, you should set a lower value to ensure that the headers are not truncated.
@@ -0,0 +1,22 @@
---
title: reactStrictMode
description: The complete Next.js runtime is now Strict Mode-compliant, learn how to opt-in
---
{/* The content of this doc is shared between the app and pages router. You can use the `<PagesOnly>Content</PagesOnly>` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}
> **Good to know**: Since Next.js 13.5.1, Strict Mode is `true` by default with `app` router, so the above configuration is only necessary for `pages`. You can still disable Strict Mode by setting `reactStrictMode: false`.
> **Suggested**: We strongly suggest you enable Strict Mode in your Next.js application to better prepare your application for the future of React.
React's [Strict Mode](https://react.dev/reference/react/StrictMode) is a development mode only feature for highlighting potential problems in an application. It helps to identify unsafe lifecycles, legacy API usage, and a number of other features.
The Next.js runtime is Strict Mode-compliant. To opt-in to Strict Mode, configure the following option in your `next.config.js`:
```js filename="next.config.js"
module.exports = {
reactStrictMode: true,
}
```
If you or your team are not ready to use Strict Mode in your entire application, that's OK! You can incrementally migrate on a page-by-page basis using `<React.StrictMode>`.
@@ -0,0 +1,364 @@
---
title: redirects
description: Add redirects to your Next.js app.
---
{/* The content of this doc is shared between the app and pages router. You can use the `<PagesOnly>Content</PagesOnly>` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}
Redirects allow you to redirect an incoming request path to a different destination path.
To use redirects you can use the `redirects` key in `next.config.js`:
```js filename="next.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` `true` or `false` - if `true` will use the 308 status code which instructs clients/search engines to cache the redirect forever, if `false` will use the 307 status code which is temporary and is not cached.
> **Why does Next.js use 307 and 308?** Traditionally a 302 was used for a temporary redirect, and a 301 for a permanent redirect, but many browsers changed the request method of the redirect to `GET`, regardless of the original method. For example, if the browser made a request to `POST /v1/users` which returned status code `302` with location `/v2/users`, the subsequent request might be `GET /v2/users` instead of the expected `POST /v2/users`. Next.js uses the 307 temporary redirect, and 308 permanent redirect status codes to explicitly preserve the request method used.
- `basePath`: `false` or `undefined` - if false the `basePath` won't be included when matching, can be used for external redirects only.
- `locale`: `false` or `undefined` - whether the locale should not be included when matching.
- `has` is an array of [has objects](#header-cookie-and-query-matching) with the `type`, `key` and `value` properties.
- `missing` is an array of [missing objects](#header-cookie-and-query-matching) with the `type`, `key` and `value` properties.
Redirects are checked before the filesystem which includes pages and `/public` files.
When using the Pages Router, redirects are not applied to client-side routing (`Link`, `router.push`) unless [Proxy](/docs/app/api-reference/file-conventions/proxy) is present and matches the path.
When a redirect is applied, any query values provided in the request will be passed through to the redirect destination. For example, see the following redirect configuration:
```js
{
source: '/old-blog/:path*',
destination: '/blog/:path*',
permanent: false
}
```
> **Good to know**: Remember to include the forward slash `/` before the colon `:` in path parameters of the `source` and `destination` paths, otherwise the path will be treated as a literal string and you run the risk of causing infinite redirects.
When `/old-blog/post-1?hello=world` is requested, the client will be redirected to `/blog/post-1?hello=world`.
## Path Matching
Path matches are allowed, for example `/old-blog/:slug` will match `/old-blog/first-post` (no nested paths):
```js filename="next.config.js"
module.exports = {
async redirects() {
return [
{
source: '/old-blog/:slug',
destination: '/news/:slug', // Matched parameters can be used in the destination
permanent: true,
},
]
},
}
```
The pattern `/old-blog/:slug` matches `/old-blog/first-post` and `/old-blog/post-1` but not `/old-blog/a/b` (no nested paths). Patterns are anchored to the start: `/old-blog/:slug` will not match `/archive/old-blog/first-post`.
You can use modifiers on parameters: `*` (zero or more), `+` (one or more), `?` (zero or one). For example, `/blog/:slug*` matches `/blog`, `/blog/a`, and `/blog/a/b/c`.
Read more details on [path-to-regexp](https://github.com/pillarjs/path-to-regexp) documentation.
### 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`:
```js filename="next.config.js"
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 parentheses after a parameter, for example `/post/:slug(\\d{1,})` will match `/post/123` but not `/post/abc`:
```js filename="next.config.js"
module.exports = {
async redirects() {
return [
{
source: '/post/:slug(\\d{1,})',
destination: '/news/:slug', // Matched parameters can be used in the destination
permanent: false,
},
]
},
}
```
The following characters `(`, `)`, `{`, `}`, `:`, `*`, `+`, `?` are used for regex path matching, so when used in the `source` as non-special values they must be escaped by adding `\\` before them:
```js filename="next.config.js"
module.exports = {
async redirects() {
return [
{
// this will match `/english(default)/something` being requested
source: '/english\\(default\\)/:slug',
destination: '/en-us/:slug',
permanent: false,
},
]
},
}
```
## Header, Cookie, and Query Matching
To only match a redirect when header, cookie, or query values also match the `has` field or don't match the `missing` field can be used. Both the `source` and all `has` items must match and all `missing` items must not match for the redirect to be applied.
`has` and `missing` items can have the following fields:
- `type`: `String` - must be either `header`, `cookie`, `host`, or `query`.
- `key`: `String` - the key from the selected type to match against.
- `value`: `String` or `undefined` - the value to check for, if undefined any value will match. A regex like string can be used to capture a specific part of the value, e.g. if the value `first-(?<paramName>.*)` is used for `first-second` then `second` will be usable in the destination with `:paramName`.
```js filename="next.config.js"
module.exports = {
async redirects() {
return [
// if the header `x-redirect-me` is present,
// this redirect will be applied
{
source: '/:path((?!another-page$).*)',
has: [
{
type: 'header',
key: 'x-redirect-me',
},
],
permanent: false,
destination: '/another-page',
},
// if the header `x-do-not-redirect` is present,
// this redirect will NOT be applied
{
source: '/:path((?!another-page$).*)',
missing: [
{
type: 'header',
key: 'x-do-not-redirect',
},
],
permanent: false,
destination: '/another-page',
},
// if the source, query, and cookie are matched,
// this redirect will be applied
{
source: '/specific/:path*',
has: [
{
type: 'query',
key: 'page',
// the page value will not be available in the
// destination since value is provided and doesn't
// use a named capture group e.g. (?<page>home)
value: 'home',
},
{
type: 'cookie',
key: 'authorized',
value: 'true',
},
],
permanent: false,
destination: '/another/:path*',
},
// if the header `x-authorized` is present and
// contains a matching value, this redirect will be applied
{
source: '/',
has: [
{
type: 'header',
key: 'x-authorized',
value: '(?<authorized>yes|true)',
},
],
permanent: false,
destination: '/home?authorized=:authorized',
},
// if the host is `example.com`,
// this redirect will be applied
{
source: '/:path((?!another-page$).*)',
has: [
{
type: 'host',
value: 'example.com',
},
],
permanent: false,
destination: '/another-page',
},
]
},
}
```
### Redirects with basePath support
When leveraging [`basePath` support](/docs/app/api-reference/config/next-config-js/basePath) with redirects each `source` and `destination` is automatically prefixed with the `basePath` unless you add `basePath: false` to the redirect:
```js filename="next.config.js"
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: 'https://example.com',
basePath: false,
permanent: false,
},
]
},
}
```
### Redirects with i18n support
<AppOnly>
When implementing redirects with internationalization in the App Router, you can include locales in `next.config.js` redirects, but only as hardcoded paths.
For dynamic or per-request locale handling, use [dynamic route segments and proxy](/docs/app/guides/internationalization), which can redirect based on the user's preferred language.
```js filename="next.config.js"
module.exports = {
async redirects() {
return [
{
// Manually handle locale prefixes for App Router
source: '/en/old-path',
destination: '/en/new-path',
permanent: false,
},
{
// Redirect for all locales using a parameter
source: '/:locale/old-path',
destination: '/:locale/new-path',
permanent: false,
},
{
// Redirect from one locale to another
source: '/de/old-path',
destination: '/en/new-path',
permanent: false,
},
{
// Catch-all redirect for multiple locales
source: '/:locale(en|fr|de)/:path*',
destination: '/:locale/new-section/:path*',
permanent: false,
},
]
},
}
```
</AppOnly>
<PagesOnly>
When leveraging [`i18n` support](/docs/pages/guides/internationalization) 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.
```js filename="next.config.js"
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,
},
// it's possible to match all locales even when locale: false is set
{
source: '/:locale/page',
destination: '/en/newpage',
permanent: false,
locale: false,
},
{
// this gets converted to /(en|fr|de)/(.*) so will not match the top-level
// `/` or `/fr` routes like /:path* would
source: '/(.*)',
destination: '/another',
permanent: false,
},
]
},
}
```
</PagesOnly>
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. To ensure IE11 compatibility, a `Refresh` header is automatically added for the 308 status code.
## Other Redirects
- Inside [API Routes](/docs/pages/building-your-application/routing/api-routes) and [Route Handlers](/docs/app/api-reference/file-conventions/route), you can redirect based on the incoming request.
- Inside [`getStaticProps`](/docs/pages/building-your-application/data-fetching/get-static-props) and [`getServerSideProps`](/docs/pages/building-your-application/data-fetching/get-server-side-props), you can redirect specific pages at request-time.
## Version History
| Version | Changes |
| --------- | ------------------ |
| `v13.3.0` | `missing` added. |
| `v10.2.0` | `has` added. |
| `v9.5.0` | `redirects` added. |
@@ -0,0 +1,477 @@
---
title: rewrites
description: Add rewrites to your Next.js app.
---
{/* The content of this doc is shared between the app and pages router. You can use the `<PagesOnly>Content</PagesOnly>` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}
Rewrites allow you to map an incoming request path to a different destination path.
<AppOnly>
Rewrites act as a URL proxy and mask the destination path, making it appear the user hasn't changed their location on the site. In contrast, [redirects](/docs/app/api-reference/config/next-config-js/redirects) will reroute to a new page and show the URL changes.
</AppOnly>
<PagesOnly>
Rewrites act as a URL proxy and mask the destination path, making it appear the user hasn't changed their location on the site. In contrast, [redirects](/docs/pages/api-reference/config/next-config-js/redirects) will reroute to a new page and show the URL changes.
</PagesOnly>
To use rewrites you can use the `rewrites` key in `next.config.js`:
```js filename="next.config.js"
module.exports = {
async rewrites() {
return [
{
source: '/about',
destination: '/',
},
]
},
}
```
Rewrites are applied to client-side routing. In the example above, navigating to `<Link href="/about">` will serve content from `/` while keeping the URL as `/about`.
`rewrites` is an async function that expects to return either an array or an object of arrays (see below) holding objects with `source` and `destination` properties:
- `source`: `String` - is the incoming request path pattern.
- `destination`: `String` is the path you want to route to.
- `basePath`: `false` or `undefined` - if false the basePath won't be included when matching, can be used for external rewrites only.
- `locale`: `false` or `undefined` - whether the locale should not be included when matching.
- `has` is an array of [has objects](#header-cookie-and-query-matching) with the `type`, `key` and `value` properties.
- `missing` is an array of [missing objects](#header-cookie-and-query-matching) with the `type`, `key` and `value` properties.
When the `rewrites` function returns an array, rewrites are applied after checking the filesystem (pages and `/public` files) and before dynamic routes. When the `rewrites` function returns an object of arrays with a specific shape, this behavior can be changed and more finely controlled, as of `v10.1` of Next.js:
```js filename="next.config.js"
module.exports = {
async rewrites() {
return {
beforeFiles: [
// These rewrites are checked after headers/redirects
// and before all files including _next/public files which
// allows overriding page files
{
source: '/some-page',
destination: '/somewhere-else',
has: [{ type: 'query', key: 'overrideMe' }],
},
],
afterFiles: [
// These rewrites are checked after pages/public files
// are checked but before dynamic routes
{
source: '/non-existent',
destination: '/somewhere-else',
},
],
fallback: [
// These rewrites are checked after both pages/public files
// and dynamic routes are checked
{
source: '/:path*',
destination: `https://my-old-site.com/:path*`,
},
],
}
},
}
```
> **Good to know**: rewrites in `beforeFiles` do not check the filesystem/dynamic routes immediately after matching a source, they continue until all `beforeFiles` have been checked.
The order Next.js routes are checked is:
<AppOnly>
1. [headers](/docs/app/api-reference/config/next-config-js/headers) are checked/applied
2. [redirects](/docs/app/api-reference/config/next-config-js/redirects) are checked/applied
3. [proxy](/docs/app/api-reference/file-conventions/proxy)
4. `beforeFiles` rewrites are checked/applied
5. static files from the [public directory](/docs/app/api-reference/file-conventions/public-folder), `_next/static` files, and non-dynamic pages are checked/served
6. `afterFiles` rewrites are checked/applied, if one of these rewrites is matched we check dynamic routes/static files after each match
7. `fallback` rewrites are checked/applied, these are applied before rendering the 404 page and after dynamic routes/all static assets have been checked. If you use [fallback: true/'blocking'](/docs/pages/api-reference/functions/get-static-paths#fallback-true) in `getStaticPaths`, the fallback `rewrites` defined in your `next.config.js` will _not_ be run.
</AppOnly>
<PagesOnly>
1. [headers](/docs/pages/api-reference/config/next-config-js/headers) are checked/applied
2. [redirects](/docs/pages/api-reference/config/next-config-js/redirects) are checked/applied
3. `beforeFiles` rewrites are checked/applied
4. static files from the [public directory](/docs/pages/api-reference/file-conventions/public-folder), `_next/static` files, and non-dynamic pages are checked/served
5. `afterFiles` rewrites are checked/applied, if one of these rewrites is matched we check dynamic routes/static files after each match
6. `fallback` rewrites are checked/applied, these are applied before rendering the 404 page and after dynamic routes/all static assets have been checked. If you use [fallback: true/'blocking'](/docs/pages/api-reference/functions/get-static-paths#fallback-true) in `getStaticPaths`, the fallback `rewrites` defined in your `next.config.js` will _not_ be run.
</PagesOnly>
## 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`.
```js filename="next.config.js"
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.
```js filename="next.config.js"
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`.
```js filename="next.config.js"
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
},
]
},
}
```
> **Good to know**: Static pages from [Automatic Static Optimization](/docs/pages/building-your-application/rendering/automatic-static-optimization) or [prerendering](/docs/pages/building-your-application/data-fetching/get-static-props) params from rewrites will be parsed on the client after hydration and provided in the query.
## Path Matching
Path matches are allowed, for example `/blog/:slug` will match `/blog/first-post` (no nested paths):
```js filename="next.config.js"
module.exports = {
async rewrites() {
return [
{
source: '/blog/:slug',
destination: '/news/:slug', // Matched parameters can be used in the destination
},
]
},
}
```
The pattern `/blog/:slug` matches `/blog/first-post` and `/blog/post-1` but not `/blog/a/b` (no nested paths). Patterns are anchored to the start: `/blog/:slug` will not match `/archive/blog/first-post`.
You can use modifiers on parameters: `*` (zero or more), `+` (one or more), `?` (zero or one). For example, `/blog/:slug*` matches `/blog`, `/blog/a`, and `/blog/a/b/c`.
Read more details on [path-to-regexp](https://github.com/pillarjs/path-to-regexp) documentation.
### 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`:
```js filename="next.config.js"
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`:
```js filename="next.config.js"
module.exports = {
async rewrites() {
return [
{
source: '/old-blog/:post(\\d{1,})',
destination: '/blog/:post', // Matched parameters can be used in the destination
},
]
},
}
```
The following characters `(`, `)`, `{`, `}`, `[`, `]`, `|`, `\`, `^`, `.`, `:`, `*`, `+`, `-`, `?`, `$` are used for regex path matching, so when used in the `source` as non-special values they must be escaped by adding `\\` before them:
```js filename="next.config.js"
module.exports = {
async rewrites() {
return [
{
// this will match `/english(default)/something` being requested
source: '/english\\(default\\)/:slug',
destination: '/en-us/:slug',
},
]
},
}
```
## Header, Cookie, and Query Matching
To only match a rewrite when header, cookie, or query values also match the `has` field or don't match the `missing` field can be used. Both the `source` and all `has` items must match and all `missing` items must not match for the rewrite to be applied.
`has` and `missing` items can have the following fields:
- `type`: `String` - must be either `header`, `cookie`, `host`, or `query`.
- `key`: `String` - the key from the selected type to match against.
- `value`: `String` or `undefined` - the value to check for, if undefined any value will match. A regex like string can be used to capture a specific part of the value, e.g. if the value `first-(?<paramName>.*)` is used for `first-second` then `second` will be usable in the destination with `:paramName`.
```js filename="next.config.js"
module.exports = {
async rewrites() {
return [
// if the header `x-rewrite-me` is present,
// this rewrite will be applied
{
source: '/:path*',
has: [
{
type: 'header',
key: 'x-rewrite-me',
},
],
destination: '/another-page',
},
// if the header `x-rewrite-me` is not present,
// this rewrite will be applied
{
source: '/:path*',
missing: [
{
type: 'header',
key: 'x-rewrite-me',
},
],
destination: '/another-page',
},
// if the source, query, and cookie are matched,
// this rewrite will be applied
{
source: '/specific/:path*',
has: [
{
type: 'query',
key: 'page',
// the page value will not be available in the
// destination since value is provided and doesn't
// use a named capture group e.g. (?<page>home)
value: 'home',
},
{
type: 'cookie',
key: 'authorized',
value: 'true',
},
],
destination: '/:path*/home',
},
// if the header `x-authorized` is present and
// contains a matching value, this rewrite will be applied
{
source: '/:path*',
has: [
{
type: 'header',
key: 'x-authorized',
value: '(?<authorized>yes|true)',
},
],
destination: '/home?authorized=:authorized',
},
// if the host is `example.com`,
// this rewrite will be applied
{
source: '/:path*',
has: [
{
type: 'host',
value: 'example.com',
},
],
destination: '/another-page',
},
]
},
}
```
## Rewriting to an external URL
<details>
<summary>Examples</summary>
- [Using Multiple Zones](https://github.com/vercel/next.js/tree/canary/examples/with-zones)
</details>
Rewrites allow you to rewrite to an external URL. This is especially useful for incrementally adopting Next.js. The following is an example rewrite for redirecting the `/blog` route of your main app to an external site.
```js filename="next.config.js"
module.exports = {
async rewrites() {
return [
{
source: '/blog',
destination: 'https://example.com/blog',
},
{
source: '/blog/:slug',
destination: 'https://example.com/blog/:slug', // Matched parameters can be used in the destination
},
]
},
}
```
If you're using `trailingSlash: true`, you also need to insert a trailing slash in the `source` parameter. If the destination server is also expecting a trailing slash it should be included in the `destination` parameter as well.
```js filename="next.config.js"
module.exports = {
trailingSlash: true,
async rewrites() {
return [
{
source: '/blog/',
destination: 'https://example.com/blog/',
},
{
source: '/blog/:path*/',
destination: 'https://example.com/blog/:path*/',
},
]
},
}
```
### Incremental adoption of Next.js
You can also have Next.js fall back to proxying to an existing website after checking all Next.js routes.
This way you don't have to change the rewrites configuration when migrating more pages to Next.js
```js filename="next.config.js"
module.exports = {
async rewrites() {
return {
fallback: [
{
source: '/:path*',
destination: `https://custom-routes-proxying-endpoint.vercel.app/:path*`,
},
],
}
},
}
```
### Rewrites with basePath support
When leveraging [`basePath` support](/docs/app/api-reference/config/next-config-js/basePath) with rewrites each `source` and `destination` is automatically prefixed with the `basePath` unless you add `basePath: false` to the rewrite:
```js filename="next.config.js"
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 cannot be used for internal rewrites e.g. `destination: '/another'`
source: '/without-basePath',
destination: 'https://example.com',
basePath: false,
},
]
},
}
```
<PagesOnly>
### Rewrites with i18n support
When leveraging [`i18n` support](/docs/pages/guides/internationalization) 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.
```js filename="next.config.js"
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,
},
{
// it's possible to match all locales even when locale: false is set
source: '/:locale/api-alias/:path*',
destination: '/api/:path*',
locale: false,
},
{
// this gets converted to /(en|fr|de)/(.*) so will not match the top-level
// `/` or `/fr` routes like /:path* would
source: '/(.*)',
destination: '/another',
},
]
},
}
```
</PagesOnly>
## Version History
| Version | Changes |
| --------- | ---------------- |
| `v13.3.0` | `missing` added. |
| `v10.2.0` | `has` added. |
| `v9.5.0` | Headers added. |
@@ -0,0 +1,49 @@
---
title: sassOptions
description: Configure Sass options.
---
`sassOptions` allow you to configure the Sass compiler.
```ts filename="next.config.ts" switcher
import type { NextConfig } from 'next'
const sassOptions = {
additionalData: `
$var: red;
`,
}
const nextConfig: NextConfig = {
sassOptions: {
...sassOptions,
implementation: 'sass-embedded',
},
}
export default nextConfig
```
```js filename="next.config.js" switcher
/** @type {import('next').NextConfig} */
const sassOptions = {
additionalData: `
$var: red;
`,
}
const nextConfig = {
sassOptions: {
...sassOptions,
implementation: 'sass-embedded',
},
}
module.exports = nextConfig
```
> **Good to know:**
>
> - `sassOptions` are not typed outside of `implementation` because Next.js does not maintain the other possible properties.
> - The `functions` property for defining custom Sass functions is only supported with webpack. When using Turbopack, custom Sass functions are not available because Turbopack's Rust-based architecture cannot directly execute JavaScript functions passed through this option.
@@ -0,0 +1,55 @@
---
title: serverActions
description: Configure Server Actions behavior in your Next.js application.
---
Options for configuring Server Actions behavior in your Next.js application.
## `allowedOrigins`
A list of extra safe origin domains from which Server Actions can be invoked. Next.js compares the origin of a Server Action request with the host domain, ensuring they match to prevent CSRF attacks. If not provided, only the same origin is allowed.
```js filename="next.config.js"
/** @type {import('next').NextConfig} */
module.exports = {
experimental: {
serverActions: {
allowedOrigins: ['my-proxy.com', '*.my-proxy.com'],
},
},
}
```
## `bodySizeLimit`
By default, the maximum size of the request body sent to a Server Action is 1MB, to prevent the consumption of excessive server resources in parsing large amounts of data, as well as potential DDoS attacks.
However, you can configure this limit using the `serverActions.bodySizeLimit` option. It can take the number of bytes or any string format supported by bytes, for example `1000`, `'500kb'` or `'3mb'`.
```js filename="next.config.js"
/** @type {import('next').NextConfig} */
module.exports = {
experimental: {
serverActions: {
bodySizeLimit: '2mb',
},
},
}
```
## Enabling Server Actions (v13)
Server Actions became a stable feature in Next.js 14, and are enabled by default. However, if you are using an earlier version of Next.js, you can enable them by setting `experimental.serverActions` to `true`.
```js filename="next.config.js"
/** @type {import('next').NextConfig} */
const config = {
experimental: {
serverActions: true,
},
}
module.exports = config
```
@@ -0,0 +1,36 @@
---
title: serverComponentsHmrCache
description: Configure whether fetch responses in Server Components are cached across HMR refresh requests.
version: experimental
---
The experimental `serverComponentsHmrCache` option allows you to cache `fetch` responses in Server Components across Hot Module Replacement (HMR) refreshes in local development. This results in faster responses and reduced costs for billed API calls.
By default, the HMR cache applies to all `fetch` requests, including those with the `cache: 'no-store'` option. This means uncached requests will not show fresh data between HMR refreshes. However, the cache will be cleared on navigation or full-page reloads.
You can disable the HMR cache by setting `serverComponentsHmrCache` to `false` in your `next.config.js` file:
```ts filename="next.config.ts" switcher
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
experimental: {
serverComponentsHmrCache: false, // defaults to true
},
}
export default nextConfig
```
```js filename="next.config.js" switcher
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
serverComponentsHmrCache: false, // defaults to true
},
}
module.exports = nextConfig
```
> **Good to know:** For better observability, we recommend using the [`logging.fetches`](/docs/app/api-reference/config/next-config-js/logging) option which logs fetch cache hits and misses in the console during development.
@@ -0,0 +1,103 @@
---
title: serverExternalPackages
description: Opt-out specific dependencies from the Server Components bundling and use native Node.js `require`.
---
Dependencies used inside [Server Components](/docs/app/getting-started/server-and-client-components) and [Route Handlers](/docs/app/api-reference/file-conventions/route) will automatically be bundled by Next.js.
If a dependency is using Node.js specific features, you can choose to opt-out specific dependencies from the Server Components bundling and use native Node.js `require`.
```js filename="next.config.js"
/** @type {import('next').NextConfig} */
const nextConfig = {
serverExternalPackages: ['@acme/ui'],
}
module.exports = nextConfig
```
Next.js includes a [short list of popular packages](https://github.com/vercel/next.js/blob/canary/packages/next/src/lib/server-external-packages.jsonc) that currently are working on compatibility and automatically opt-ed out:
- `@alinea/generated`
- `@appsignal/nodejs`
- `@aws-sdk/client-s3`
- `@aws-sdk/s3-presigned-post`
- `@blockfrost/blockfrost-js`
- `@highlight-run/node`
- `@huggingface/transformers`
- `@jpg-store/lucid-cardano`
- `@libsql/client`
- `@mikro-orm/core`
- `@mikro-orm/knex`
- `@node-rs/argon2`
- `@node-rs/bcrypt`
- `@prisma/client`
- `@react-pdf/renderer`
- `@sentry/profiling-node`
- `@sparticuz/chromium`
- `@sparticuz/chromium-min`
- `@statsig/statsig-node-core`
- `@swc/core`
- `@xenova/transformers`
- `@zenstackhq/runtime`
- `argon2`
- `autoprefixer`
- `aws-crt`
- `bcrypt`
- `better-sqlite3`
- `canvas`
- `chromadb-default-embed`
- `config`
- `cpu-features`
- `cypress`
- `dd-trace`
- `eslint`
- `express`
- `firebase-admin`
- `htmlrewriter`
- `import-in-the-middle`
- `isolated-vm`
- `jest`
- `jsdom`
- `keyv`
- `libsql`
- `mdx-bundler`
- `mongodb`
- `mongoose`
- `newrelic`
- `next-mdx-remote`
- `next-seo`
- `node-cron`
- `node-pty`
- `node-web-audio-api`
- `onnxruntime-node`
- `oslo`
- `pg`
- `pino`
- `pino-pretty`
- `pino-roll`
- `playwright`
- `playwright-core`
- `postcss`
- `prettier`
- `prisma`
- `puppeteer-core`
- `puppeteer`
- `ravendb`
- `require-in-the-middle`
- `rimraf`
- `sharp`
- `shiki`
- `sqlite3`
- `thread-stream`
- `ts-morph`
- `ts-node`
- `typescript`
- `vscode-oniguruma`
- `webpack`
- `websocket`
- `zeromq`
| Version | Changes |
| --------- | -------------------------------------------------------------------------------------------------------------- |
| `v15.0.0` | Moved from experimental to stable. Renamed from `serverComponentsExternalPackages` to `serverExternalPackages` |
@@ -0,0 +1,43 @@
---
title: staleTimes
description: Learn how to override the invalidation time of the client cache.
version: experimental
---
`staleTimes` is an experimental feature that enables caching of page segments in the [Client Cache](/docs/app/glossary#client-cache).
You can enable this experimental feature and provide custom revalidation times by setting the experimental `staleTimes` flag:
```js filename="next.config.js"
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
staleTimes: {
dynamic: 30,
static: 180,
},
},
}
module.exports = nextConfig
```
The `static` and `dynamic` properties correspond with the time period (in seconds) based on different types of [link prefetching](/docs/app/api-reference/components/link#prefetch).
- The `dynamic` property is used when the page is neither statically generated nor fully prefetched (e.g. with `prefetch={true}`).
- Default: 0 seconds (not cached)
- The `static` property is used for statically generated pages, or when the `prefetch` prop on `Link` is set to `true`, or when calling [`router.prefetch`](/docs/app/api-reference/functions/use-router).
- Default: 5 minutes
> **Good to know:**
>
> - [Loading boundaries](/docs/app/api-reference/file-conventions/loading) are considered reusable for the `static` period defined in this configuration.
> - This doesn't affect [partial rendering](/docs/app/getting-started/linking-and-navigating#client-side-transitions), **meaning shared layouts won't automatically be refetched on every navigation, only the page segment that changes.**
> - This doesn't change [back/forward caching](/docs/app/glossary#client-cache) behavior to prevent layout shift and to prevent losing the browser scroll position.
### Version History
| Version | Changes |
| --------- | ---------------------------------------------------------- |
| `v15.0.0` | The `dynamic` `staleTimes` default changed from 30s to 0s. |
| `v14.2.0` | Experimental `staleTimes` introduced. |
@@ -0,0 +1,41 @@
---
title: staticGeneration*
description: Learn how to configure static generation in your Next.js application.
version: experimental
---
The `staticGeneration*` options allow you to configure the Static Generation process for advanced use cases.
```ts filename="next.config.ts" switcher
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
experimental: {
staticGenerationRetryCount: 1,
staticGenerationMaxConcurrency: 8,
staticGenerationMinPagesPerWorker: 25,
},
}
export default nextConfig
```
```js filename="next.config.js" switcher
const nextConfig = {
experimental: {
staticGenerationRetryCount: 1,
staticGenerationMaxConcurrency: 8,
staticGenerationMinPagesPerWorker: 25,
},
}
export default nextConfig
```
## Config Options
The following options are available:
- `staticGenerationRetryCount`: The number of times to retry a failed page generation before failing the build.
- `staticGenerationMaxConcurrency`: The maximum number of pages to be processed per worker.
- `staticGenerationMinPagesPerWorker`: The minimum number of pages to be processed before starting a new worker.
@@ -0,0 +1,226 @@
---
title: taint
description: Enable tainting Objects and Values.
version: experimental
---
## Usage
The `taint` option enables support for experimental React APIs for tainting objects and values. This feature helps prevent sensitive data from being accidentally passed to the client. When enabled, you can use:
- [`experimental_taintObjectReference`](https://react.dev/reference/react/experimental_taintObjectReference) taint objects references.
- [`experimental_taintUniqueValue`](https://react.dev/reference/react/experimental_taintUniqueValue) to taint unique values.
> **Good to know**: Activating this flag also enables the React `experimental` channel for `app` directory.
```ts filename="next.config.ts" switcher
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
experimental: {
taint: true,
},
}
export default nextConfig
```
```js filename="next.config.js" switcher
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
taint: true,
},
}
module.exports = nextConfig
```
> **Warning:** Do not rely on the taint API as your only mechanism to prevent exposing sensitive data to the client. See our [security recommendations](/blog/security-nextjs-server-components-actions).
The taint APIs allows you to be defensive, by declaratively and explicitly marking data that is not allowed to pass through the Server-Client boundary. When an object or value, is passed through the Server-Client boundary, React throws an error.
This is helpful for cases where:
- The methods to read data are out of your control
- You have to work with sensitive data shapes not defined by you
- Sensitive data is accessed during Server Component rendering
It is recommended to model your data and APIs so that sensitive data is not returned to contexts where it is not needed.
## Caveats
- Tainting can only keep track of objects by reference. Copying an object creates an untainted version, which loses all guarantees given by the API. You'll need to taint the copy.
- Tainting cannot keep track of data derived from a tainted value. You also need to taint the derived value.
- Values are tainted for as long as their lifetime reference is within scope. See the [`experimental_taintUniqueValue` parameters reference](https://react.dev/reference/react/experimental_taintUniqueValue#parameters), for more information.
## Examples
### Tainting an object reference
In this case, the `getUserDetails` function returns data about a given user. We taint the user object reference, so that it cannot cross a Server-Client boundary. For example, assuming `UserCard` is a Client Component.
```ts switcher
import { experimental_taintObjectReference } from 'react'
function getUserDetails(id: string): UserDetails {
const user = await db.queryUserById(id)
experimental_taintObjectReference(
'Do not use the entire user info object. Instead, select only the fields you need.',
user
)
return user
}
```
```js switcher
import { experimental_taintObjectReference } from 'react'
function getUserDetails(id) {
const user = await db.queryUserById(id)
experimental_taintObjectReference(
'Do not use the entire user info object. Instead, select only the fields you need.',
user
)
return user
}
```
We can still access individual fields from the tainted `userDetails` object.
```tsx filename="app/contact/page.tsx switcher
export async function ContactPage({
params,
}: {
params: Promise<{ id: string }>
}) {
const { id } = await params
const userDetails = await getUserDetails(id)
return (
<UserCard
firstName={userDetails.firstName}
lastName={userDetails.lastName}
/>
)
}
```
```jsx filename="app/contact/page.js switcher
export async function ContactPage({ params }) {
const { id } = await params
const userDetails = await getUserDetails(id)
return (
<UserCard
firstName={userDetails.firstName}
lastName={userDetails.lastName}
/>
)
}
```
Now, passing the entire object to the Client Component will throw an error.
```tsx switcher
export async function ContactPage({
params,
}: {
params: Promise<{ id: string }>
}) {
const userDetails = await getUserDetails(id)
// Throws an error
return <UserCard user={userDetails} />
}
```
```jsx switcher
export async function ContactPage({ params }) {
const { id } = await params
const userDetails = await getUserDetails(id)
// Throws an error
return <UserCard user={userDetails} />
}
```
### Tainting a unique value
In this case, we can access the server configuration by awaiting calls to `config.getConfigDetails`. However, the system configuration contains the `SERVICE_API_KEY` that we don't want to expose to clients.
We can taint the `config.SERVICE_API_KEY` value.
```ts switcher
import { experimental_taintUniqueValue } from 'react'
function getSystemConfig(): SystemConfig {
const config = await config.getConfigDetails()
experimental_taintUniqueValue(
'Do not pass configuration tokens to the client',
config,
config.SERVICE_API_KEY
)
return config
}
```
```js switcher
import { experimental_taintUniqueValue } from 'react'
function getSystemConfig() {
const config = await config.getConfigDetails()
experimental_taintUniqueValue(
'Do not pass configuration tokens to the client',
config,
config.SERVICE_API_KEY
)
return config
}
```
We can still access other properties of the `systemConfig` object.
```tsx
export async function Dashboard() {
const systemConfig = await getSystemConfig()
return <ClientDashboard version={systemConfig.SERVICE_API_VERSION} />
}
```
However, passing `SERVICE_API_KEY` to `ClientDashboard` throws an error.
```tsx
export async function Dashboard() {
const systemConfig = await getSystemConfig()
// Someone makes a mistake in a PR
const version = systemConfig.SERVICE_API_KEY
return <ClientDashboard version={version} />
}
```
Note that, even though, `systemConfig.SERVICE_API_KEY` is reassigned to a new variable. Passing it to a Client Component still throws an error.
Whereas, a value derived from a tainted unique value, will be exposed to the client.
```tsx
export async function Dashboard() {
const systemConfig = await getSystemConfig()
// Someone makes a mistake in a PR
const version = `version::${systemConfig.SERVICE_API_KEY}`
return <ClientDashboard version={version} />
}
```
A better approach is to remove `SERVICE_API_KEY` from the data returned by `getSystemConfig`.
@@ -0,0 +1,33 @@
---
title: trailingSlash
description: Configure Next.js pages to resolve with or without a trailing slash.
---
{/* The content of this doc is shared between the app and pages router. You can use the `<PagesOnly>Content</PagesOnly>` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}
By default Next.js 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 `next.config.js` and add the `trailingSlash` config:
```js filename="next.config.js"
module.exports = {
trailingSlash: true,
}
```
With this option set, URLs like `/about` will redirect to `/about/`.
When using `trailingSlash: true`, certain URLs are exceptions and will not have a trailing slash appended:
- Static file URLs, such as files with extensions.
- Any paths under `.well-known/`.
For example, the following URLs will remain unchanged: `/file.txt`, `images/photos/picture.png`, and `.well-known/subfolder/config.json`.
When used with [`output: "export"`](/docs/app/guides/static-exports) configuration, the `/about` page will output `/about/index.html` (instead of the default `/about.html`).
## Version History
| Version | Changes |
| -------- | ---------------------- |
| `v9.5.0` | `trailingSlash` added. |
@@ -0,0 +1,23 @@
---
title: transpilePackages
description: Automatically transpile and bundle dependencies from local packages (like monorepos) or from external dependencies (`node_modules`).
---
{/* The content of this doc is shared between the app and pages router. You can use the `<PagesOnly>Content</PagesOnly>` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}
Next.js can automatically transpile and bundle dependencies from local packages (like monorepos) or from external dependencies (`node_modules`). This replaces the `next-transpile-modules` package.
```js filename="next.config.js"
/** @type {import('next').NextConfig} */
const nextConfig = {
transpilePackages: ['package-name'],
}
module.exports = nextConfig
```
## Version History
| Version | Changes |
| --------- | -------------------------- |
| `v13.0.0` | `transpilePackages` added. |
@@ -0,0 +1,398 @@
---
title: turbopack
description: Configure Next.js with Turbopack-specific options
---
{/* The content of this doc is shared between the app and pages router. You can use the `<PagesOnly>Content</PagesOnly>` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}
The `turbopack` option lets you customize [Turbopack](/docs/app/api-reference/turbopack) to transform different files and change how modules are resolved.
> **Good to know**: The `turbopack` option was previously named `experimental.turbo` in Next.js versions 13.0.0 to 15.2.x. The `experimental.turbo` option will be removed in Next.js 16.
>
> If you are using an older version of Next.js, run `npx @next/codemod@latest next-experimental-turbo-to-turbopack .` to automatically migrate your configuration.
```ts filename="next.config.ts" switcher
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
turbopack: {
// ...
},
}
export default nextConfig
```
```js filename="next.config.js" switcher
/** @type {import('next').NextConfig} */
const nextConfig = {
turbopack: {
// ...
},
}
module.exports = nextConfig
```
> **Good to know**:
>
> - Turbopack for Next.js does not require loaders or loader configuration for built-in functionality. Turbopack has built-in support for CSS and compiling modern JavaScript, so there's no need for `css-loader`, `postcss-loader`, or `babel-loader` if you're using `@babel/preset-env`.
## Reference
### Options
The following options are available for the `turbopack` configuration:
| Option | Description |
| ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `root` | Sets the application root directory. Should be an absolute path. |
| `rules` | List of supported webpack loaders to apply when running with Turbopack. |
| `resolveAlias` | Map aliased imports to modules to load in their place. |
| `resolveExtensions` | List of extensions to resolve when importing files. |
| `debugIds` | Enable generation of [debug IDs](https://github.com/tc39/ecma426/blob/main/proposals/debug-id.md) in JavaScript bundles and source maps. |
### Supported loaders
The following loaders have been tested to work with Turbopack's webpack loader implementation, but many other webpack loaders should work as well even if not listed here:
- [`babel-loader`](https://www.npmjs.com/package/babel-loader) [_(Configured automatically if a Babel configuration file is found)_](/docs/app/api-reference/turbopack#language-features)
- [`@svgr/webpack`](https://www.npmjs.com/package/@svgr/webpack)
- [`svg-inline-loader`](https://www.npmjs.com/package/svg-inline-loader)
- [`yaml-loader`](https://www.npmjs.com/package/yaml-loader)
- [`string-replace-loader`](https://www.npmjs.com/package/string-replace-loader)
- [`raw-loader`](https://www.npmjs.com/package/raw-loader)
- [`sass-loader`](https://www.npmjs.com/package/sass-loader) [_(Configured automatically)_](/docs/app/api-reference/turbopack#css-and-styling)
- [`graphql-tag/loader`](https://www.npmjs.com/package/graphql-tag)
#### Missing Webpack loader features
Turbopack uses the [`loader-runner`](https://github.com/webpack/loader-runner) library to execute webpack loaders, which provides most of the standard loader API. However, some features are not supported:
**Module loading:**
- [`importModule`](https://webpack.js.org/api/loaders/#thisimportmodule) - No support
- [`loadModule`](https://webpack.js.org/api/loaders/#thisloadmodule) - No support
**File system and output:**
- [`fs`](https://webpack.js.org/api/loaders/#thisfs) - Partial support: only `fs.readFile` is currently implemented.
- [`emitFile`](https://webpack.js.org/api/loaders/#thisemitfile) - No support
**Context properties:**
- [`version`](https://webpack.js.org/api/loaders/#thisversion) - No support
- [`mode`](https://webpack.js.org/api/loaders/#thismode) - No support
- [`target`](https://webpack.js.org/api/loaders/#thistarget) - No support
**Utilities:**
- [`utils`](https://webpack.js.org/api/loaders/#thisutils) - No support
- [`resolve`](https://webpack.js.org/api/loaders/#thisresolve) - No support (use [`getResolve`](https://webpack.js.org/api/loaders/#thisgetresolve) instead)
If you have a loader that is critically dependent upon one of these features please file an issue.
## Examples
### Root directory
Turbopack uses the root directory to resolve modules. Files outside of the project root are not resolved.
The reason files are not resolved outside of the project root is to improve cache validation, reduce filesystem watching overhead, and reduce the number of resolving steps needed.
Next.js automatically detects the root directory of your project. It does so by looking for one of these files:
- `pnpm-lock.yaml`
- `package-lock.json`
- `yarn.lock`
- `bun.lock`
- `bun.lockb`
If you have a different project structure, for example if you don't use workspaces, you can manually set the `root` option:
```js filename="next.config.js"
const path = require('path')
module.exports = {
turbopack: {
root: path.join(__dirname, '..'),
},
}
```
To resolve files from linked dependencies outside the project root (via `npm link`, `yarn link`, `pnpm link`, etc.), you must configure the `turbopack.root` to the parent directory of both the project and the linked dependencies.
While this expands the scope of filesystem watching, it's typically only necessary during development when actively working on linked packages.
### Configuring webpack loaders
If you need loader support beyond what's built in, many webpack loaders already work with Turbopack. There are currently some limitations:
- Only a core subset of the webpack loader API is implemented. Currently, there is enough coverage for some popular loaders, and we'll expand our API support in the future.
- Only loaders that return JavaScript code are supported. Loaders that transform files like stylesheets or images are not currently supported.
- Options passed to webpack loaders must be plain JavaScript primitives, objects, and arrays. For example, it's not possible to pass `require()` plugin modules as option values.
To configure loaders, add the names of the loaders you've installed and any options in `next.config.js`, mapping file extensions to a list of loaders. Rules are evaluated in order.
Here is an example below using the [`@svgr/webpack`](https://www.npmjs.com/package/@svgr/webpack) loader, which enables importing `.svg` files and rendering them as React components.
```js filename="next.config.js"
module.exports = {
turbopack: {
rules: {
'*.svg': {
loaders: ['@svgr/webpack'],
as: '*.js',
},
},
},
}
```
> **Good to know**: Globs used in the `rules` object match based on file name, unless the glob contains a `/` character, which will cause it to match based on the full project-relative file path. Windows file paths are normalized to use unix-style `/` path separators.
>
> Turbopack uses a modified version of the [Rust `globset` library](https://docs.rs/globset/latest/globset/).
For loaders that require configuration options, you can use an object format instead of a string:
```js filename="next.config.js"
module.exports = {
turbopack: {
rules: {
'*.svg': {
loaders: [
{
loader: '@svgr/webpack',
options: {
icon: true,
},
},
],
as: '*.js',
},
},
},
}
```
> **Good to know**: Prior to Next.js version 13.4.4, `turbopack.rules` was named `turbo.loaders` and only accepted file extensions like `.mdx` instead of `*.mdx`.
### Advanced webpack loader conditions
You can further restrict where a loader runs using the advanced `condition` syntax:
```js filename="next.config.js"
module.exports = {
turbopack: {
rules: {
// '*' will match all file paths, but we restrict where our
// rule runs with a condition.
'*': {
condition: {
all: [
// 'foreign' is a built-in condition.
{ not: 'foreign' },
// 'path' can be a RegExp or a glob string. A RegExp matches
// anywhere in the full project-relative file path.
{ path: /^img\/[0-9]{3}\// },
{
any: [
{ path: '*.svg' },
// 'query' matches anywhere in the full query string,
// which can be empty, or start with `?`.
{ query: /[?&]svgr(?=&|$)/ },
// 'content' is always a RegExp, and can match
// anywhere in the file.
{ content: /\<svg\W/ },
],
},
],
},
loaders: ['@svgr/webpack'],
as: '*.js',
},
},
},
}
```
- Supported boolean operators are `{all: [...]}`, `{any: [...]}` and `{not: ...}`.
- Supported customizable operators are `{path: string | RegExp}`, `{content: RegExp}`, `{query: string | RegExp}`, and `{contentType: string | RegExp}`. If multiple operators are specified in the same object, it acts as an implicit `and`.
- `path` matches against the project-relative file path. A string is treated as a glob pattern, while a RegExp can be used to match the path partially.
- `content` matches anywhere in the file content.
- `query` matches the import's query string (e.g., `?foo` in `import './file?foo'`). A string must match exactly, while a RegExp can be used to match the query string partially.
- `contentType` matches the MIME content type of the resource (e.g., from data URLs like `data:text/plain,...`). A string is treated as a glob pattern (e.g., `text/*`, `image/*`), while a RegExp can be used to match the content type partially.
In addition, a number of built-in conditions are supported:
- `browser`: Matches code that will execute on the client. Server code can be matched using `{not: 'browser'}`.
- `foreign`: Matches code in `node_modules`, as well as some Next.js internals. Usually you'll want to restrict loaders to `{not: 'foreign'}`. This can improve performance by reducing the number of files the loader is invoked on.
- `development`: Matches when using `next dev`.
- `production`: Matches when using `next build`.
- `node`: Matches code that will run on the default Node.js runtime.
- `edge-light`: Matches code that will run on the [Edge runtime](/docs/app/api-reference/edge).
Rules can be an object or an array of objects. An array is often useful for modeling disjoint conditions:
```js filename="next.config.js"
module.exports = {
turbopack: {
rules: {
'*.svg': [
{
condition: 'browser',
loaders: ['@svgr/webpack'],
as: '*.js',
},
{
condition: { not: 'browser' },
loaders: [require.resolve('./custom-svg-loader.js')],
as: '*.js',
},
],
},
},
}
```
> **Good to know**: All matching rules are executed in order.
### Module types
You can set the module type directly without using a loader. This is useful for changing how files are processed, similar to webpack's [`type`](https://webpack.js.org/configuration/module/#ruletype) option.
```js filename="next.config.js"
module.exports = {
turbopack: {
rules: {
'*.svg': {
type: 'asset',
},
},
},
}
```
When using `type: 'asset'`, importing the file returns its URL:
```tsx filename="app/page.tsx"
import svgUrl from './icon.svg'
export default function Page() {
return <img src={svgUrl} alt="Icon" />
}
```
The `type` option can be combined with `loaders` - loaders run first, then the result is processed according to the specified type.
Available module types:
| Type | Description |
| ------------ | -------------------------------------------------------- |
| `asset` | Emit file and return URL (like webpack `asset/resource`) |
| `ecmascript` | Process as JavaScript |
| `typescript` | Process as TypeScript |
| `css` | Process as CSS |
| `css-module` | Process as CSS module |
| `wasm` | Process as WebAssembly |
| `raw` | Return raw contents as string |
| `bytes` | Inline contents as bytes |
### Inline loader configuration with import attributes
You can apply a Turbopack loader to an individual import using the `with` clause (import attributes). This is specified per-import rather than globally via `turbopack.rules`.
This is useful when you want to apply a loader to a specific import without affecting all files of that type.
```tsx filename="app/page.tsx"
// Apply a raw loader to import a .txt file as a JavaScript module
import rawText from '../data.txt' with { turbopackLoader: 'raw-loader', turbopackAs: '*.js' }
export default function Page() {
return <p>{rawText}</p>
}
```
The following import attributes are supported:
| Attribute | Description |
| ------------------------ | ----------------------------------------------------------------------------------------------------------------------------- |
| `turbopackLoader` | The loader to apply (e.g. `'raw-loader'`). |
| `turbopackLoaderOptions` | JSON string of loader options (e.g. `'{"search":"X","replace":"Y"}'`). |
| `turbopackAs` | Rename pattern for the output (same as `turbopack.rules[].as`). For example, `'*.js'` treats the loader output as JavaScript. |
| `turbopackModuleType` | Set the module type for the output (same as `turbopack.rules[].type`). |
Loaders with options pass a JSON-encoded string via `turbopackLoaderOptions`:
```tsx filename="app/page.tsx"
import value from '../data.js' with { turbopackLoader: 'string-replace-loader', turbopackLoaderOptions: '{"search":"PLACEHOLDER","replace":"replaced value"}' }
```
> **Good to know**: Import attributes with `turbopackLoader` are Turbopack-specific and are not supported by webpack. This feature requires the `with` keyword (not `assert`) in your import statements.
### Resolving aliases
Turbopack can be configured to modify module resolution through aliases, similar to webpack's [`resolve.alias`](https://webpack.js.org/configuration/resolve/#resolvealias) configuration.
To configure resolve aliases, map imported patterns to their new destination in `next.config.js`:
```js filename="next.config.js"
module.exports = {
turbopack: {
resolveAlias: {
underscore: 'lodash',
mocha: { browser: 'mocha/browser-entry.js' },
},
},
}
```
This aliases imports of the `underscore` package to the `lodash` package. In other words, `import underscore from 'underscore'` will load the `lodash` module instead of `underscore`.
Turbopack also supports conditional aliasing through this field, similar to Node.js' [conditional exports](https://nodejs.org/docs/latest-v18.x/api/packages.html#conditional-exports). At the moment only the `browser` condition is supported. In the case above, imports of the `mocha` module will be aliased to `mocha/browser-entry.js` when Turbopack targets browser environments.
### Resolving custom extensions
Turbopack can be configured to resolve modules with custom extensions, similar to webpack's [`resolve.extensions`](https://webpack.js.org/configuration/resolve/#resolveextensions) configuration.
To configure resolve extensions, use the `resolveExtensions` field in `next.config.js`:
```js filename="next.config.js"
module.exports = {
turbopack: {
resolveExtensions: ['.mdx', '.tsx', '.ts', '.jsx', '.js', '.mjs', '.json'],
},
}
```
This overwrites the original resolve extensions with the provided list. Make sure to include the default extensions.
For more information and guidance for how to migrate your app to Turbopack from webpack, see [Turbopack's documentation on webpack compatibility](https://turbo.build/pack/docs/migrating-from-webpack).
### Debug IDs
Turbopack can be configured to generate [debug IDs](https://github.com/tc39/ecma426/blob/main/proposals/debug-id.md) in JavaScript bundles and source maps.
To configure debug IDs, use the `debugIds` field in `next.config.js`:
```js filename="next.config.js"
module.exports = {
turbopack: {
debugIds: true,
},
}
```
The option automatically adds a polyfill for debug IDs to the JavaScript bundle to ensure compatibility. The debug IDs are available in the `globalThis._debugIds` global variable.
## Version History
| Version | Changes |
| -------- | ---------------------------------------------------- |
| `16.2.0` | `turbopackLoader` import attributes were added. |
| `16.2.0` | `turbopack.rules.*.type` was added. |
| `16.2.0` | `turbopack.rules.*.condition.contentType` was added. |
| `16.2.0` | `turbopack.rules.*.condition.query` was added. |
| `16.0.0` | `turbopack.debugIds` was added. |
| `16.0.0` | `turbopack.rules.*.condition` was added. |
| `15.3.0` | `experimental.turbo` is changed to `turbopack`. |
| `13.0.0` | `experimental.turbo` introduced. |
@@ -0,0 +1,48 @@
---
title: Turbopack FileSystem Caching
nav_title: turbopackFileSystemCache
description: Learn how to enable FileSystem Caching for Turbopack builds
---
## Usage
Turbopack FileSystem Cache enables Turbopack to reduce work across `next dev` or `next build` commands. When enabled, Turbopack will save and restore data to the `.next` folder between builds, which can greatly speed up subsequent builds and dev sessions.
> **Good to know:** The FileSystem Cache feature is considered stable for development and experimental for production builds
```ts filename="next.config.ts" switcher
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
experimental: {
// Enable filesystem caching for `next dev`
turbopackFileSystemCacheForDev: true,
// Enable filesystem caching for `next build`
turbopackFileSystemCacheForBuild: true,
},
}
export default nextConfig
```
```js filename="next.config.js" switcher
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
// Enable filesystem caching for `next dev`
turbopackFileSystemCacheForDev: true,
// Enable filesystem caching for `next build`
turbopackFileSystemCacheForBuild: true,
},
}
module.exports = nextConfig
```
## Version Changes
| Version | Changes |
| --------- | -------------------------------------------------------------- |
| `v16.1.0` | FileSystem caching is enabled by default for development |
| `v16.0.0` | Beta release with separate flags for build and dev |
| `v15.5.0` | Persistent caching released as experimental on canary releases |
@@ -0,0 +1,173 @@
---
title: turbopack.ignoreIssue
description: Suppress specific Turbopack errors and warnings from the CLI output and error overlay.
related:
title: Next Steps
description: Learn more about Turbopack configuration.
links:
- app/api-reference/config/next-config-js/turbopack
- app/api-reference/turbopack
---
The `turbopack.ignoreIssue` option allows you to filter out specific [Turbopack](/docs/app/api-reference/turbopack) errors and warnings so they do not appear in the CLI output or the error overlay. This is useful for suppressing known warnings that do not affect your application, such as intentionally unresolved optional dependencies.
This option is only available when using Turbopack (`next dev --turbopack`).
## Usage
```ts filename="next.config.ts" switcher
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
turbopack: {
ignoreIssue: [
{
path: '**/vendor/**',
},
],
},
}
export default nextConfig
```
```js filename="next.config.js" switcher
/** @type {import('next').NextConfig} */
const nextConfig = {
turbopack: {
ignoreIssue: [
{
path: '**/vendor/**',
},
],
},
}
module.exports = nextConfig
```
## Options
Each rule in the `ignoreIssue` array is an object with the following fields:
| Field | Type | Required | Description |
| ----------------------------- | ------------------ | -------- | ------------------------------------------ |
| [`path`](#path) | `string \| RegExp` | Yes | Matches against the file path of the issue |
| [`title`](#title) | `string \| RegExp` | No | Matches against the issue title |
| [`description`](#description) | `string \| RegExp` | No | Matches against the issue description |
An issue is suppressed when it matches the `path` **and** all other specified fields in a rule. If only `path` is provided, any issue from a matching file is suppressed.
> **Good to know:** Issue titles and descriptions may change between Turbopack versions. The `path` field is generally stable, but is not guaranteed to remain consistent for all issue types. When possible, prefer using more specific `path` patterns over `title` or `description` matching.
### `path`
A **glob pattern** (when a string) or **regular expression** that matches against the file path where the issue originated.
```js filename="next.config.js"
module.exports = {
turbopack: {
ignoreIssue: [
// Glob pattern: suppress issues from any file under vendor/
{ path: '**/vendor/**' },
// RegExp: suppress issues from files matching a pattern
{ path: /node_modules\/legacy-lib/ },
],
},
}
```
### `title`
An **exact string match** (when a string) or **regular expression** that matches against the issue title.
```js filename="next.config.js"
module.exports = {
turbopack: {
ignoreIssue: [
{
path: '**/src/**',
title: 'Module not found',
},
],
},
}
```
### `description`
An **exact string match** (when a string) or **regular expression** that matches against the issue description.
```js filename="next.config.js"
module.exports = {
turbopack: {
ignoreIssue: [
{
path: '**/src/**',
description: /Cannot find module 'optional-dep'/,
},
],
},
}
```
## Examples
### Suppressing warnings for optional dependencies
If your code uses `try/catch` around an optional `require()` call, Turbopack may report a "Module not found" warning. You can suppress it:
```ts filename="next.config.ts" switcher
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
turbopack: {
ignoreIssue: [
{
path: '**/lib/optional-feature/**',
title: 'Module not found',
},
],
},
}
export default nextConfig
```
```js filename="next.config.js" switcher
/** @type {import('next').NextConfig} */
const nextConfig = {
turbopack: {
ignoreIssue: [
{
path: '**/lib/optional-feature/**',
title: 'Module not found',
},
],
},
}
module.exports = nextConfig
```
### Combining multiple rules
You can specify multiple rules to suppress different issues:
```js filename="next.config.js"
module.exports = {
turbopack: {
ignoreIssue: [
{ path: '**/vendor/**' },
{ path: '**/legacy/**', title: 'Module not found' },
{ path: /generated\//, description: /expected identifier/ },
],
},
}
```
## Version History
| Version | Changes |
| --------- | ----------------------------------- |
| `v16.2.0` | `turbopack.ignoreIssue` introduced. |
@@ -0,0 +1,17 @@
---
title: typedRoutes
description: Enable support for statically typed links.
---
> **Note**: This option has been marked as stable, so you should use `typedRoutes` instead of `experimental.typedRoutes`.
Support for [statically typed links](/docs/app/api-reference/config/typescript#statically-typed-links). This feature requires using TypeScript in your project.
```js filename="next.config.js"
/** @type {import('next').NextConfig} */
const nextConfig = {
typedRoutes: true,
}
module.exports = nextConfig
```
@@ -0,0 +1,60 @@
---
title: typescript
description: Configure how Next.js handles TypeScript errors during production builds and specify a custom tsconfig file.
---
{/* The content of this doc is shared between the app and pages router. You can use the `<PagesOnly>Content</PagesOnly>` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}
Configure TypeScript behavior with the `typescript` option in `next.config.js`:
```js filename="next.config.js"
module.exports = {
typescript: {
ignoreBuildErrors: false,
tsconfigPath: 'tsconfig.json',
},
}
```
## Options
| Option | Type | Default | Description |
| ------------------- | --------- | ----------------- | ---------------------------------------------------------------- |
| `ignoreBuildErrors` | `boolean` | `false` | Allow production builds to complete even with TypeScript errors. |
| `tsconfigPath` | `string` | `'tsconfig.json'` | Path to a custom `tsconfig.json` file. |
## `ignoreBuildErrors`
Next.js fails your **production build** (`next build`) when TypeScript errors are present in your project.
If you'd like Next.js to dangerously produce production code even when your application has errors, you can disable the built-in type checking step.
Note that this completely skips the TypeScript type checking step. It does not run TypeScript and suppress errors, it bypasses the check entirely.
If disabled, be sure you are running type checks as part of your build or deploy process, otherwise this can be very dangerous.
```js filename="next.config.js"
module.exports = {
typescript: {
// !! WARN !!
// Dangerously allow production builds to successfully complete even if
// your project has type errors.
// !! WARN !!
ignoreBuildErrors: true,
},
}
```
## `tsconfigPath`
Use a different TypeScript configuration file for builds or tooling:
```js filename="next.config.js"
module.exports = {
typescript: {
tsconfigPath: 'tsconfig.build.json',
},
}
```
See the [TypeScript configuration](/docs/app/api-reference/config/typescript#custom-tsconfig-path) page for more details.
@@ -0,0 +1,92 @@
---
title: urlImports
description: Configure Next.js to allow importing modules from external URLs.
version: experimental
---
{/* The content of this doc is shared between the app and pages router. You can use the `<PagesOnly>Content</PagesOnly>` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}
URL imports are an experimental feature that allows you to import modules directly from external servers (instead of from the local disk).
> **Warning**: Only use domains that you trust to download and execute on your machine. Please exercise discretion, and caution until the feature is flagged as stable.
To opt-in, add the allowed URL prefixes inside `next.config.js`:
```js filename="next.config.js"
module.exports = {
experimental: {
urlImports: ['https://example.com/assets/', 'https://cdn.skypack.dev'],
},
}
```
Then, you can import modules directly from URLs:
```js
import { a, b, c } from 'https://example.com/assets/some/module.js'
```
URL Imports can be used everywhere normal package imports can be used.
## Security Model
This feature is being designed with **security as the top priority**. To start, we added an experimental flag forcing you to explicitly allow the domains you accept URL imports from. We're working to take this further by limiting URL imports to execute in the browser sandbox using the [Edge Runtime](/docs/app/api-reference/edge).
## Lockfile
When using URL imports, Next.js will create a `next.lock` directory containing a lockfile and fetched assets.
This directory **must be committed to Git**, not ignored by `.gitignore`.
- When running `next dev`, Next.js will download and add all newly discovered URL Imports to your lockfile.
- When running `next build`, Next.js will use only the lockfile to build the application for production.
Typically, no network requests are needed and any outdated lockfile will cause the build to fail.
One exception is resources that respond with `Cache-Control: no-cache`.
These resources will have a `no-cache` entry in the lockfile and will always be fetched from the network on each build.
## Examples
### Skypack
```js
import confetti from 'https://cdn.skypack.dev/canvas-confetti'
import { useEffect } from 'react'
export default () => {
useEffect(() => {
confetti()
})
return <p>Hello</p>
}
```
### Static Image Imports
```js
import Image from 'next/image'
import logo from 'https://example.com/assets/logo.png'
export default () => (
<div>
<Image src={logo} placeholder="blur" />
</div>
)
```
### URLs in CSS
```css
.className {
background: url('https://example.com/assets/hero.jpg');
}
```
### Asset Imports
```js
const logo = new URL('https://example.com/assets/file.txt', import.meta.url)
console.log(logo.pathname)
// prints "/_next/static/media/file.a9727b5d.txt"
```
@@ -0,0 +1,126 @@
---
title: useLightningcss
description: Enable experimental support for Lightning CSS.
version: experimental
---
Experimental support for using [Lightning CSS](https://lightningcss.dev) with webpack. Lightning CSS is a fast CSS transformer and minifier, written in Rust.
If this option is not set, Next.js on webpack uses [PostCSS](https://postcss.org/) with [`postcss-preset-env`](https://www.npmjs.com/package/postcss-preset-env) by default.
Turbopack uses Lightning CSS by default since Next 14.2. This configuration option has no effect on Turbopack. Turbopack always uses Lightning CSS.
```ts filename="next.config.ts" switcher
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
experimental: {
useLightningcss: false, // default, ignored on Turbopack
},
}
export default nextConfig
```
```js filename="next.config.js" switcher
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
useLightningcss: true, // disables PostCSS on webpack
},
}
module.exports = nextConfig
```
## `lightningCssFeatures`
By default, Lightning CSS decides which CSS features to transpile based on your [browserslist](https://browsersl.ist/) targets. The `lightningCssFeatures` option lets you override this by forcing specific features to always be transpiled (`include`) or never be transpiled (`exclude`), regardless of browser support.
This applies to both webpack (when `useLightningcss` is enabled) and Turbopack.
```ts filename="next.config.ts" switcher
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
experimental: {
useLightningcss: true,
lightningCssFeatures: {
// Always transpile these features, even if targets support them
include: ['light-dark', 'oklab-colors'],
// Never transpile these features, even if targets don't support them
exclude: ['nesting'],
},
},
}
export default nextConfig
```
```js filename="next.config.js" switcher
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
useLightningcss: true,
lightningCssFeatures: {
// Always transpile these features, even if targets support them
include: ['light-dark', 'oklab-colors'],
// Never transpile these features, even if targets don't support them
exclude: ['nesting'],
},
},
}
module.exports = nextConfig
```
### Options
| Option | Type | Description |
| --------- | ---------- | -------------------------------------------------------------------------- |
| `include` | `string[]` | Features to always transpile, regardless of browser targets. |
| `exclude` | `string[]` | Features to never transpile, even when browser targets would require them. |
### Available features
Individual features:
| Feature name | Description |
| ----------------------------------- | ---------------------------------------------------- |
| `nesting` | [CSS Nesting](https://drafts.csswg.org/css-nesting/) |
| `not-selector-list` | `:not` with multiple selectors |
| `dir-selector` | `:dir()` selector |
| `lang-selector-list` | `:lang()` with multiple languages |
| `is-selector` | `:is()` selector |
| `text-decoration-thickness-percent` | Percentage values in `text-decoration-thickness` |
| `media-interval-syntax` | Media query range interval syntax |
| `media-range-syntax` | Media query range syntax (`width >= 600px`) |
| `custom-media-queries` | `@custom-media` rules |
| `clamp-function` | `clamp()` function |
| `color-function` | `color()` function |
| `oklab-colors` | `oklab()` and `oklch()` colors |
| `lab-colors` | `lab()` and `lch()` colors |
| `p3-colors` | Display P3 colors |
| `hex-alpha-colors` | 4 and 8 digit hex colors with alpha |
| `space-separated-color-notation` | Space-separated color notation (`rgb(0 0 0)`) |
| `font-family-system-ui` | `system-ui` font family |
| `double-position-gradients` | Double-position gradient stops |
| `vendor-prefixes` | Vendor-prefixed properties and values |
| `logical-properties` | Logical properties and values |
| `light-dark` | `light-dark()` color function |
Composite groups (shorthand for enabling multiple features at once):
| Group name | Includes |
| --------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `selectors` | `nesting`, `not-selector-list`, `dir-selector`, `lang-selector-list`, `is-selector` |
| `media-queries` | `media-interval-syntax`, `media-range-syntax`, `custom-media-queries` |
| `colors` | `color-function`, `oklab-colors`, `lab-colors`, `p3-colors`, `hex-alpha-colors`, `space-separated-color-notation`, `light-dark` |
## Version History
| Version | Changes |
| -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `16.2.0` | `lightningCssFeatures` added. |
| `15.1.0` | Support for `useSwcCss` was removed from Turbopack. |
| `14.2.0` | Turbopack's default CSS processor was changed from `@swc/css` to Lightning CSS. `useLightningcss` became ignored on Turbopack, and a legacy `experimental.turbo.useSwcCss` option was added. |
@@ -0,0 +1,38 @@
---
title: viewTransition
description: Enable ViewTransition API from React in App Router
version: experimental
---
`viewTransition` is an experimental flag that enables the new [View Transitions API](https://developer.mozilla.org/en-US/docs/Web/API/View_Transition_API) in React. This API allows you to leverage the native View Transitions browser API to create seamless transitions between UI states.
To enable this feature, you need to set the `viewTransition` property to `true` in your `next.config.js` file.
```js filename="next.config.js"
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
viewTransition: true,
},
}
module.exports = nextConfig
```
> Important Notice: The `<ViewTransition>` Component is already available in React's Canary release channel.
> `experimental.viewTransition` is only required to enable deeper integration with Next.js features e.g. automatically
> [adding Transition types](https://react.dev/reference/react/addTransitionType) for navigations. Next.js specific transition types are not implemented yet.
## Usage
You can import the [`<ViewTransition>` Component](https://react.dev/reference/react/ViewTransition) from React in your application:
```jsx
import { ViewTransition } from 'react'
```
### Live Demo
Check out our [Next.js View Transition Demo](https://view-transition-example.vercel.app) to see this feature in action.
As this API evolves, we will update our documentation and share more examples. However, for now, we strongly advise against using this feature in production.
@@ -0,0 +1,27 @@
---
title: webVitalsAttribution
description: Learn how to use the webVitalsAttribution option to pinpoint the source of Web Vitals issues.
version: experimental
---
{/* The content of this doc is shared between the app and pages router. You can use the `<PagesOnly>Content</PagesOnly>` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}
When debugging issues related to Web Vitals, it is often helpful if we can pinpoint the source of the problem.
For example, in the case of Cumulative Layout Shift (CLS), we might want to know the first element that shifted when the single largest layout shift occurred.
Or, in the case of Largest Contentful Paint (LCP), we might want to identify the element corresponding to the LCP for the page.
If the LCP element is an image, knowing the URL of the image resource can help us locate the asset we need to optimize.
Pinpointing the biggest contributor to the Web Vitals score, aka [attribution](https://github.com/GoogleChrome/web-vitals/blob/4ca38ae64b8d1e899028c692f94d4c56acfc996c/README.md#attribution),
allows us to obtain more in-depth information like entries for [PerformanceEventTiming](https://developer.mozilla.org/docs/Web/API/PerformanceEventTiming), [PerformanceNavigationTiming](https://developer.mozilla.org/docs/Web/API/PerformanceNavigationTiming) and [PerformanceResourceTiming](https://developer.mozilla.org/docs/Web/API/PerformanceResourceTiming).
Attribution is disabled by default in Next.js but can be enabled **per metric** by specifying the following in `next.config.js`.
```js filename="next.config.js"
module.exports = {
experimental: {
webVitalsAttribution: ['CLS', 'LCP'],
},
}
```
Valid attribution values are all `web-vitals` metrics specified in the [`NextWebVitalsMetric`](https://github.com/vercel/next.js/blob/442378d21dd56d6e769863eb8c2cb521a463a2e0/packages/next/shared/lib/utils.ts#L43) type.
@@ -0,0 +1,88 @@
---
title: Custom Webpack Config
nav_title: webpack
description: Learn how to customize the webpack config used by Next.js
---
{/* The content of this doc is shared between the app and pages router. You can use the `<PagesOnly>Content</PagesOnly>` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}
> **Good to know**: changes to webpack config are not covered by semver so proceed at your own risk
Before continuing to add custom webpack configuration to your application make sure Next.js doesn't already support your use-case:
<AppOnly>
- [CSS imports](/docs/app/getting-started/css)
- [CSS modules](/docs/app/getting-started/css#css-modules)
- [Sass/SCSS imports](/docs/app/guides/sass)
- [Sass/SCSS modules](/docs/app/guides/sass)
</AppOnly>
<PagesOnly>
- [CSS imports](/docs/app/getting-started/css)
- [CSS modules](/docs/app/getting-started/css)
- [Sass/SCSS imports](/docs/pages/guides/sass)
- [Sass/SCSS modules](/docs/pages/guides/sass)
- [Customizing babel configuration](/docs/pages/guides/babel)
</PagesOnly>
Some commonly asked for features are available as plugins:
- [@next/mdx](https://github.com/vercel/next.js/tree/canary/packages/next-mdx)
- [@next/bundle-analyzer](https://github.com/vercel/next.js/tree/canary/packages/next-bundle-analyzer)
In order to extend our usage of `webpack`, you can define a function that extends its config inside `next.config.js`, like so:
```js filename="next.config.js"
module.exports = {
webpack: (
config,
{ buildId, dev, isServer, defaultLoaders, nextRuntime, webpack }
) => {
// Important: return the modified config
return config
},
}
```
> The `webpack` function is executed three times, twice for the server (nodejs / edge runtime) and once for the client. This allows you to distinguish between client and server configuration using the `isServer` property.
The second argument to the `webpack` function is an object with the following properties:
- `buildId`: `String` - The build id, used as a unique identifier between builds.
- `dev`: `Boolean` - Indicates if the compilation will be done in development.
- `isServer`: `Boolean` - It's `true` for server-side compilation, and `false` for client-side compilation.
- `nextRuntime`: `String | undefined` - The target runtime for server-side compilation; either `"edge"` or `"nodejs"`, it's `undefined` for client-side compilation.
- `defaultLoaders`: `Object` - Default loaders used internally by Next.js:
- `babel`: `Object` - Default `babel-loader` configuration.
Example usage of `defaultLoaders.babel`:
```js
// Example config for adding a loader that depends on babel-loader
// This source was taken from the @next/mdx plugin source:
// https://github.com/vercel/next.js/tree/canary/packages/next-mdx
module.exports = {
webpack: (config, options) => {
config.module.rules.push({
test: /\.mdx/,
use: [
options.defaultLoaders.babel,
{
loader: '@mdx-js/loader',
options: pluginOptions.options,
},
],
})
return config
},
}
```
#### `nextRuntime`
Notice that `isServer` is `true` when `nextRuntime` is `"edge"` or `"nodejs"`, `nextRuntime` `"edge"` is currently for proxy and Server Components in edge runtime only.
@@ -0,0 +1,532 @@
---
title: TypeScript
description: Next.js provides a TypeScript-first development experience for building your React application.
---
{/* The content of this doc is shared between the app and pages router. You can use the `<PagesOnly>Content</PagesOnly>` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}
Next.js comes with built-in TypeScript, automatically installing the necessary packages and configuring the proper settings when you create a new project with `create-next-app`.
To add TypeScript to an existing project, rename a file to `.ts` / `.tsx`. Run `next dev` and `next build` to automatically install the necessary dependencies and add a `tsconfig.json` file with the recommended config options.
> **Good to know**: If you already have a `jsconfig.json` file, copy the `paths` compiler option from the old `jsconfig.json` into the new `tsconfig.json` file, and delete the old `jsconfig.json` file.
<AppOnly>
## IDE Plugin
Next.js includes a custom TypeScript plugin and type checker, which VSCode and other code editors can use for advanced type-checking and auto-completion.
You can enable the plugin in VS Code by:
1. Opening the command palette (`Ctrl/⌘` + `Shift` + `P`)
2. Searching for "TypeScript: Select TypeScript Version"
3. Selecting "Use Workspace Version"
<Image
alt="TypeScript Command Palette"
srcLight="/docs/light/typescript-command-palette.png"
srcDark="/docs/dark/typescript-command-palette.png"
width="1600"
height="637"
/>
Now, when editing files, the custom plugin will be enabled. When running `next build`, the custom type checker will be used.
The TypeScript plugin can help with:
- Warning if invalid values for [segment config options](/docs/app/api-reference/file-conventions/route-segment-config) are passed.
- Showing available options and in-context documentation.
- Ensuring the `'use client'` directive is used correctly.
- Ensuring client hooks (like `useState`) are only used in Client Components.
> **🎥 Watch:** Learn about the built-in TypeScript plugin → [YouTube (3 minutes)](https://www.youtube.com/watch?v=pqMqn9fKEf8)
## End-to-End Type Safety
The Next.js App Router has **enhanced type safety**. This includes:
1. **No serialization of data between fetching function and page**: You can `fetch` directly in components, layouts, and pages on the server. This data _does not_ need to be serialized (converted to a string) to be passed to the client side for consumption in React. Instead, since `app` uses Server Components by default, we can use values like `Date`, `Map`, `Set`, and more without any extra steps. Previously, you needed to manually type the boundary between server and client with Next.js-specific types.
2. **Streamlined data flow between components**: With the removal of `_app` in favor of root layouts, it is now easier to visualize the data flow between components and pages. Previously, data flowing between individual `pages` and `_app` were difficult to type and could introduce confusing bugs. With [colocated data fetching](/docs/app/getting-started/fetching-data) in the App Router, this is no longer an issue.
[Data Fetching in Next.js](/docs/app/getting-started/fetching-data) now provides as close to end-to-end type safety as possible without being prescriptive about your database or content provider selection.
We're able to type the response data as you would expect with normal TypeScript. For example:
```tsx filename="app/page.tsx" switcher
async function getData() {
const res = await fetch('https://api.example.com/...')
// The return value is *not* serialized
// You can return Date, Map, Set, etc.
return res.json()
}
export default async function Page() {
const name = await getData()
return '...'
}
```
For _complete_ end-to-end type safety, this also requires your database or content provider to support TypeScript. This could be through using an [ORM](https://en.wikipedia.org/wiki/Object%E2%80%93relational_mapping) or type-safe query builder.
## Route-Aware Type Helpers
Next.js generates global helpers for App Router route types. These are available without imports and are generated during `next dev`, `next build`, or via [`next typegen`](/docs/app/api-reference/cli/next#next-typegen-options):
- [`PageProps`](/docs/app/api-reference/file-conventions/page#page-props-helper)
- [`LayoutProps`](/docs/app/api-reference/file-conventions/layout#layout-props-helper)
- [`RouteContext`](/docs/app/api-reference/file-conventions/route#route-context-helper)
</AppOnly>
## `next-env.d.ts`
Next.js generates a `next-env.d.ts` file in your project root. This file references Next.js type definitions, allowing TypeScript to recognize non-code imports (images, stylesheets, etc.) and Next.js-specific types.
Running `next dev`, `next build`, or [`next typegen`](/docs/app/api-reference/cli/next#next-typegen-options) regenerates this file.
> **Good to know**:
>
> - We recommend adding `next-env.d.ts` to your `.gitignore` file.
> - The file must be in your `tsconfig.json` `include` array (`create-next-app` does this automatically).
## Examples
### Type Checking Next.js Configuration Files
You can use TypeScript and import types in your Next.js configuration by using `next.config.ts`.
```ts filename="next.config.ts"
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
/* config options here */
}
export default nextConfig
```
Module resolution in `next.config.ts` is currently limited to CommonJS. However, ECMAScript Modules (ESM) syntax is available when [using Node.js native TypeScript resolver](#using-nodejs-native-typescript-resolver-for-nextconfigts) for Node.js v22.10.0 and higher.
When using the `next.config.js` file, you can add some type checking in your IDE using JSDoc as below:
```js filename="next.config.js"
// @ts-check
/** @type {import('next').NextConfig} */
const nextConfig = {
/* config options here */
}
module.exports = nextConfig
```
### Using Node.js Native TypeScript Resolver for `next.config.ts`
> **Note**: Available on Node.js v22.10.0+ and only when the feature is enabled. Next.js does not enable it.
Next.js detects the [Node.js native TypeScript resolver](https://nodejs.org/api/typescript.html) via [`process.features.typescript`](https://nodejs.org/api/process.html#processfeaturestypescript), added in **v22.10.0**. When present, `next.config.ts` can use native ESM, including toplevel `await` and dynamic `import()`. This mechanism inherits the capabilities and limitations of Node's resolver.
In Node.js versions **v22.18.0+**, `process.features.typescript` is enabled by default. For versions between **v22.10.0** and **22.17.x**, opt in with `NODE_OPTIONS=--experimental-transform-types`:
```bash filename="Terminal"
NODE_OPTIONS=--experimental-transform-types next <command>
```
#### For CommonJS Projects (Default)
Although `next.config.ts` supports native ESM syntax in CommonJS projects, Node.js will still assume `next.config.ts` is a CommonJS file by default, resulting in Node.js reparsing the file as ESM when module syntax is detected. Therefore, we recommend using the `next.config.mts` file for CommonJS projects to explicitly indicate it's an ESM module:
```ts filename="next.config.mts"
import type { NextConfig } from 'next'
// Top-level await and dynamic import are supported
const flags = await import('./flags.js').then((m) => m.default ?? m)
const nextConfig: NextConfig = {
/* config options here */
typedRoutes: Boolean(flags?.typedRoutes),
}
export default nextConfig
```
#### For ESM Projects
When `"type"` is set to `"module"` in `package.json`, your project uses ESM. Learn more about this setting [in the Node.js docs](https://nodejs.org/api/packages.html#type). In this case, you can write `next.config.ts` directly with ESM syntax.
> **Good to know**: When using `"type": "module"` in your `package.json`, all `.js` and `.ts` files in your project are treated as ESM modules by default. You may need to rename files with CommonJS syntax to `.cjs` or `.cts` extensions if needed.
### Statically Typed Links
Next.js can statically type links to prevent typos and other errors when using `next/link`, improving type safety when navigating between pages.
Works in both the Pages and App Router for the `href` prop in `next/link`. In the App Router, it also types `next/navigation` methods like `push`, `replace`, and `prefetch`. It does not type `next/router` methods in Pages Router.
Literal `href` strings are validated, while non-literal `href`s may require a cast with `as Route`.
To opt-into this feature, `typedRoutes` needs to be enabled and the project needs to be using TypeScript.
```ts filename="next.config.ts"
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
typedRoutes: true,
}
export default nextConfig
```
Next.js will generate a link definition in `.next/types` that contains information about all existing routes in your application, which TypeScript can then use to provide feedback in your editor about invalid links.
> **Good to know**: If you set up your project without `create-next-app`, ensure the generated Next.js types are included by adding `.next/types/**/*.ts` to the `include` array in your `tsconfig.json`:
{/* prettier-ignore-start */}
```json filename="tsconfig.json" highlight={4}
{
"include": [
"next-env.d.ts",
".next/types/**/*.ts",
"**/*.ts",
"**/*.tsx"
],
"exclude": ["node_modules"]
}
```
{/* prettier-ignore-end */}
Currently, support includes any string literal, including dynamic segments. For non-literal strings, you need to manually cast with `as Route`. The example below shows both `next/link` and `next/navigation` usage:
```tsx filename="app/example-client.tsx"
'use client'
import type { Route } from 'next'
import Link from 'next/link'
import { useRouter } from 'next/navigation'
export default function Example() {
const router = useRouter()
const slug = 'nextjs'
return (
<>
{/* Link: literal and dynamic */}
<Link href="/about" />
<Link href={`/blog/${slug}`} />
<Link href={('/blog/' + slug) as Route} />
{/* TypeScript error if href is not a valid route */}
<Link href="/aboot" />
{/* Router: literal and dynamic strings are validated */}
<button onClick={() => router.push('/about')}>Push About</button>
<button onClick={() => router.replace(`/blog/${slug}`)}>
Replace Blog
</button>
<button onClick={() => router.prefetch('/contact')}>
Prefetch Contact
</button>
{/* For non-literal strings, cast to Route */}
<button onClick={() => router.push(('/blog/' + slug) as Route)}>
Push Non-literal Blog
</button>
</>
)
}
```
The same applies for redirecting routes defined by proxy:
```ts filename="proxy.ts"
import { NextRequest, NextResponse } from 'next/server'
export function proxy(request: NextRequest) {
if (request.nextUrl.pathname === '/proxy-redirect') {
return NextResponse.redirect(new URL('/', request.url))
}
return NextResponse.next()
}
```
```tsx filename="app/some/page.tsx"
import type { Route } from 'next'
export default function Page() {
return <Link href={'/proxy-redirect' as Route}>Link Text</Link>
}
```
To accept `href` in a custom component wrapping `next/link`, use a generic:
```tsx
import type { Route } from 'next'
import Link from 'next/link'
function Card<T extends string>({ href }: { href: Route<T> | URL }) {
return (
<Link href={href}>
<div>My Card</div>
</Link>
)
}
```
You can also type a simple data structure and iterate to render links:
```ts filename="components/nav-items.ts"
import type { Route } from 'next'
type NavItem<T extends string = string> = {
href: T
label: string
}
export const navItems: NavItem<Route>[] = [
{ href: '/', label: 'Home' },
{ href: '/about', label: 'About' },
{ href: '/blog', label: 'Blog' },
]
```
Then, map over the items to render `Link`s:
```tsx filename="components/nav.tsx"
import Link from 'next/link'
import { navItems } from './nav-items'
export function Nav() {
return (
<nav>
{navItems.map((item) => (
<Link key={item.href} href={item.href}>
{item.label}
</Link>
))}
</nav>
)
}
```
> **How does it work?**
>
> When running `next dev` or `next build`, Next.js generates a hidden `.d.ts` file inside `.next` that contains information about all existing routes in your application (all valid routes as the `href` type of `Link`). This `.d.ts` file is included in `tsconfig.json` and the TypeScript compiler will check that `.d.ts` and provide feedback in your editor about invalid links.
### Type IntelliSense for Environment Variables
During development, Next.js generates a `.d.ts` file in `.next/types` that contains information about the loaded environment variables for your editor's IntelliSense. If the same environment variable key is defined in multiple files, it is deduplicated according to the [Environment Variable Load Order](/docs/app/guides/environment-variables#environment-variable-load-order).
To opt-into this feature, `experimental.typedEnv` needs to be enabled and the project needs to be using TypeScript.
```ts filename="next.config.ts"
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
experimental: {
typedEnv: true,
},
}
export default nextConfig
```
> **Good to know**: Types are generated based on the environment variables loaded at development runtime, which excludes variables from `.env.production*` files by default. To include production-specific variables, run `next dev` with `NODE_ENV=production`.
<AppOnly>
### With Async Server Components
To use an `async` Server Component with TypeScript, ensure you are using TypeScript `5.1.3` or higher and `@types/react` `18.2.8` or higher.
If you are using an older version of TypeScript, you may see a `'Promise<Element>' is not a valid JSX element` type error. Updating to the latest version of TypeScript and `@types/react` should resolve this issue.
</AppOnly>
<PagesOnly>
### Static Generation and Server-side Rendering
For [`getStaticProps`](/docs/pages/api-reference/functions/get-static-props), [`getStaticPaths`](/docs/pages/api-reference/functions/get-static-paths), and [`getServerSideProps`](/docs/pages/api-reference/functions/get-server-side-props), you can use the `GetStaticProps`, `GetStaticPaths`, and `GetServerSideProps` types respectively:
```tsx filename="pages/blog/[slug].tsx"
import type { GetStaticProps, GetStaticPaths, GetServerSideProps } from 'next'
export const getStaticProps = (async (context) => {
// ...
}) satisfies GetStaticProps
export const getStaticPaths = (async () => {
// ...
}) satisfies GetStaticPaths
export const getServerSideProps = (async (context) => {
// ...
}) satisfies GetServerSideProps
```
> **Good to know:** `satisfies` was added to TypeScript in [4.9](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-9.html). We recommend upgrading to the latest version of TypeScript.
### With API Routes
The following is an example of how to use the built-in types for API routes:
```ts filename="pages/api/hello.ts"
import type { NextApiRequest, NextApiResponse } from 'next'
export default function handler(req: NextApiRequest, res: NextApiResponse) {
res.status(200).json({ name: 'John Doe' })
}
```
You can also type the response data:
```ts filename="pages/api/hello.ts"
import type { NextApiRequest, NextApiResponse } from 'next'
type Data = {
name: string
}
export default function handler(
req: NextApiRequest,
res: NextApiResponse<Data>
) {
res.status(200).json({ name: 'John Doe' })
}
```
### With custom `App`
If you have a [custom `App`](/docs/pages/building-your-application/routing/custom-app), you can use the built-in type `AppProps` and change file name to `./pages/_app.tsx` like so:
```ts
import type { AppProps } from 'next/app'
export default function MyApp({ Component, pageProps }: AppProps) {
return <Component {...pageProps} />
}
```
</PagesOnly>
### Incremental type checking
Since `v10.2.1` Next.js supports [incremental type checking](https://www.typescriptlang.org/tsconfig#incremental) when enabled in your `tsconfig.json`, this can help speed up type checking in larger applications.
### Custom `tsconfig` path
In some cases, you might want to use a different TypeScript configuration for builds or tooling. To do that, set `typescript.tsconfigPath` in `next.config.ts` to point Next.js to another `tsconfig` file.
```ts filename="next.config.ts"
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
typescript: {
tsconfigPath: 'tsconfig.build.json',
},
}
export default nextConfig
```
For example, switch to a different config for production builds:
```ts filename="next.config.ts"
import type { NextConfig } from 'next'
const isProd = process.env.NODE_ENV === 'production'
const nextConfig: NextConfig = {
typescript: {
tsconfigPath: isProd ? 'tsconfig.build.json' : 'tsconfig.json',
},
}
export default nextConfig
```
<details>
<summary>Why you might use a separate `tsconfig` for builds</summary>
You might need to relax checks in scenarios like monorepos, where the build also validates shared dependencies that don't match your project's standards, or when loosening checks in CI to continue delivering while migrating locally to stricter TypeScript settings (and still wanting your IDE to highlight misuse).
For example, if your project uses `useUnknownInCatchVariables` but some monorepo dependencies still assume `any`:
```json filename="tsconfig.build.json"
{
"extends": "./tsconfig.json",
"compilerOptions": {
"useUnknownInCatchVariables": false
}
}
```
This keeps your editor strict via `tsconfig.json` while allowing the production build to use relaxed settings.
</details>
> **Good to know**:
>
> - IDEs typically read `tsconfig.json` for diagnostics and IntelliSense, so you can still see IDE warnings while production builds use the alternate config. Mirror critical options if you want parity in the editor.
> - In development, only `tsconfig.json` is watched for changes. If you edit a different file name via `typescript.tsconfigPath`, restart the dev server to apply changes.
> - The configured file is used in `next dev`, `next build`, and `next typegen`.
### Disabling TypeScript errors in production
Next.js fails your **production build** (`next build`) when TypeScript errors are present in your project.
If you'd like Next.js to dangerously produce production code even when your application has errors, you can disable the built-in type checking step.
If disabled, be sure you are running type checks as part of your build or deploy process, otherwise this can be very dangerous.
Open `next.config.ts` and enable the `ignoreBuildErrors` option in the [`typescript`](/docs/app/api-reference/config/next-config-js/typescript) config:
```ts filename="next.config.ts"
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
typescript: {
// !! WARN !!
// Dangerously allow production builds to successfully complete even if
// your project has type errors.
// !! WARN !!
ignoreBuildErrors: true,
},
}
export default nextConfig
```
> **Good to know**: You can run `tsc --noEmit` to check for TypeScript errors yourself before building. This is useful for CI/CD pipelines where you'd like to check for TypeScript errors before deploying.
### Custom type declarations
When you need to declare custom types, you might be tempted to modify `next-env.d.ts`. However, this file is automatically generated, so any changes you make will be overwritten. Instead, you should create a new file, let's call it `new-types.d.ts`, and reference it in your `tsconfig.json`:
```json filename="tsconfig.json"
{
"compilerOptions": {
"skipLibCheck": true
//...truncated...
},
"include": [
"new-types.d.ts",
"next-env.d.ts",
".next/types/**/*.ts",
"**/*.ts",
"**/*.tsx"
],
"exclude": ["node_modules"]
}
```
## Version Changes
| Version | Changes |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| `v15.0.0` | [`next.config.ts`](#type-checking-nextjs-configuration-files) support added for TypeScript projects. |
| `v13.2.0` | Statically typed links are available in beta. |
| `v12.0.0` | [SWC](/docs/architecture/nextjs-compiler) is now used by default to compile TypeScript and TSX for faster builds. |
| `v10.2.1` | [Incremental type checking](https://www.typescriptlang.org/tsconfig#incremental) support added when enabled in your `tsconfig.json`. |
@@ -0,0 +1,385 @@
---
title: ESLint Plugin
nav_title: ESLint
description: Learn how to use and configure the ESLint plugin to catch common issues and problems in a Next.js application.
---
{/* The content of this doc is shared between the app and pages router. You can use the `<PagesOnly>Content</PagesOnly>` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}
Next.js provides an ESLint configuration package, [`eslint-config-next`](https://www.npmjs.com/package/eslint-config-next), that makes it easy to catch common issues in your application. It includes the [`@next/eslint-plugin-next`](https://www.npmjs.com/package/@next/eslint-plugin-next) plugin along with recommended rule-sets from [`eslint-plugin-react`](https://www.npmjs.com/package/eslint-plugin-react) and [`eslint-plugin-react-hooks`](https://www.npmjs.com/package/eslint-plugin-react-hooks).
The package provides two main configurations:
- **`eslint-config-next`**: Base configuration with Next.js, React, and React Hooks rules. Supports both JavaScript and TypeScript files.
- **`eslint-config-next/core-web-vitals`**: Includes everything from the base config, plus upgrades rules that impact [Core Web Vitals](https://web.dev/vitals/) from warnings to errors. Recommended for most projects.
Additionally, for TypeScript projects:
- **`eslint-config-next/typescript`**: Adds TypeScript-specific linting rules from [`typescript-eslint`](https://typescript-eslint.io/). Use this alongside the base or core-web-vitals config.
## Setup ESLint
Get linting working quickly with the ESLint CLI (flat config):
1. Install ESLint and the Next.js config:
```bash package="pnpm"
pnpm add -D eslint eslint-config-next
```
```bash package="npm"
npm i -D eslint eslint-config-next
```
```bash package="yarn"
yarn add --dev eslint eslint-config-next
```
```bash package="bun"
bun add -d eslint eslint-config-next
```
2. Create `eslint.config.mjs` with the Next.js config:
```js filename="eslint.config.mjs"
import { defineConfig, globalIgnores } from 'eslint/config'
import nextVitals from 'eslint-config-next/core-web-vitals'
const eslintConfig = defineConfig([
...nextVitals,
// Override default ignores of eslint-config-next.
globalIgnores([
// Default ignores of eslint-config-next:
'.next/**',
'out/**',
'build/**',
'next-env.d.ts',
]),
])
export default eslintConfig
```
3. Run ESLint:
```bash package="pnpm"
pnpm exec eslint .
```
```bash package="npm"
npx eslint .
```
```bash package="yarn"
yarn eslint .
```
```bash package="bun"
bunx eslint .
```
## Reference
The `eslint-config-next` package includes the `recommended` rule-sets from the following ESLint plugins:
- [`eslint-plugin-react`](https://www.npmjs.com/package/eslint-plugin-react)
- [`eslint-plugin-react-hooks`](https://www.npmjs.com/package/eslint-plugin-react-hooks)
- [`@next/eslint-plugin-next`](https://www.npmjs.com/package/@next/eslint-plugin-next)
### Rules
The `@next/eslint-plugin-next` rules included are:
| Enabled in recommended config | Rule | Description |
| :---------------------------: | ------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- |
| <Check size={18} /> | [@next/next/google-font-display](/docs/messages/google-font-display) | Enforce font-display behavior with Google Fonts. |
| <Check size={18} /> | [@next/next/google-font-preconnect](/docs/messages/google-font-preconnect) | Ensure `preconnect` is used with Google Fonts. |
| <Check size={18} /> | [@next/next/inline-script-id](/docs/messages/inline-script-id) | Enforce `id` attribute on `next/script` components with inline content. |
| <Check size={18} /> | [@next/next/next-script-for-ga](/docs/messages/next-script-for-ga) | Prefer `next/script` component when using the inline script for Google Analytics. |
| <Check size={18} /> | [@next/next/no-assign-module-variable](/docs/messages/no-assign-module-variable) | Prevent assignment to the `module` variable. |
| <Check size={18} /> | [@next/next/no-async-client-component](/docs/messages/no-async-client-component) | Prevent Client Components from being async functions. |
| <Check size={18} /> | [@next/next/no-before-interactive-script-outside-document](/docs/messages/no-before-interactive-script-outside-document) | Prevent usage of `next/script`'s `beforeInteractive` strategy outside of `pages/_document.js`. |
| <Check size={18} /> | [@next/next/no-css-tags](/docs/messages/no-css-tags) | Prevent manual stylesheet tags. |
| <Check size={18} /> | [@next/next/no-document-import-in-page](/docs/messages/no-document-import-in-page) | Prevent importing `next/document` outside of `pages/_document.js`. |
| <Check size={18} /> | [@next/next/no-duplicate-head](/docs/messages/no-duplicate-head) | Prevent duplicate usage of `<Head>` in `pages/_document.js`. |
| <Check size={18} /> | [@next/next/no-head-element](/docs/messages/no-head-element) | Prevent usage of `<head>` element. |
| <Check size={18} /> | [@next/next/no-head-import-in-document](/docs/messages/no-head-import-in-document) | Prevent usage of `next/head` in `pages/_document.js`. |
| <Check size={18} /> | [@next/next/no-html-link-for-pages](/docs/messages/no-html-link-for-pages) | Prevent usage of `<a>` elements to navigate to internal Next.js pages. |
| <Check size={18} /> | [@next/next/no-img-element](/docs/messages/no-img-element) | Prevent usage of `<img>` element due to slower LCP and higher bandwidth. |
| <Check size={18} /> | [@next/next/no-page-custom-font](/docs/messages/no-page-custom-font) | Prevent page-only custom fonts. |
| <Check size={18} /> | [@next/next/no-script-component-in-head](/docs/messages/no-script-component-in-head) | Prevent usage of `next/script` in `next/head` component. |
| <Check size={18} /> | [@next/next/no-styled-jsx-in-document](/docs/messages/no-styled-jsx-in-document) | Prevent usage of `styled-jsx` in `pages/_document.js`. |
| <Check size={18} /> | [@next/next/no-sync-scripts](/docs/messages/no-sync-scripts) | Prevent synchronous scripts. |
| <Check size={18} /> | [@next/next/no-title-in-document-head](/docs/messages/no-title-in-document-head) | Prevent usage of `<title>` with `Head` component from `next/document`. |
| <Check size={18} /> | @next/next/no-typos | Prevent common typos in [Next.js's data fetching functions](/docs/pages/building-your-application/data-fetching) |
| <Check size={18} /> | [@next/next/no-unwanted-polyfillio](/docs/messages/no-unwanted-polyfillio) | Prevent duplicate polyfills from Polyfill.io. |
We recommend using an appropriate [integration](https://eslint.org/docs/user-guide/integrations#editors) to view warnings and errors directly in your code editor during development.
<details>
<summary>`next lint` removal</summary>
Starting with Next.js 16, `next lint` is removed.
As part of the removal, the `eslint` option in your Next config file is no longer needed and can be safely removed.
</details>
## Examples
### Specifying a root directory within a monorepo
If you're using `@next/eslint-plugin-next` in a project where Next.js isn't installed in your root directory (such as a monorepo), you can tell `@next/eslint-plugin-next` where to find your Next.js application using the `settings` property in your `eslint.config.mjs`:
```js filename="eslint.config.mjs"
import { defineConfig } from 'eslint/config'
import eslintNextPlugin from '@next/eslint-plugin-next'
const eslintConfig = defineConfig([
{
files: ['**/*.{js,jsx,ts,tsx}'],
plugins: {
next: eslintNextPlugin,
},
settings: {
next: {
rootDir: 'packages/my-app/',
},
},
},
])
export default eslintConfig
```
`rootDir` can be a path (relative or absolute), a glob (i.e. `"packages/*/"`), or an array of paths and/or globs.
### Disabling rules
If you would like to modify or disable any rules provided by the supported plugins (`react`, `react-hooks`, `next`), you can directly change them using the `rules` property in your `eslint.config.mjs`:
```js filename="eslint.config.mjs"
import { defineConfig, globalIgnores } from 'eslint/config'
import nextVitals from 'eslint-config-next/core-web-vitals'
const eslintConfig = defineConfig([
...nextVitals,
{
rules: {
'react/no-unescaped-entities': 'off',
'@next/next/no-page-custom-font': 'off',
},
},
// Override default ignores of eslint-config-next.
globalIgnores([
// Default ignores of eslint-config-next:
'.next/**',
'out/**',
'build/**',
'next-env.d.ts',
]),
])
export default eslintConfig
```
### With Core Web Vitals
Enable the `eslint-config-next/core-web-vitals` configuration in your ESLint config.
```js filename="eslint.config.mjs"
import { defineConfig, globalIgnores } from 'eslint/config'
import nextVitals from 'eslint-config-next/core-web-vitals'
const eslintConfig = defineConfig([
...nextVitals,
// Override default ignores of eslint-config-next.
globalIgnores([
// Default ignores of eslint-config-next:
'.next/**',
'out/**',
'build/**',
'next-env.d.ts',
]),
])
export default eslintConfig
```
`eslint-config-next/core-web-vitals` upgrades certain lint rules in `@next/eslint-plugin-next` from warnings to errors to help improve your [Core Web Vitals](https://web.dev/vitals/) metrics.
> The `eslint-config-next/core-web-vitals` configuration is automatically included for new applications built with [Create Next App](/docs/app/api-reference/cli/create-next-app).
### With TypeScript
In addition to the Next.js ESLint rules, `create-next-app --typescript` will also add TypeScript-specific lint rules with `eslint-config-next/typescript` to your config:
```js filename="eslint.config.mjs"
import { defineConfig, globalIgnores } from 'eslint/config'
import nextVitals from 'eslint-config-next/core-web-vitals'
import nextTs from 'eslint-config-next/typescript'
const eslintConfig = defineConfig([
...nextVitals,
...nextTs,
// Override default ignores of eslint-config-next.
globalIgnores([
// Default ignores of eslint-config-next:
'.next/**',
'out/**',
'build/**',
'next-env.d.ts',
]),
])
export default eslintConfig
```
Those rules are based on [`plugin:@typescript-eslint/recommended`](https://typescript-eslint.io/linting/configs#recommended).
See [typescript-eslint > Configs](https://typescript-eslint.io/linting/configs) for more details.
### With Prettier
ESLint also contains code formatting rules, which can conflict with your existing [Prettier](https://prettier.io/) setup. We recommend including [eslint-config-prettier](https://github.com/prettier/eslint-config-prettier) in your ESLint config to make ESLint and Prettier work together.
First, install the dependency:
```bash package="pnpm"
pnpm add -D eslint-config-prettier
```
```bash package="npm"
npm i -D eslint-config-prettier
```
```bash package="yarn"
yarn add --dev eslint-config-prettier
```
```bash package="bun"
bun add -d eslint-config-prettier
```
Then, add `prettier` to your existing ESLint config:
```js filename="eslint.config.mjs"
import { defineConfig, globalIgnores } from 'eslint/config'
import nextVitals from 'eslint-config-next/core-web-vitals'
import prettier from 'eslint-config-prettier/flat'
const eslintConfig = defineConfig([
...nextVitals,
prettier,
// Override default ignores of eslint-config-next.
globalIgnores([
// Default ignores of eslint-config-next:
'.next/**',
'out/**',
'build/**',
'next-env.d.ts',
]),
])
export default eslintConfig
```
### Running lint on staged files
If you would like to use ESLint with [lint-staged](https://github.com/okonet/lint-staged) to run the linter on staged git files, add the following to the `.lintstagedrc.js` file in the root of your project:
```js filename=".lintstagedrc.js"
const path = require('path')
const buildEslintCommand = (filenames) =>
`eslint --fix ${filenames
.map((f) => `"${path.relative(process.cwd(), f)}"`)
.join(' ')}`
module.exports = {
'*.{js,jsx,ts,tsx}': [buildEslintCommand],
}
```
## Migrating existing config
If you already have ESLint configured in your application, there are two approaches to integrate Next.js linting rules, depending on your setup.
#### Using the plugin directly
Use `@next/eslint-plugin-next` directly if you have any of the following already configured:
- Conflicting plugins installed separately or through another config (such as `airbnb` or `react-app`):
- `react`
- `react-hooks`
- `jsx-a11y`
- `import`
- Custom `parserOptions` different from Next.js defaults (only if you have [customized your Babel configuration](/docs/pages/guides/babel))
- `eslint-plugin-import` with custom Node.js and/or TypeScript [resolvers](https://github.com/benmosher/eslint-plugin-import#resolvers)
In these cases, use `@next/eslint-plugin-next` directly to avoid conflicts:
First, install the plugin:
```bash package="pnpm"
pnpm add -D @next/eslint-plugin-next
```
```bash package="npm"
npm i -D @next/eslint-plugin-next
```
```bash package="yarn"
yarn add --dev @next/eslint-plugin-next
```
```bash package="bun"
bun add -d @next/eslint-plugin-next
```
Then add it to your ESLint config:
```js filename="eslint.config.mjs"
import { defineConfig } from 'eslint/config'
import nextPlugin from '@next/eslint-plugin-next'
const eslintConfig = defineConfig([
// Your other configurations...
{
files: ['**/*.{js,jsx,ts,tsx}'],
plugins: {
'@next/next': nextPlugin,
},
rules: {
...nextPlugin.configs.recommended.rules,
},
},
])
export default eslintConfig
```
This approach eliminates the risk of collisions or errors that can occur when the same plugins or parsers are imported across multiple configurations.
#### Adding to existing config
If you're adding Next.js to an existing ESLint setup, spread the Next.js config into your array:
```js filename="eslint.config.mjs"
import nextConfig from 'eslint-config-next/core-web-vitals'
// Your other config imports...
const eslintConfig = [
// Your other configurations...
...nextConfig,
]
export default eslintConfig
```
When you spread `...nextConfig`, you're adding multiple config objects that include file patterns, plugins, rules, ignores, and parser settings. ESLint applies configs in order, so later rules can override earlier ones for matching files.
> **Good to know:** This approach works well for straightforward setups. If you have a complex existing config with specific file patterns or plugin configurations that conflict, consider using the plugin directly (as shown above) for more granular control.
| Version | Changes |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `v16.0.0` | `next lint` and the `eslint` next.config.js option were removed in favor of the ESLint CLI. A [codemod](/docs/app/guides/upgrading/codemods#migrate-from-next-lint-to-eslint-cli) is available to help you migrate. |
@@ -0,0 +1,4 @@
---
title: Configuration
description: Learn how to configure Next.js applications.
---