For a cover image that changes with each blog post, add an opengraph-image.tsx file under the post’s dynamic route, load that post’s data, and return a Next.js ImageResponse. For a prepared image shared by a route, use a static opengraph-image.jpg instead. Next.js’s file convention connects either option to the route’s social metadata automatically.
Choose a static image or generate one from post data
| Approach | Use it when | Trade-off |
|---|---|---|
Static opengraph-image.jpg |
You already have a suitable image and do not need the cover to vary based on post data. | Simpler to manage, but each distinct post cover must be prepared as an asset. |
Generated opengraph-image.tsx |
You want titles or other post data to produce individual covers from a shared design. | Requires a route that loads the post and renders it; the output must fit ImageResponse’s supported CSS subset. |
Next.js supports literal image files and programmatic generation through its metadata file convention. More specific files deeper in the route tree take precedence over higher-level Open Graph images. See the Next.js Open Graph image file convention.
As an Amazon Associate I earn from qualifying purchases.
Generate a cover for each post in the App Router
Place the image route alongside the page for a dynamic blog post:
app/
blog/
[slug]/
page.tsx
opengraph-image.tsx
The route can resolve the slug, retrieve the matching post, and render a design using its title and other fields. The following example assumes your project has a getPost(slug) function that returns a post with a title property, or null when there is no matching post. Adapt parameter typing and data access to your installed Next.js version and project.
#1 Best Overall
- HTML CSS Design and Build Web Sites
- Comes with secure packaging
- It can be a gift option
import { ImageResponse } from 'next/og'
import { getPost } from '@/lib/posts'
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 getPost(slug)
if (!post) {
throw new Error(`Post not found: ${slug}`)
}
return new ImageResponse(
(
<div
style={{
width: '100%',
height: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
padding: '64px',
background: '#111827',
color: '#ffffff',
fontSize: 64,
fontWeight: 700,
textAlign: 'center',
}}
>
{post.title}
</div>
),
size,
)
}
The route parameter type shown is illustrative; Next.js route parameter typing differs across versions. Follow the API and route conventions for the version installed in your project. The current App Router guide’s generated-image example exports a 1200-by-630 size and PNG content type, and Next.js generates the relevant head metadata for the file convention. This is a documented example size, not a guarantee that every social platform requires it. See the Next.js guide to metadata and OG images.
Keep the design within ImageResponse’s supported CSS
ImageResponse renders JSX with a subset of CSS, not the full browser layout engine. The documented approach supports flexbox and absolute positioning, along with text wrapping, custom fonts, and nested images. CSS Grid is specifically identified as unsupported. Build the design with supported styles, then inspect the generated result in your own project rather than assuming arbitrary browser CSS will render as expected.
The documented rendering pipeline uses @vercel/og, Satori, and resvg to convert HTML and CSS to PNG. For API details and version-specific constraints, consult the Next.js 15 ImageResponse reference; the current App Router guide should remain your starting point for the main workflow.
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Use a static cover when you do not need route-based rendering
For a prepared image, put a supported literal image file in the relevant app directory, for example:
Rank #3
app/blog/opengraph-image.jpg
For a single post, the file can instead sit in that post’s directory. Deeper route files are more specific and take precedence over higher-level images. The metadata file convention handles the associated head tags, so a separate hand-written Open Graph tag is not required just to make this file convention work.
Understand when generated covers update
Generated metadata images are statically optimized and cached by default. They are not necessarily rendered anew for every request. Dynamic APIs, uncached data, or route configuration can change the rendering behavior, so decide how fresh a cover must be when choosing how post data is fetched and cached. If a title or design changes, verify that the route’s caching and deployment behavior will produce the updated image rather than assuming a new image is created immediately on each visit. Next.js explains these defaults in its file convention documentation.
Rank #4
- Brand: Wiley
- Set of 2 Volumes
- A handy two-book set that uniquely combines related technologies Highly visual format and accessible language makes these books highly effective learning tools Perfect for beginning web designers and front-end developers
Do not confuse OG generation with next/image
next/image is for images rendered in page content, where image sizing, layout stability, lazy loading, and remote image resizing may matter. It is not the documented API for generating a post-specific Open Graph cover. Use the metadata file convention with ImageResponse for generated social images. See the Next.js image optimization guide for the separate page-image feature.
Free tools Windows power users keep installed
One-click scans. No signup required.
Troubleshoot common problems
- The image uses the wrong post title: Check that the route reads the slug from the dynamic segment and that the data lookup returns the post for that slug, not a shared or default record.
- The image route fails for a missing post: Make the data lookup’s missing-post behavior explicit. The example throws when no post is found; adapt that behavior to your application’s route and error-handling conventions.
- The layout differs from the page’s browser rendering: ImageResponse supports only a CSS subset. Replace unsupported layout techniques such as Grid with documented styles, and inspect the generated image.
- A cover does not reflect a recent content change: Check the route’s static optimization, data caching, and dynamic configuration. Static generation and caching are defaults, not a promise of per-request regeneration.
- A page image appears, but the social preview is missing: Confirm the image file or route uses the metadata convention in the relevant App Router directory, and inspect the route’s generated metadata.
next/imagealone does not create OG metadata. - TypeScript rejects the route parameters: The parameter typing in the sample may not match your Next.js version. Use the installed version’s route conventions and adapt the type rather than copying it unchanged.
Or skip the browser setup
If you need a screenshot of a rendered page rather than a code-generated social cover, ScreenshotNeo is a website screenshot API and MCP server. One request can return a screenshot or PDF; for a WebP shot, use:
Quick Recap
Best Value
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
See the ScreenshotNeo API documentation for parameters and response details. It removes cookie banners, newsletter popups, and chat widgets before capture; bot checks, blank pages, and failed loads are not billed. Its MCP server lets AI agents take screenshots, and the free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Sign up for 1,000 free screenshots a month, no card required.
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.




