opengraph-image and twitter-image file conventions overview
The opengraph-image and twitter-image file conventions allow you to set Open Graph and Twitter images for a route segment. They are useful for setting the images that appear on social networks and messaging apps when a user shares a link to your site. There are two ways to set these images: using image files (.jpg, .png, .gif) or using code to generate images (.js, .ts, .tsx).
Image file types for opengraph-image and twitter-image
The opengraph-image file convention supports .jpg, .jpeg, .png, and .gif file types. The twitter-image file convention supports .jpg, .jpeg, .png, and .gif file types. The opengraph-image.alt and twitter-image.alt file conventions support .txt file type only.
File size limits for shared images
The twitter-image file size must not exceed 5MB, and the opengraph-image file size must not exceed 8MB. If the image file size exceeds these limits, the build will fail.
opengraph-image meta tags generated in head
When an opengraph-image.(jpg|jpeg|png|gif) image file is added to a route segment, Next.js automatically adds the following tags to the app's <head> element: <meta property="og:image" content="<generated>" />, <meta property="og:image:type" content="<generated>" />, <meta property="og:image:width" content="<generated>" />, and <meta property="og:image:height" content="<generated>" />.
twitter-image meta tags generated in head
When a twitter-image.(jpg|jpeg|png|gif) image file is added to a route segment, Next.js automatically adds the following tags to the app's <head> element: <meta name="twitter:image" content="<generated>" />, <meta name="twitter:image:type" content="<generated>" />, <meta name="twitter:image:width" content="<generated>" />, and <meta name="twitter:image:height" content="<generated>" />.
Using alt text with opengraph-image.alt.txt
Add an accompanying opengraph-image.alt.txt file in the same route segment as the opengraph-image.(jpg|jpeg|png|gif) image to specify its alt text. The file contains plain text, such as 'About Acme', and generates the meta tag <meta property="og:image:alt" content="About Acme" /> in the head.
Using alt text with twitter-image.alt.txt
Add an accompanying twitter-image.alt.txt file in the same route segment as the twitter-image.(jpg|jpeg|png|gif) image to specify its alt text. The file contains plain text, such as 'About Acme', and generates the meta tag <meta name="twitter:image:alt" content="About Acme" /> in the head.
Generate images using code with .js, .ts, .tsx
Generate a route segment's shared image by creating an opengraph-image or twitter-image route that default exports a function. The opengraph-image and twitter-image file conventions support .js, .ts, and .tsx file types for code-based image generation.
Generated images static optimization by default
By default, generated images are statically optimized (generated at build time and cached) unless they use Request-time APIs or uncached data.
Generate multiple images with generateImageMetadata
You can generate multiple images in the same file using the generateImageMetadata function.
opengraph-image.js and twitter-image.js caching behavior
opengraph-image.js and twitter-image.js are special Route Handlers that are cached by default unless they use a Request-time API or dynamic config option.
ImageResponse API for generating images
The ImageResponse API from the next/og package is the easiest way to generate images for opengraph-image and twitter-image routes. It returns a Response object and accepts JSX content with styling options and configuration.
opengraph-image and twitter-image function props
The default export function for opengraph-image and twitter-image receives an optional params prop. params is a promise that resolves to an object containing the dynamic route parameters from the root segment down to the segment where opengraph-image or twitter-image is colocated.
params prop in generated image function with dynamic routes
For route app/shop/opengraph-image.js with URL /shop, params is undefined. For route app/shop/[slug]/opengraph-image.js with URL /shop/1, params is Promise<{ slug: '1' }>. For route app/shop/[tag]/[item]/opengraph-image.js with URL /shop/1/2, params is Promise<{ tag: '1', item: '2' }>.
opengraph-image and twitter-image return type
The default export function for opengraph-image and twitter-image should return a Response. ImageResponse satisfies this return type.
Config exports for image metadata
You can optionally configure the image's metadata by exporting alt, size, and contentType variables from opengraph-image or twitter-image route. alt is a string, size is an object with width and height numbers, and contentType is a string specifying the image MIME type.
alt config export for images
Export a const alt with a string value from opengraph-image or twitter-image to set alternate text. This generates <meta property="og:image:alt" content="My images alt text" /> in the head.
size config export for images
Export a const size with an object containing width and height number properties from opengraph-image or twitter-image to set image dimensions. For example: export const size = { width: 1200, height: 630 }. This generates <meta property="og:image:width" content="1200" /> and <meta property="og:image:height" content="630" /> in the head.
contentType config export for images
Export a const contentType with a string value specifying the MIME type from opengraph-image or twitter-image. For example: export const contentType = 'image/png'. This generates <meta property="og:image:type" content="image/png" /> in the head.
Route Segment Config for opengraph-image and twitter-image
opengraph-image and twitter-image are specialized Route Handlers that can use the same route segment configuration options as Pages and Layouts.
Example: generating image with external data and params
import { ImageResponse } from 'next/og'
export const alt = 'About Acme'
export const size = {
width: 1200,
height: 630,
}
export const contentType = 'image/png'
export default async function Image({
params,
}: {
params: Promise<{ slug: string }>
}) {
const { slug } = await params
const post = await fetch(`https://.../posts/${slug}`).then((res) =>
res.json()
)
return new ImageResponse(
(
<div
style={{
fontSize: 48,
background: 'white',
width: '100%',
height: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
>
{post.title}
</div>
),
{
...size,
}
)
}
This example demonstrates using the params object to fetch external data and dynamically generate an image based on route parameters.
Example: generating image with local assets as base64
import { ImageResponse } from 'next/og'
import { join } from 'node:path'
import { readFile } from 'node:fs/promises'
const logoData = await readFile(join(process.cwd(), 'logo.png'), 'base64')
const logoSrc = `data:image/png;base64,${logoData}`
export default async function Image() {
return new ImageResponse(
(
<div
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
>
<img src={logoSrc} height="100" />
</div>
)
)
}
This example shows how to read a local image file from the file system and pass it to ImageResponse as a base64-encoded string. The asset is read at module scope so it doesn't depend on request data.
Example: generating image with local assets as ArrayBuffer
import { ImageResponse } from 'next/og'
import { join } from 'node:path'
import { readFile } from 'node:fs/promises'
const logoData = await readFile(join(process.cwd(), 'logo.png'))
const logoSrc = Uint8Array.from(logoData).buffer
export default async function Image() {
return new ImageResponse(
(
<div
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
>
{/* @ts-expect-error Satori accepts ArrayBuffer/typed arrays for <img src> at runtime */}
<img src={logoSrc} height="100" />
</div>
)
)
}
This example shows how to pass a local image file as an ArrayBuffer to the img src attribute. A @ts-expect-error directive is needed because passing ArrayBuffer to img src is not part of the HTML spec, though the rendering engine used by next/og supports it.
Example: basic ImageResponse with custom fonts
import { ImageResponse } from 'next/og'
import { readFile } from 'node:fs/promises'
import { join } from 'node:path'
export const alt = 'About Acme'
export const size = {
width: 1200,
height: 630,
}
export const contentType = 'image/png'
const interSemiBold = await readFile(
join(process.cwd(), 'assets/Inter-SemiBold.ttf')
)
export default async function Image() {
return new ImageResponse(
(
<div
style={{
fontSize: 128,
background: 'white',
width: '100%',
height: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
>
About Acme
</div>
),
{
...size,
fonts: [
{
name: 'Inter',
data: interSemiBold,
style: 'normal',
weight: 400,
},
],
}
)
}
This example demonstrates creating an ImageResponse with custom fonts loaded from the file system.
generateImageMetadata receives id prop
If you use generateImageMetadata, the image generation function will also receive an id prop that is a promise resolving to the id value from one of the items returned by generateImageMetadata.
Static optimization note for external data in generated images
By default, generated images that use external data via fetch will be statically optimized. You can configure the individual fetch options or route segment options to change this behavior, such as using revalidate to enable ISR or other caching strategies.
Version history: params now a promise
In Next.js v16.0.0, the params prop is now a promise that resolves to an object, rather than being a direct object.
Version history: opengraph-image and twitter-image introduced
The opengraph-image and twitter-image file conventions were introduced in Next.js v13.3.0.
Layout definition and behavior
A Layout is UI that is shared between multiple pages. Layouts preserve state, remain interactive, and do not re-render on navigation. Layouts are defined by exporting a React component from a layout.js file.
Loading UI creation with loading.js
Loading UI is fallback UI shown while a route segment is loading. It is created by adding a loading.js file to a folder, which automatically wraps the page in a Suspense boundary.
Page definition
A Page is UI that is unique to a route. It is defined by exporting a React component from a page.js file within the app directory.
instant validation default behavior
By default with `validationLevel: 'warning'`, Cache Components apps validate every Page and Default segment in development. This can be configured via `experimental.instantInsights.validationLevel` in next.config.js.
instant route segment config overview
The `instant` route segment config controls how Next.js validates whether a navigation into a segment would produce an instant UI. It works with prefetching to help build fast-feeling navigations by letting you declare whether navigations into a segment should produce UI that renders instantly without waiting on externally loaded data, or whether navigations aren't expected to be instant.
instant export basic usage
Export `instant` as a constant from a layout.tsx, layout.js, page.tsx, or page.js file. It can be set to `true`, `false`, or an object with configuration options like `level`.
instant = true behavior
When `instant` is set to `true`, the segment opts into validation at whatever level is configured globally. With framework defaults, validation runs in development only and surfaces errors in the dev overlay.
instant = false disables validation
Setting `instant` to `false` on a layout or page indicates that the segment is allowed to block when navigating to it. This is useful when a deeper page should be instant but an ancestor cannot be. Set `false` only on blocking ancestors when you have configured a deeper page as instant.
instant level option
The `instant` export can be an object with a `level` property. The only currently available level is `'warning'`, which validates in development only and displays errors in the dev overlay without affecting the build. In the future, a validation level supporting build-time validation will be added.
instant requires cacheComponents enabled
The `instant` export only works when `cacheComponents` is enabled in next.config.js. It cannot be used in Client Components and will throw an error if attempted.
instant validation in development vs production
Next.js does not perform prefetches in development, so navigations may not feel as instant as they will in production. Validation reflects what will happen during `next start`, where prefetching is enabled.
static shell validation with instant false
Cache Components validates that each page produces a non-empty static shell at prerender time. To opt a route out of this validation, ensure the highest `instant` config in the route's tree is `false`. A `false` higher in the tree takes precedence over any deeper `true` for the static-shell check.
instant validation triggers at shared layout boundaries
The `instant` config triggers validation at every shared layout boundary in the route. Validation runs during development on page loads and HMR updates, and surfaces errors in the dev error overlay. Each error identifies the component that would block navigation.
instant TypeScript type definition
The TypeScript type for `instant` is `type InstantConfig = true | false | { level?: 'warning' }`. Export it as `export const instant: InstantConfig = true` or similar.
instant introduced in Next.js v16
The `instant` export was introduced in Next.js v16.x.x and is only available with Cache Components enabled.
instant validation fixes with use cache or Suspense
When validation identifies a component blocking navigation, the fix is usually to cache the data with `use cache` directive or wrap it in a `<Suspense>` boundary.
instant false at root layout disables static shell validation
Setting `instant = false` on the root layout disables static shell validation for the entire app. Place `false` as low as possible in the tree, only as high as needed to cover the routes you want to opt out, so the rest of the app continues validating.
instant ancestor configuration inheritance
A higher-up `instant = true` does not force its descendants to validate. Leaving an ancestor unconfigured is fine. You don't need to add `false` to ancestors of an instant page just because they do something blocking.
framework-synthesized routes excluded from implicit validation
Framework-synthesized error routes (`/_global-error`, `/_not-found`) are excluded from implicit validation. To validate them, opt in explicitly with `instant = true`.
instant validation level may change in future versions
The framework default validation level may change in future versions to opt users into higher levels of validation. Because this feature is experimental, that change is not considered a breaking change. To pin a specific behavior, set `validationLevel` explicitly in next.config.js.