Next.js can generate Open Graph images in two ways: add a static image named opengraph-image to a route segment, or create an opengraph-image.tsx route that returns an image with ImageResponse from next/og. Use a static file for fixed artwork and a generated route when the image needs to change with a page, such as a blog post title or author. Next.js adds the corresponding image metadata tags for either approach.
Choose a static image or a generated route
| Approach | Use it when | What to know |
|---|---|---|
Static opengraph-image asset |
The artwork is the same for every page in a route segment. | Next.js recognizes supported image files by convention and adds metadata. A more specific image lower in the route hierarchy takes precedence over an image in a parent segment. |
Generated opengraph-image.js, .ts, or .tsx |
The image should incorporate route-specific or data-driven content. | Use ImageResponse from next/og. The route can export image alt text, size, and content type. |
The static option avoids maintaining a rendering route; the generated option avoids manually creating a separate image for every content item. Neither choice is universally better: decide based on whether the image varies and whether the design can be expressed with the renderer’s supported CSS.
Where the file goes
Put the image file or generated route in the route segment it describes. For example, a site-wide image can live at the app route root, while a post-specific generator belongs alongside that post route’s metadata. A more specific segment image overrides the one inherited from a higher folder. This lets a site use a general default and provide dedicated images only where they add value.
Generate a route-specific image with ImageResponse
Create an opengraph-image.tsx file in the relevant route segment and return an ImageResponse. The example below builds a 1200-by-630 PNG from a post slug. It assumes the application has a getPost function that returns a post with a title; connect that function to the project’s own data layer.
Windows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallCrashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minute#1 Best Overall
import { ImageResponse } from 'next/og'
export const alt = 'Article social preview'
export const size = {
width: 1200,
height: 630,
}
export const contentType = 'image/png'
type Props = {
params: Promise<{ slug: string }>
}
export default async function OpenGraphImage({ params }: Props) {
const { slug } = await params
const post = await getPost(slug)
return new ImageResponse(
(
<div
style={{
width: '100%',
height: '100%',
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
padding: '64px',
background: '#101827',
color: '#ffffff',
fontSize: 64,
}}
>
<div style={{ display: 'flex', fontSize: 28 }}>Freedom251</div>
<div style={{ display: 'flex', marginTop: 32 }}>{post.title}</div>
</div>
),
size,
)
}
The getPost call is intentionally application-specific: Next.js can provide route parameters, but no particular database, CMS, or content API is required. Add an explicit not-found or fallback behavior appropriate to that data source if a slug has no post, rather than assuming the post always exists.
Metadata exports and image dimensions
The route can export alt, size, and contentType so the image has descriptive metadata, dimensions, and a MIME type. The official generated-image example uses 1200×630 pixels and image/png. Treat that as a documented example configuration, not as proof that every social platform requires those dimensions.
The displayed title is external content. Ensure it fits the composition: long headings can dominate a fixed-size image. A practical design should reserve space for a title, test representative short and long titles, and avoid assuming arbitrary browser CSS will work in the renderer.
Rank #2
Use route data, local fonts, and nested images
A generated image can incorporate route parameters or external data, which is how one implementation can create distinct previews for different posts. The current documentation’s dynamic route example types params as a promise. Resolve it before reading the slug, as shown above. Do not copy an older example’s signature without checking the installed Next.js version.
The official guide also demonstrates loading a local font and using nested images in the generated composition. These assets can make the output match a site’s branding, but they add implementation and bundle considerations. An older Next.js 15 ImageResponse page documents a 500 KB maximum bundle size; because that is version-specific older documentation, verify the limit against the version in the project before relying on it.
For nested images, the docs show loading a local image from the project and passing its data to the renderer. They note that using an ArrayBuffer as an <img src> is not part of the HTML specification even though next/og supports it, so TypeScript may require a targeted typing workaround. Keep any suppression narrow and document why it exists.
Rank #3
Understand CSS and output constraints
The documented rendering pipeline uses @vercel/og, Satori, and resvg to convert JSX and CSS into PNG. It is not a full browser layout engine: the supported CSS is a subset, and flexbox is supported while CSS Grid should not be assumed to work. Build the composition from supported layout primitives and validate the rendered result rather than porting a complex browser page unchanged.
Static image files supported by the convention include JPG/JPEG, PNG, and GIF. Next.js documents a maximum static Open Graph image file size of 8 MB and a maximum Twitter image file size of 5 MB; exceeding the static OG limit causes the build to fail. These are framework convention limits, not general platform upload limits. Compress or resize static assets when needed, and distinguish the static-file limits from generated route behavior.
Control freshness and caching
Generated images are statically optimized and cached by default unless the route uses Dynamic APIs or dynamic configuration. Static metadata files and special metadata handlers are also documented as cached by default. This matters when image text or imagery comes from content that changes after deployment: a cached or statically generated preview may not immediately reflect an edit.
Choose the behavior based on how fresh the preview must be. If a title is expected to remain stable for a deployment, default optimization may suit it. If the content changes and the image must reflect those changes, examine the route’s data access, fetch options, and route-segment configuration in the documentation for the project’s version. External-data examples can alter static optimization depending on fetch options or route configuration. Do not add dynamic behavior casually; it changes the rendering and caching trade-off.
Generate more than one image variant
Use generateImageMetadata when a route segment should describe multiple image variants. Each returned metadata object needs an id, and the image generator receives the matching ID so it can produce the corresponding variant. This is useful when variants differ in a defined way, rather than trying to infer an image version from unrelated request state.
Check the framework version before implementing this API. The current documentation’s version history says Next.js 16 changed both params and the image generator’s id to promises. Examples written for earlier versions may therefore have different signatures. Use the documentation corresponding to the installed version rather than mixing signatures across releases.
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Test the result in the app
- Choose the route segment. Place a static asset or generated image file at the segment whose pages it should describe.
- Run the application or build. Confirm the route resolves and any data lookup works for a real content item.
- Inspect the image itself. Check that the title, font, colors, and any nested images appear within the intended dimensions, including for unusually long content.
- Inspect page metadata. Confirm the page’s generated metadata points to the intended image and that the route-specific image takes precedence where expected.
- Test a missing or malformed slug. Ensure the data lookup fails in a controlled way instead of returning a misleading image or an unhandled error.
- Revisit after changing content. Verify that the caching behavior matches the freshness the site requires.
For a screenshot of a page rendering, remember that an OG image route itself returns an image; screenshotting is a separate check of the page that embeds the metadata. A rendered browser screenshot can help inspect the page, but it does not substitute for checking the generated image route and its metadata.
Troubleshoot common implementation problems
- The parent image appears instead of the post image: check that the file is in the intended route segment and that the more specific route segment contains the recognized convention name.
- The layout differs from a browser mockup: check for CSS outside the renderer’s supported subset. Rework the composition using supported flexbox-style layout rather than relying on CSS Grid or general browser behavior.
- The output is stale after content changes: review whether the route is statically optimized or cached by default, and whether its data-fetching and route configuration make it dynamic.
- The build fails for a static image: verify the format and the documented 8 MB static Open Graph image limit; the docs also state a 5 MB Twitter-image limit.
- TypeScript rejects an image source: when using the documented ArrayBuffer approach for nested images, account for the typing mismatch narrowly; the renderer support does not make that value part of the HTML specification.
- A copied example has type errors around parameters or IDs: check the Next.js version. Next.js 16 documents promise-based
paramsand image-generatoridsignatures. - A title or asset is missing: verify the route parameter and the application-specific data lookup independently, then decide how the route should handle absent content.
Or skip the browser setup
To capture a page screenshot for visual QA, ScreenshotNeo offers a one-request screenshot API; it is separate from Next.js’s OG image generation and does not replace configuring the metadata route. See the ScreenshotNeo website and API documentation.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before capture; those steps can be turned off. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP server offers screenshot and PDF tools to AI agents. The Free plan includes 1,000 shots a month with no card; paid plans start at $5 for 3,000 shots. Sign up for the free plan.
Frequently Asked Questions
Can I use a static image for one page and generated images for others?
Yes. Put the static asset or generator in the route segment it should describe; a more specific segment image takes precedence over a parent image.
Recommended Free Tools
Does the 1200×630 example mean every social platform requires that size?
No. It is the size used in the Next.js generated-image example, not a universal platform requirement.
Do Next.js generated OG images support every CSS feature?
No. The renderer supports a subset of CSS; flexbox is supported, and CSS Grid should not be assumed to work.
Quick Recap
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.

