Manoj
←Back to Blog
·4 min read

Generating Open Graph Images with Next.js

Generate consistent social preview images with Next.js metadata routes, ImageResponse, and a small reusable layout.

nextjsopen-graphseofrontend

Generating Open Graph Images with Next.js

A shared link often reaches a reader before the page itself does. Its preview image needs to explain the content quickly, remain readable at a small size, and look like it belongs to the site.

Creating every image by hand is manageable for a few pages. As the archive grows, a generated layout can keep the branding consistent while using the title and category of each article.

Start with the file convention

Next.js supports an opengraph-image.tsx metadata file inside an App Router segment. The file exports an image generator and can describe the image's dimensions, alternate text, and content type.

The framework connects that file to the page's metadata. Its Open Graph image reference explains the convention and static optimization behavior.

Use the default Node.js runtime for current Next.js versions. Avoid copying an old tutorial's runtime = "edge" export into a new implementation; the Edge Runtime is deprecated in the version used by this portfolio.

Build a small image first

This example can live at app/opengraph-image.tsx in a Next.js application. It uses named colors for a minimal image; a real site can source its palette from shared brand constants.

import { ImageResponse } from "next/og";

export const alt = "Developer notes on building reliable software";
export const size = { width: 1200, height: 630 };
export const contentType = "image/png";

const Image = () =>
  new ImageResponse(
    <div
      style={{
        width: "100%",
        height: "100%",
        display: "flex",
        flexDirection: "column",
        justifyContent: "center",
        padding: 80,
        background: "black",
        color: "white",
      }}
    >
      <div style={{ fontSize: 24 }}>DEVELOPER NOTES</div>
      <div style={{ fontSize: 64, marginTop: 24 }}>
        Building software that is easier to maintain
      </div>
    </div>,
    size,
  );

export default Image;

Begin with a title, a label, and enough padding. Decorative layers can wait until the simplest version renders reliably.

Image rendering has its own constraints

ImageResponse turns JSX and supported styles into an image; it is not a screenshot of your normal page. A browser layout that works with every CSS feature may not work unchanged in this renderer.

The ImageResponse documentation describes supported layout features, font formats, and bundle limits. Flexbox-based compositions are a practical starting point. Supply fonts explicitly if predictable typography matters, and keep font assets and other bundled resources small.

Do not assume Tailwind classes or your global stylesheet automatically style the generated image. Give the generator the supported styles and assets it actually needs.

Reuse content metadata

For an article-specific image, load the same title and tags used by the page. Maintaining a second handwritten title invites mismatches when the article changes.

In Next.js 16, dynamic route parameters are asynchronous. An image function that receives params should await it before reading the slug. Keep that version-specific detail aligned with the documentation bundled with your installed framework.

Treat title length as a layout requirement. Test a short heading, a long heading, punctuation, and an article with no tags. Limit secondary text and allow intentional wrapping rather than shrinking every title until it becomes unreadable.

Decide what missing content should produce

A public blog can use a generic branded image when article metadata is unavailable. Another site might intentionally return a missing-resource response. Either approach should be explicit and consistent with the route's behavior.

Keep generated previews limited to public information. A shareable image must not accidentally include a private draft, an internal identifier, or account-specific details merely because the generator can access server data.

Also consider remote assets. An external avatar or font adds a dependency to image generation. If the design works with a bundled font and text-only branding, that can be a simpler operational choice.

Verify the actual response

Request the image route directly after a production build. Check the status, PNG content type, dimensions, and file size, then inspect the rendered image.

Next, confirm the article's HTML points to the intended image URL and includes useful alternate text. A valid image that no page references will not improve the share preview.

Social platforms can cache previews, so separate the response your server currently provides from a platform's older cached result. Keep the generated output readable, stable, and easy to inspect. That gives every new article a consistent preview without turning publication into a design task.