Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

In a Next.js App Router project, configure metadata in a page or layout, keep secrets in server-side environment variables, and choose one caching model before adding cache controls. Next.js 16 introduced Cache Components, which uses opt-in APIs such as use cache; apps that do not enable it use the previous App Router model, with per-fetch and route-segment controls. The examples below identify which model each caching example uses.

Start by identifying your router and caching model

This guide’s metadata and caching examples target the App Router in the app directory. Environment variables use Next.js conventions that also apply to Pages Router projects. The official Environment Variables guide is located in the Pages Router documentation, but that placement does not make NEXT_PUBLIC_ or process.env behavior exclusive to that router.

Before changing caching code, check whether your app enables Cache Components. In Next.js 16, cacheComponents: true selects the newer model. Without that setting, use the previous model’s fetch and route-segment controls. These approaches are alternatives: do not add old route-segment cache settings to code intended to use Cache Components.

How do I add metadata in Next.js?

Use a metadata object for values known at build time, and generateMetadata when a title or description depends on route parameters, fetched data, or parent metadata. Both are Server Component features for an App Router page or layout. A single route segment cannot export both.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Set site-wide defaults in the root layout

For example, add a static metadata export to app/layout.tsx:

import type { Metadata } from 'next'

export const metadata: Metadata = {
  metadataBase: new URL('https://www.example.com'),
  title: {
    default: 'Example site',
    template: '%s | Example site',
  },
  description: 'Guides and information from Example site.',
}

export default function RootLayout({
  children,
}: Readonly<{ children: React.ReactNode }>) {
  return (
    <html lang="en">
      <body>{children}</body>
    </html>
  )
}

Replace the example origin and copy with your own. metadataBase gives URL-valued metadata a base for resolving relative paths, such as an Open Graph image path. Without it, a relative URL value can cause a build error; an absolute URL does not need it.

Set route-specific static metadata

A child page can export its own metadata when its values do not depend on runtime data. For instance, app/about/page.tsx can export a metadata object containing that page’s title and description. The root layout remains the place for defaults, while child segments provide more specific values.

Generate metadata from route data

Use generateMetadata when values depend on the route or a record loaded for that route:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
import type { Metadata } from 'next'

type Props = {
  params: Promise<{ slug: string }>
}

export async function generateMetadata({ params }: Props): Promise<Metadata> {
  const { slug } = await params
  const post = await getPost(slug)

  return {
    title: post.title,
    description: post.summary,
    openGraph: {
      title: post.title,
      description: post.summary,
      images: [post.socialImage],
    },
  }
}

getPost represents your data-access function; implement it for your application and handle a missing record according to your route’s not-found behavior. If the page body also loads this record, Next.js documents memoization for equivalent fetch requests and React cache for non-fetch data access, so metadata and rendering can share work.

Use metadata files for assets

Next.js also recognizes special metadata files for items such as favicons, manifests, and Open Graph or Twitter images. Use those conventions when an asset is the main output rather than trying to express it only as a metadata field. File-based metadata takes priority over values returned by the Metadata API when both apply.

Metadata produces the relevant document head tags and supports search-result and sharing presentation, but the framework documentation does not establish that setting a particular metadata field guarantees higher search rankings.

Know when metadata can stream

In supported cases, Next.js can stream metadata after the initial UI for bots that execute JavaScript. HTML-limited bots continue to receive blocking metadata in the document head. The framework identifies those bots from the user agent; htmlLimitedBots can override that behavior, but doing so can increase response time. Treat this as an advanced compatibility choice, not a default performance tweak.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

How do I use environment variables in Next.js?

Put environment values in project-root .env* files or configure them in your deployment environment. Next.js loads supported files into process.env. If the project uses a src directory, keep the environment files at the project root, not inside src.

Keep secrets on the server

By default, environment variables are available to server-side code and are not exposed to browser JavaScript. A name beginning with NEXT_PUBLIC_ is different: Next.js inlines that value into client-side JavaScript during next build. Treat every such value as public; never use the prefix for passwords, private API keys, or other secrets.

Keep environment files out of version control. Next.js starter projects normally ignore them, and the production guidance also recommends keeping .env.* files ignored. Commit a placeholder or example file only if it contains no credentials or other sensitive values.

Choose build-time or runtime values deliberately

A NEXT_PUBLIC_ value is frozen into the browser bundle at build time. Changing the deployment environment after the build will not change that value in the already-built client bundle. Build a separate bundle when a public value must differ between environments.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Server-side values can instead be read at runtime during dynamic rendering. The self-hosting guide describes this as a way to promote one Docker image across environments while supplying different server settings at deployment time. Use this approach for server-only configuration that must vary after the image is built; make sure the route actually reads the value during runtime rendering rather than embedding it in a public client bundle.

Load variables in tools outside Next.js

If another tool in the project—such as an ORM configuration or test runner—needs Next.js-compatible environment loading, the official guide documents @next/env and loadEnvConfig. This is separate from reading variables inside a Next.js server component or route.

How do I cache and revalidate data in Next.js?

First choose the model. Cache Components is an opt-in model introduced in Next.js 16. If it is enabled, follow that model’s APIs. If it is not enabled, use the previous App Router model. The Next.js documentation updated in February and March 2026 describes these as distinct approaches, not a single stable set of defaults.

Question Cache Components model Previous App Router model
Configuration Enable cacheComponents: true. Do not enable Cache Components; use the previous-model guide.
How caching is applied Opt specific routes, components, or functions into caching with use cache. Set caching behavior with fetch options and route-segment controls.
Lifetime controls Use cacheLife. Use next.revalidate for fetch resources or the route-segment revalidate setting.
Invalidation Use cache tagging APIs such as cacheTag for tag-based management and invalidation. Use revalidateTag or revalidatePath for on-demand invalidation.
Migration consideration When enabled, Cache Components APIs replace previous route-segment settings. Existing code can continue using the previous-model controls while Cache Components is off.

Cache Components: opt specific code in

Enable the feature in next.config.ts:

import type { NextConfig } from 'next'

const nextConfig: NextConfig = {
  cacheComponents: true,
}

export default nextConfig

Then mark the route, component, or function that should be cached with use cache. Use cacheLife to configure its lifetime and cacheTag where tag-based management is useful. In this model, dynamic data can still be fetched at runtime unless the relevant code is opted into caching.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
import { cacheLife, cacheTag } from 'next/cache'

export async function getCatalog() {
  'use cache'
  cacheLife('hours')
  cacheTag('catalog')

  return db.catalog.findMany()
}

The documented default use cache profile has a 5-minute client stale time and 15-minute server revalidation, according to the Next.js documentation updated in 2026. Those values belong to that default profile, not every cache or every deployment; a configured cacheLife scope can change the lifetime.

Pay particular attention to metadata that reads request-time or uncached data. If the rest of a page can be prerendered with Cache Components, the framework requires an explicit choice: cache the data where appropriate or deliberately defer rendering. Do not assume runtime metadata streaming will happen without affecting the rendering decision.

Previous App Router model: configure fetches and routes

If cacheComponents is not enabled, use the previous model. A fetch can set a maximum cache lifetime with next.revalidate:

const response = await fetch('https://api.example.com/posts', {
  next: { revalidate: 3600 },
})

For this model, next.revalidate is the maximum lifetime in seconds: false means cache indefinitely, 0 prevents caching, and a number sets an upper bound. Route-segment controls such as dynamic, fetchCache, and revalidate are also part of the previous model. The lowest relevant revalidation setting can cause a route to revalidate more frequently than a particular fetch’s setting.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

To invalidate tagged fetch data on demand, attach tags and call the corresponding invalidation API from an appropriate server-side action or route handler:

const response = await fetch('https://api.example.com/posts', {
  next: { tags: ['posts'] },
})

// In a server-side action or route handler after a content change:
revalidateTag('posts')

revalidatePath is the path-targeted alternative. These invalidation examples belong to the previous model; do not combine them casually with Cache Components examples. Development behavior can differ from production, so a refresh in the development server is not proof of production cache hits or revalidation timing.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

What changes when you self-host Next.js?

The default self-hosted server cache is local to each instance. That can suit one persistent next start instance, but it is not shared automatically across several instances. If an instance is ephemeral, requests can land on different instances, or a CDN or reverse proxy sits in front of the app, review cache storage, custom cache handlers, and invalidation coordination as part of the architecture.

  • One persistent instance: the local filesystem cache may be sufficient for the documented default setup.
  • Multiple instances: plan how cached data and invalidations stay consistent between instances; local caches alone do not coordinate them.
  • Ephemeral compute: account for cache loss when instances are replaced and assess whether shared storage or a custom handler is needed.
  • CDN or reverse proxy: account for the additional cache layer when setting lifetimes and deciding how updates invalidate or refresh content.

These deployment cases call for reviewing the cache architecture; they do not imply that every Next.js site needs a paid caching service.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.