Portrait of Aung Pyae Phyo, software engineer
Blog

Generate Opengraph Image in Next.JS

Create a new Next.js Project

Open your terminal and write this following command:

terminal
pnpm create next-app dynamic-og-background

Next.js generator will be show like this:

terminal
✔ What is your project named? … .
✔ Would you like to use TypeScript? … No / Yes
✔ Would you like to use ESLint? … No / Yes
✔ Would you like to use Tailwind CSS? … No / Yes
✔ Would you like to use `src/` directory? … No / Yes
✔ Would you like to use App Router? (recommended) … No / Yes
✔ Would you like to customize the default import alias (@/*)? … No / Yes

Change your directory with this following command:

terminal
cd dynamic-og-background

and open with your code editor or IDE.eg:

terminal
code .

or

terminal
webstorm .

Project Structure

├── README.md
├── next-env.d.ts
├── next.config.js
├── package.json
├── postcss.config.js
├── public
│   ├── og-bg.png // I created this image to use as background
│   ├── next.svg
│   └── vercel.svg
├── src
│   └── app
│       ├── api // I created this folder to store my api routes
│       │   └── og
│       │       └── route.tsx // Here is my og route
│       ├── fonts // I created this folder to store my fonts
│       │   └── mono.ttf // Here am using outfit font
│       ├── favicon.ico
│       ├── globals.css
│       ├── layout.tsx
│       └── page.tsx
├── tailwind.config.ts
└── tsconfig.json
├── pnpm-lock.yaml

I created api folder to store my api routes and also created fonts folder to store my fonts. You can use any font you want.

Implement the dynamic opengraph route

og/route.ts
import { ImageResponse } from 'next/og';
import { NextRequest } from 'next/server';

export const runtime = 'edge';

export async function GET(req: NextRequest) {
  const { searchParams } = req.nextUrl;
  const postTitle = searchParams.get('title');
  const font = fetch(new URL('../mono.ttf', import.meta.url)).then((res) =>
    res.arrayBuffer(),
  );
  const fontData = await font;

  return new ImageResponse(
    (
      <div
        style={{
          height: '100%',
          width: '100%',
          display: 'flex',
          flexDirection: 'column',
          alignItems: 'flex-start',
          padding: '100',
          justifyContent: 'flex-start',
          backgroundImage: `https://exmaple.com/og-bg.png)`,
        }}
      >
        <p
          style={{
            display: 'flex',
            fontSize: 100,
            fontFamily: 'Jetbrains Mono',
            letterSpacing: '-0.05em',
            fontWeight: '7000',
            fontStyle: 'normal',
            color: 'black',
            lineHeight: '120px',
            whiteSpace: 'pre-wrap',
            textTransform: 'capitalize',
          }}
        >
          {postTitle}
        </p>
      </div>
    ),
    {
      width: 1920,
      height: 1080,
      fonts: [
        {
          name: 'Jetbrains Mono',
          data: fontData,
          style: 'normal',
        },
      ],
    },
  );
}

Output

<meta property="og:image" content="<generated>" />
<meta property="og:image:alt" content="About Acme" />
<meta property="og:image:type" content="image/png" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />

Code Explanation

  • Import the necessary modules and constants.
  • Set Runtime: Declare runtime as 'edge'.
  • Define an asynchronous function to handle GET requests.
  • Use the fetch API to get the Outfit font data and convert it to an array buffer.
  • Generate an ImageResponse object with dynamic JSX content.
  • Specify options for the ImageResponse, including width, height, and font details.

Test your dynamic opengraph route

  • pnpm dev
  • open your browser and enter your dynamic open graph route in your browser address bar.
  • example: http://localhost:3000/og?title=hello

For more information, check out the official documentation on Open Graph.