gavmac00/nextjs-app-docs huggingface dataset:
<button onClick={() => setShowMore(!showMore)}>Toggle</button>
 
      {/* Load only on the client side */}
      <ComponentC />
    </div>
  )
}Skipping SSR
When using React.lazy() and Suspense, Client Components will be pre-rendered (SSR) by default.If you want to disable pre-rendering for a Client Component, you can use the ssr option set to false: const ComponentC = dynamic(() => import('../components/C'), { ssr: false })Importing Server Components
If you dynamically import a Server Component, only the Client Components that are children of the Server Component will be lazy-loaded - not the Server Component itself.app/page.js import dynamic from 'next/dynamic'
 
// Server Component:
const ServerComponent = dynamic(() => import('../components/ServerComponent'))
 
export default function ServerComponentExample() {
  return (
    <div>
export default function ServerComponentExample() {
  return (
    <div>
      <ServerComponent />
    </div>
  )
}Loading External Libraries
External libraries can be loaded on demand using the import() function. This example uses the external library fuse.js for fuzzy search. The module is only loaded on the client after the user types in the search input.app/page.js 'use client'
 
import { useState } from 'react'
 
const names = ['Tim', 'Joe', 'Bel', 'Lee']
 
export default function Page() {
  const [results, setResults] = useState()
 
  return (
    <div>
      <input
        type="text"
        placeholder="Search"
        onChange={async (e) => {
          const { value } = e.currentTarget
          // Dynamically load fuse.js
const { value } = e.currentTarget
          // Dynamically load fuse.js
          const Fuse = (await import('fuse.js')).default
          const fuse = new Fuse(names)
 
          setResults(fuse.search(value))
        }}
      />
      <pre>Results: {JSON.stringify(results, null, 2)}</pre>
    </div>
  )
}Adding a custom loading component
app/page.js import dynamic from 'next/dynamic'
 
const WithCustomLoading = dynamic(
  () => import('../components/WithCustomLoading'),
  {
    loading: () => <p>Loading...</p>,
  }
)
 
export default function Page() {
  return (
    <div>
      {/* The loading component will be rendered while  <WithCustomLoading/> is loading */}
      <WithCustomLoading />
    </div>
  )
<WithCustomLoading />
    </div>
  )
}Importing Named Exports
To dynamically import a named export, you can return it from the Promise returned by import() function:components/hello.js 'use client'
 
export function Hello() {
  return <p>Hello!</p>
}app/page.js import dynamic from 'next/dynamic'
 
const ClientComponent = dynamic(() =>
  import('../components/hello').then((mod) => mod.Hello)
)
Font Optimization
next/font will automatically optimize your fonts (including custom fonts) and remove external network requests for improved privacy and performance.
🎥 Watch: Learn more about how to use next/font → YouTube (6 minutes).
next/font includes built-in automatic self-hosting for any font file. This means you can optimally load web fonts with zero layout shift, thanks to the underlying CSS size-adjust property used.
This new font system also allows you to conveniently use all Google Fonts with performance and privacy in mind. CSS and font files are downloaded at build time and self-hosted with the rest of your static assets. No requests are sent to Google by the browser.
Google Fonts
Automatically self-host any Google Font. Fonts are included in the deployment and served from the same domain as your deployment. No requests are sent to Google by the browser.
Get started by importing the font you would like to use from next/font/google as a function. We recommend using variable fonts for the best performance and flexibility.
app/layout.tsx import { Inter } from 'next/font/google'
 
// If loading a variable font, you don't need to specify the font weight
const inter = Inter({
  subsets: ['latin'],
  display: 'swap',
})
 
export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en" className={inter.className}>
      <body>{children}</body>
    </html>
  )
}If you can't use a variable font, you will need to specify a weight:app/layout.tsx import { Roboto } from 'next/font/google'
 
const roboto = Roboto({
  weight: '400',
const roboto = Roboto({
  weight: '400',
  subsets: ['latin'],
  display: 'swap',
})
 
export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en" className={roboto.className}>
      <body>{children}</body>
    </html>
  )
}
You can specify multiple weights and/or styles by using an array:
app/layout.js const roboto = Roboto({
  weight: ['400', '700'],
  style: ['normal', 'italic'],
  subsets: ['latin'],
  display: 'swap',
})
Good to know: Use an underscore (_) for font names with multiple words. E.g. Roboto Mono should be imported as Roboto_Mono.
Specifying a subset
Specifying a subset
Google Fonts are automatically subset. This reduces the size of the font file and improves performance. You'll need to define which of these subsets you want to preload. Failing to specify any subsets while preload is true will result in a warning.
This can be done by adding it to the function call:
app/layout.tsx const inter = Inter({ subsets: ['latin'] })
View the Font API Reference for more information.
Using Multiple Fonts
You can import and use multiple fonts in your application. There are two approaches you can take.
The first approach is to create a utility function that exports a font, imports it, and applies its className where needed. This ensures the font is preloaded only when it's rendered:
app/fonts.ts import { Inter, Roboto_Mono } from 'next/font/google'
 
export const inter = Inter({
  subsets: ['latin'],
  display: 'swap',
})
subsets: ['latin'],
  display: 'swap',
})
 
export const roboto_mono = Roboto_Mono({
  subsets: ['latin'],
  display: 'swap',
})
app/layout.tsx import { inter } from './fonts'
 
export default function Layout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en" className={inter.className}>
      <body>
        <div>{children}</div>
      </body>
    </html>
  )
}app/page.tsx import { roboto_mono } from './fonts'
 
export default function Page() {
  return (
    <>
      <h1 className={roboto_mono.className}>My page</h1>
    </>
  )
}
</>
  )
}
In the example above, Inter will be applied globally, and Roboto Mono can be imported and applied as needed.
Alternatively, you can create a CSS variable and use it with your preferred CSS solution:
app/layout.tsx import { Inter, Roboto_Mono } from 'next/font/google'
import styles from './global.css'
 
const inter = Inter({
  subsets: ['latin'],
  variable: '--font-inter',
  display: 'swap',
})
 
const roboto_mono = Roboto_Mono({
  subsets: ['latin'],
  variable: '--font-roboto-mono',
  display: 'swap',
})
 
export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en" className={`${inter.variable} ${roboto_mono.variable}`}>
      <body>
        <h1>My App</h1>
        <div>{children}</div>
      </body>
    </html>
  )
}
app/global.css html {
  font-family: var(--font-inter);
}
 
h1 {
  font-family: var(--font-roboto-mono);
}
In the example above, Inter will be applied globally, and any <h1> tags will be styled with Roboto Mono.
Recommendation: Use multiple fonts conservatively since each new font is an additional resource the client has to download.
Local Fonts
Local Fonts
Import next/font/local and specify the src of your local font file. We recommend using variable fonts for the best performance and flexibility.
app/layout.tsx import localFont from 'next/font/local'
 
// Font files can be colocated inside of `app`
const myFont = localFont({
  src: './my-font.woff2',
  display: 'swap',
})
 
export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en" className={myFont.className}>
      <body>{children}</body>
    </html>
  )
}
If you want to use multiple files for a single font family, src can be an array:
 const roboto = localFont({
  src: [
    {
      path: './Roboto-Regular.woff2',
src: [
    {
      path: './Roboto-Regular.woff2',
      weight: '400',
      style: 'normal',
    },
    {
      path: './Roboto-Italic.woff2',
      weight: '400',
      style: 'italic',
    },
    {
      path: './Roboto-Bold.woff2',
      weight: '700',
      style: 'normal',
    },
    {
      path: './Roboto-BoldItalic.woff2',
      weight: '700',
      style: 'italic',
    },
  ],
})
View the Font API Reference for more information.
With Tailwind CSS
next/font can be used with Tailwind CSS through a CSS variable.
With Tailwind CSS
next/font can be used with Tailwind CSS through a CSS variable.
In the example below, we use the font Inter from next/font/google (you can use any font from Google or Local Fonts). Load your font with the variable option to define your CSS variable name and assign it to inter. Then, use inter.variable to add the CSS variable to your HTML document.
app/layout.tsx import { Inter, Roboto_Mono } from 'next/font/google'
 
const inter = Inter({
  subsets: ['latin'],
  display: 'swap',
  variable: '--font-inter',
})
 
const roboto_mono = Roboto_Mono({
  subsets: ['latin'],
  display: 'swap',
  variable: '--font-roboto-mono',
})
 
export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en" className={`${inter.variable} ${roboto_mono.variable}`}>
      <body>{children}</body>
    </html>
  )
}
Finally, add the CSS variable to your Tailwind CSS config:
tailwind.config.js /** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    './pages/**/*.{js,ts,jsx,tsx}',
    './components/**/*.{js,ts,jsx,tsx}',
    './app/**/*.{js,ts,jsx,tsx}',
  ],
  theme: {
    extend: {
      fontFamily: {
        sans: ['var(--font-inter)'],
        mono: ['var(--font-roboto-mono)'],
      },
    },
  },
},
    },
  },
  plugins: [],
}
You can now use the font-sans and font-mono utility classes to apply the font to your elements.
Preloading
When a font function is called on a page of your site, it is not globally available and preloaded on all routes. Rather, the font is only preloaded on the related routes based on the type of file where it is used:
If it's a unique page, it is preloaded on the unique route for that page.
If it's a layout, it is preloaded on all the routes wrapped by the layout.
If it's the root layout, it is preloaded on all routes.
Reusing fonts
If it's the root layout, it is preloaded on all routes.
Reusing fonts
Every time you call the localFont or Google font function, that font is hosted as one instance in your application. Therefore, if you load the same font function in multiple files, multiple instances of the same font are hosted. In this situation, it is recommended to do the following:
Call the font loader function in one shared file
Export it as a constant
Import the constant in each file where you would like to use this font
OpenTelemetry
Good to know: This feature is experimental, you need to explicitly opt-in by providing experimental.instrumentationHook = true; in your next.config.js.
Observability is crucial for understanding and optimizing the behavior and performance of your Next.js app.
As applications become more complex, it becomes increasingly difficult to identify and diagnose issues that may arise. By leveraging observability tools, such as logging and metrics, developers can gain insights into their application's behavior and identify areas for optimization. With observability, developers can proactively address issues before they become major problems and provide a better user experience. Therefore, it is highly recommended to use observability in your Next.js applications to improve performance, optimize resources, and enhance user experience.
We recommend using OpenTelemetry for instrumenting your apps.
It's a platform-agnostic way to instrument apps that allows you to change your observability provider without changing your code.
Read Official OpenTelemetry docs for more information about OpenTelemetry and how it works.
This documentation uses terms like Span, Trace or Exporter throughout this doc, all of which can be found in the OpenTelemetry Observability Primer.
Next.js supports OpenTelemetry instrumentation out of the box, which means that we already instrumented Next.js itself.
When you enable OpenTelemetry we will automatically wrap all your code like getStaticProps in spans with helpful attributes.
Good to know: We currently support OpenTelemetry bindings only in serverless functions.
We don't provide any for edge or client side code.
Getting Started
OpenTelemetry is extensible but setting it up properly can be quite verbose.
That's why we prepared a package @vercel/otel that helps you get started quickly.
It's not extensible and you should configure OpenTelemetry manually if you need to customize your setup.
Using @vercel/otel
Using @vercel/otel
To get started, you must install @vercel/otel:
Terminal npm install @vercel/otel
Next, create a custom instrumentation.ts (or .js) file in the root directory of the project (or inside src folder if using one):
your-project/instrumentation.ts import { registerOTel } from '@vercel/otel'
 
export function register() {
  registerOTel('next-app')
}
Good to know
The instrumentation file should be in the root of your project and not inside the app or pages directory. If you're using the src folder, then place the file inside src alongside pages and app.
If you use the pageExtensions config option to add a suffix, you will also need to update the instrumentation filename to match.
We have created a basic with-opentelemetry example that you can use.
Manual OpenTelemetry configuration
Manual OpenTelemetry configuration
If our wrapper @vercel/otel doesn't suit your needs, you can configure OpenTelemetry manually.
Firstly you need to install OpenTelemetry packages:
Terminal npm install @opentelemetry/sdk-node @opentelemetry/resources @opentelemetry/semantic-conventions @opentelemetry/sdk-trace-node @opentelemetry/exporter-trace-otlp-http
Now you can initialize NodeSDK in your instrumentation.ts.
OpenTelemetry APIs are not compatible with edge runtime, so you need to make sure that you are importing them only when process.env.NEXT_RUNTIME === 'nodejs'. We recommend creating a new file instrumentation.node.ts which you conditionally import only when using node:
instrumentation.ts export async function register() {
  if (process.env.NEXT_RUNTIME === 'nodejs') {
    await import('./instrumentation.node.ts')
  }
}
await import('./instrumentation.node.ts')
  }
}
instrumentation.node.ts import { NodeSDK } from '@opentelemetry/sdk-node'
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'
import { Resource } from '@opentelemetry/resources'
import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions'
import { SimpleSpanProcessor } from '@opentelemetry/sdk-trace-node'
 
const sdk = new NodeSDK({
  resource: new Resource({
    [SemanticResourceAttributes.SERVICE_NAME]: 'next-app',
  }),
  spanProcessor: new SimpleSpanProcessor(new OTLPTraceExporter()),
})
sdk.start()
Doing this is equivalent to using @vercel/otel, but it's possible to modify and extend.
For example, you could use @opentelemetry/exporter-trace-otlp-grpc instead of @opentelemetry/exporter-trace-otlp-http or you can specify more resource attributes.
Testing your instrumentation
You need an OpenTelemetry collector with a compatible backend to test OpenTelemetry traces locally.
We recommend using our OpenTelemetry dev environment.
If everything works well you should be able to see the root server span labeled as GET /requested/pathname.
All other spans from that particular trace will be nested under it.
Next.js traces more spans than are emitted by default.
To see more spans, you must set NEXT_OTEL_VERBOSE=1.
Deployment
Using OpenTelemetry Collector
When you are deploying with OpenTelemetry Collector, you can use @vercel/otel.
It will work both on Vercel and when self-hosted.
Deploying on Vercel
Deploying on Vercel
We made sure that OpenTelemetry works out of the box on Vercel.
Follow Vercel documentation to connect your project to an observability provider.
Self-hosting
Deploying to other platforms is also straightforward. You will need to spin up your own OpenTelemetry Collector to receive and process the telemetry data from your Next.js app.
To do this, follow the OpenTelemetry Collector Getting Started guide, which will walk you through setting up the collector and configuring it to receive data from your Next.js app.
Once you have your collector up and running, you can deploy your Next.js app to your chosen platform following their respective deployment guides.
Custom Exporters
We recommend using OpenTelemetry Collector.
If that is not possible on your platform, you can use a custom OpenTelemetry exporter with manual OpenTelemetry configuration
Custom Spans
You can add a custom span with OpenTelemetry APIs.
Custom Spans
You can add a custom span with OpenTelemetry APIs.
Terminal npm install @opentelemetry/api
The following example demonstrates a function that fetches GitHub stars and adds a custom fetchGithubStars span to track the fetch request's result:
 import { trace } from '@opentelemetry/api'
 
export async function fetchGithubStars() {
  return await trace
    .getTracer('nextjs-example')
    .startActiveSpan('fetchGithubStars', async (span) => {
      try {
        return await getValue()
      } finally {
        span.end()
      }
    })
}
The register function will execute before your code runs in a new environment.
You can start creating new spans, and they should be correctly added to the exported trace.
Default Spans in Next.js
Next.js automatically instruments several spans for you to provide useful insights into your application's performance.
Next.js automatically instruments several spans for you to provide useful insights into your application's performance.
Attributes on spans follow OpenTelemetry semantic conventions. We also add some custom attributes under the next namespace:
next.span_name - duplicates span name
next.span_type - each span type has a unique identifier
next.route - The route pattern of the request (e.g., /[param]/user).
next.page
This is an internal value used by an app router.
You can think about it as a route to a special file (like page.ts, layout.ts, loading.ts and others)
It can be used as a unique identifier only when paired with next.route because /layout can be used to identify both /(groupA)/layout.ts and /(groupB)/layout.ts
[http.method] [next.route]
next.span_type: BaseServer.handleRequest
[http.method] [next.route]
next.span_type: BaseServer.handleRequest
This span represents the root span for each incoming request to your Next.js application. It tracks the HTTP method, route, target, and status code of the request.
Attributes:
Common HTTP attributes
http.method
http.status_code
Server HTTP attributes
http.route
http.target
next.span_name
next.span_type
next.route
render route (app) [next.route]
next.span_type: AppRender.getBodyResult.
This span represents the process of rendering a route in the app router.
Attributes:
next.span_name
next.span_type
next.route
fetch [http.method] [http.url]
next.span_type: AppRender.fetch
This span represents the fetch request executed in your code.
Attributes:
Common HTTP attributes
http.method
Client HTTP attributes
http.url
net.peer.name
net.peer.port (only if specified)
next.span_name
http.url
net.peer.name
net.peer.port (only if specified)
next.span_name
next.span_type
executing api route (app) [next.route]
next.span_type: AppRouteRouteHandlers.runHandler.
This span represents the execution of an API route handler in the app router.
Attributes:
next.span_name
next.span_type
next.route
getServerSideProps [next.route]
next.span_type: Render.getServerSideProps.
This span represents the execution of getServerSideProps for a specific route.
Attributes:
next.span_name
next.span_type
next.route
getStaticProps [next.route]
next.span_type: Render.getStaticProps.
This span represents the execution of getStaticProps for a specific route.
Attributes:
next.span_name
next.span_type
next.route
render route (pages) [next.route]
next.span_type: Render.renderDocument.
render route (pages) [next.route]
next.span_type: Render.renderDocument.
This span represents the process of rendering the document for a specific route.
Attributes:
next.span_name
next.span_type
next.route
generateMetadata [next.page]
next.span_type: ResolveMetadata.generateMetadata.
This span represents the process of generating metadata for a specific page (a single route can have multiple of these spans).
Attributes:
next.span_name
next.span_type
next.page
Image Optimization
Examples
Image Component
According to Web Almanac, images account for a huge portion of the typical website’s page weight and can have a sizable impact on your website's LCP performance.
The Next.js Image component extends the HTML <img> element with features for automatic image optimization:
Size Optimization: Automatically serve correctly sized images for each device, using modern image formats like WebP and AVIF.
Visual Stability: Prevent layout shift automatically when images are loading.
Faster Page Loads: Images are only loaded when they enter the viewport using native browser lazy loading, with optional blur-up placeholders.
Asset Flexibility: On-demand image resizing, even for images stored on remote servers
🎥 Watch: Learn more about how to use next/image → YouTube (9 minutes).
Usage
 import Image from 'next/image'
You can then define the src for your image (either local or remote).
Local Images
You can then define the src for your image (either local or remote).
Local Images
To use a local image, import your .jpg, .png, or .webp image files.
Next.js will automatically determine the width and height of your image based on the imported file. These values are used to prevent Cumulative Layout Shift while your image is loading.
app/page.js import Image from 'next/image'
import profilePic from './me.png'
 
export default function Page() {
  return (
    <Image
      src={profilePic}
      alt="Picture of the author"
      // width={500} automatically provided
      // height={500} automatically provided
      // blurDataURL="data:..." automatically provided
      // placeholder="blur" // Optional blur-up while loading
    />
  )
}
/>
  )
}
Warning: Dynamic await import() or require() are not supported. The import must be static so it can be analyzed at build time.
Remote Images
To use a remote image, the src property should be a URL string.
Since Next.js does not have access to remote files during the build process, you'll need to provide the width, height and optional blurDataURL props manually.
The width and height attributes are used to infer the correct aspect ratio of image and avoid layout shift from the image loading in. The width and height do not determine the rendered size of the image file. Learn more about Image Sizing.
app/page.js import Image from 'next/image'
 
export default function Page() {
  return (
    <Image
      src="https://s3.amazonaws.com/my-bucket/profile.png"
      alt="Picture of the author"
      width={500}
      height={500}
width={500}
      height={500}
    />
  )
}
To safely allow optimizing images, define a list of supported URL patterns in next.config.js. Be as specific as possible to prevent malicious usage. For example, the following configuration will only allow images from a specific AWS S3 bucket:
next.config.js module.exports = {
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 's3.amazonaws.com',
        port: '',
        pathname: '/my-bucket/**',
      },
    ],
  },
}
Learn more about remotePatterns configuration. If you want to use relative URLs for the image src, use a loader.
Domains