Dynamic Social Images with Next.js
Ever shared a link and wished it had a better preview image? Those eye-catching images you see on social media are often powered by Open Graph (OG) tags. In this article, we'll explore how to create these OG images dynamically in Next.js, making your shared links stand out.
Why Dynamic Social Images?
While static images are okay for general branding, they're not great for showcasing specific content. Imagine sharing a blog post - wouldn't it be better if the shared image included the post's title or a relevant graphic? That's where dynamic image generation comes in. It allows you to create custom social media images on the fly.
Next.js to the Rescue
Next.js makes dynamic social image generation easy thanks to its routing system and recent features. You can create images directly within your application using JavaScript, TypeScript, or JSX - no extra services needed. You have two main approaches: using a special file or creating an API route. You can learn more about Next.js routing here.
Method 1: The Magic of opengraph-image.js
(or .ts/.tsx)
The first approach uses a special file called opengraph-image.js
(or its TypeScript versions).
By placing this file in a route segment, you tell Next.js: "Generate the Open Graph image for this specific page here."
It's a simple idea that gives you a lot of control over specific page images.
You can read more about Next.js file conventions here.
Method 2: Generating Images Through an API Route
Alternatively, you can create an API endpoint dedicated to generating images.
This approach is useful if you want to create more complex images or reuse the image-generating logic across different parts of your application.
You could create an API route in the app/api
folder, for example, /api/dynamic-image
.
You can read more about Next.js API Routes here.
How It Works: A Quick Overview
Using opengraph-image.js
:
- Create the File: Make an
opengraph-image.js
,.ts
, or.tsx
file within your desired route. For example, for blog posts, the file would be located atapp/posts/[slug]/opengraph-image.jsx
. - Export a Function: Inside the file, you need to export a default function. This function generates your image.
- Use
ImageResponse
: The easiest way to create your image is usingImageResponse
fromnext/og
. It lets you use JSX to define the image's layout and content. Think of it as writing HTML, but it renders an image. You can find more info about thenext/og
library here. - Dynamic Content: The function receives the route's parameters via a
params
prop. You can use these to personalize the image with data. - Metadata: Export things like
alt
(alt text),size
, andcontentType
to add meta tags to your HTML. You can see how Open Graph meta tags work in general.
Using an API Route:
- Create the API Route: Create the
route.js
inside yourapp/api
folder, creating the/api/dynamic-image
endpoint. - Export a
GET
Function: Export an async function calledGET
that will handle the request and generate the image. - Use
ImageResponse
: Similar to theopengraph-image
approach, useImageResponse
to create your image with JSX. - Access Query Parameters: You can access query parameters passed to the API route using
request.url
andURLSearchParams
. You'll need to pass the slug to the API route via query parameters in this case.
A Simple Example
Let's look at examples for both approaches.
Example 1: Using opengraph-image.jsx
import { ImageResponse } from "next/og";
export const runtime = "edge";
export const alt = "Blog Post Image";
export const size = {
width: 1200,
height: 630,
};
export const contentType = "image/png";
export default async function Image({ params }) {
const post = await fetch(`https://your-api.com/posts/${params.slug}`).then(
(res) => res.json()
);
return new ImageResponse(
<div style={{ fontSize: 48, background: "white" }}>{post.title}</div>,
{
...size,
}
);
}
Example 2: Using an API Route (app/api/dynamic-image/route.js
)
import { ImageResponse } from "next/og";
export const runtime = "edge";
export async function GET(request) {
const { searchParams } = new URL(request.url);
const slug = searchParams.get("slug");
const post = await fetch(`https://your-api.com/posts/${slug}`).then((res) =>
res.json()
);
return new ImageResponse(
<div style={{ fontSize: 48, background: "white" }}>{post.title}</div>,
{
width: 1200,
height: 630,
}
);
}
Important Note: To use the API route example effectively, you would need to modify your meta tags in your blog post template to point to the API route, passing the slug
as a query parameter, like this:
<meta property="og:image" content={`/api/dynamic-image?slug=${slug}`} />
Things to Keep in Mind
- Static Optimization:
opengraph-image.js
images are statically optimized by default (unless using dynamic data). API routes offer more control, but you may need to handle caching yourself. You can read more about Static Generation in Next.js here. - Edge Runtime: Both methods can leverage the Edge runtime for performance.
- Fonts: Make sure to fetch fonts correctly when using text.
- Performance: Optimize data fetching to avoid slowdowns.
In Conclusion
Next.js provides two powerful ways to create dynamic social media images: the opengraph-image
file and API routes.
Both methods use the ImageResponse
API and allow for the creation of personalized and visually engaging previews for shared links.
Choosing the right approach depends on your specific needs and the complexity of the images you need to generate.
This flexibility makes Next.js a great tool for improving your social media presence.