opengraph-image and twitter-image
The opengraph-image
and twitter-image
file conventions allow you to set Open Graph and Twitter images for a route segment.
They are useful for setting the images that appear on social networks and messaging apps when a user shares a link to your site.
There are two ways to set Open Graph and Twitter images:
Image files (.jpg, .png, .gif)β
Use an image file to set a route segment's shared image by placing an opengraph-image
or twitter-image
image file in the segment.
Next.js will evaluate the file and automatically add the appropriate tags to your app's <head>
element.
File convention | Supported file types |
---|---|
opengraph-image | .jpg , .jpeg , .png , .gif |
twitter-image | .jpg , .jpeg , .png , .gif |
opengraph-image.alt | .txt |
twitter-image.alt | .txt |
opengraph-image
β
Add an opengraph-image.(jpg|jpeg|png|gif)
image file to any route segment.
<meta property="og:image" content="<generated>" />
<meta property="og:image:type" content="<generated>" />
<meta property="og:image:width" content="<generated>" />
<meta property="og:image:height" content="<generated>" />
twitter-image
β
Add a twitter-image.(jpg|jpeg|png|gif)
image file to any route segment.
<meta name="twitter:image" content="<generated>" />
<meta name="twitter:image:type" content="<generated>" />
<meta name="twitter:image:width" content="<generated>" />
<meta name="twitter:image:height" content="<generated>" />
opengraph-image.alt.txt
β
Add an accompanying opengraph-image.alt.txt
file in the same route segment as the opengraph-image.(jpg|jpeg|png|gif)
image it's alt text.
About Acme
<meta property="og:image:alt" content="About Acme" />
twitter-image.alt.txt
β
Add an accompanying twitter-image.alt.txt
file in the same route segment as the twitter-image.(jpg|jpeg|png|gif)
image it's alt text.
About Acme
<meta property="twitter:image:alt" content="About Acme" />
Generate images using code (.js, .ts, .tsx)β
In addition to using literal image files, you can programmatically generate images using code.
Generate a route segment's shared image by creating an opengraph-image
or twitter-image
route that default exports a function.
File convention | Supported file types |
---|---|
opengraph-image | .js , .ts , .tsx |
twitter-image | .js , .ts , .tsx |
Good to know
- By default, generated images are statically optimized (generated at build time and cached) unless they use dynamic functions or uncached data.
- You can generate multiple Images in the same file using
generateImageMetadata
.opengraph-image.js
andtwitter-image.js
are special Route Handlers that is cached by default unless it uses a dynamic function or dynamic config option.
The easiest way to generate an image is to use the ImageResponse API from next/og
.
import { ImageResponse } from 'next/og'
export const runtime = 'edge'
// Image metadata
export const alt = 'About Acme'
export const size = {
width: 1200,
height: 630,
}
export const contentType = 'image/png'
// Image generation
export default async function Image() {
// Font
const interSemiBold = fetch(
new URL('./Inter-SemiBold.ttf', import.meta.url)
).then((res) => res.arrayBuffer())
return new ImageResponse(
(
// ImageResponse JSX element
<div
style={{
fontSize: 128,
background: 'white',
width: '100%',
height: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
>
About Acme
</div>
),
// ImageResponse options
{
// For convenience, we can re-use the exported opengraph-image
// size config to also set the ImageResponse's width and height.
...size,
fonts: [
{
name: 'Inter',
data: await interSemiBold,
style: 'normal',
weight: 400,
},
],
}
)
}
import { ImageResponse } from 'next/og'
export const runtime = 'edge'
// Image metadata
export const alt = 'About Acme'
export const size = {
width: 1200,
height: 630,
}
export const contentType = 'image/png'
// Image generation
export default async function Image() {
// Font
const interSemiBold = fetch(
new URL('./Inter-SemiBold.ttf', import.meta.url)
).then((res) => res.arrayBuffer())
return new ImageResponse(
(
// ImageResponse JSX element
<div
style={{
fontSize: 128,
background: 'white',
width: '100%',
height: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
>
About Acme
</div>
),
// ImageResponse options
{
// For convenience, we can re-use the exported opengraph-image
// size config to also set the ImageResponse's width and height.
...size,
fonts: [
{
name: 'Inter',
data: await interSemiBold,
style: 'normal',
weight: 400,
},
],
}
)
}
<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" />
Propsβ
The default export function receives the following props:
params
(optional)β
An object containing the dynamic route parameters object from the root segment down to the segment opengraph-image
or twitter-image
is colocated in.
export default function Image({ params }: { params: { slug: string } }) {
// ...
}
export default function Image({ params }) {
// ...
}
Route | URL | params |
---|---|---|
app/shop/opengraph-image.js | /shop | undefined |
app/shop/[slug]/opengraph-image.js | /shop/1 | { slug: '1' } |
app/shop/[tag]/[item]/opengraph-image.js | /shop/1/2 | { tag: '1', item: '2' } |
app/shop/[...slug]/opengraph-image.js | /shop/1/2 | { slug: ['1', '2'] } |
Returnsβ
The default export function should return a Blob
| ArrayBuffer
| TypedArray
| DataView
| ReadableStream
| Response
.
Good to know:
ImageResponse
satisfies this return type.
Config exportsβ
You can optionally configure the image's metadata by exporting alt
, size
, and contentType
variables from opengraph-image
or twitter-image
route.
Option | Type |
---|---|
alt | string |
size | { width: number; height: number } |
contentType | string - image MIME type |
alt
β
export const alt = 'My images alt text'
export default function Image() {}
export const alt = 'My images alt text'
export default function Image() {}
<meta property="og:image:alt" content="My images alt text" />
size
β
export const size = { width: 1200, height: 630 }
export default function Image() {}
export const size = { width: 1200, height: 630 }
export default function Image() {}
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
contentType
β
export const contentType = 'image/png'
export default function Image() {}
export const contentType = 'image/png'
export default function Image() {}
<meta property="og:image:type" content="image/png" />
Route Segment Configβ
opengraph-image
and twitter-image
are specialized Route Handlers that can use the same route segment configuration options as Pages and Layouts.
Examplesβ
Using external dataβ
This example uses the params
object and external data to generate the image.
Good to know: By default, this generated image will be statically optimized. You can configure the individual
fetch
options
or route segments options to change this behavior.
import { ImageResponse } from 'next/og'
export const alt = 'About Acme'
export const size = {
width: 1200,
height: 630,
}
export const contentType = 'image/png'
export default async function Image({ params }: { params: { slug: string } }) {
const post = await fetch(`https://.../posts/${params.slug}`).then((res) =>
res.json()
)
return new ImageResponse(
(
<div
style={{
fontSize: 48,
background: 'white',
width: '100%',
height: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
>
{post.title}
</div>
),
{
...size,
}
)
}
import { ImageResponse } from 'next/og'
export const alt = 'About Acme'
export const size = {
width: 1200,
height: 630,
}
export const contentType = 'image/png'
export default async function Image({ params }) {
const post = await fetch(`https://.../posts/${params.slug}`).then((res) =>
res.json()
)
return new ImageResponse(
(
<div
style={{
fontSize: 48,
background: 'white',
width: '100%',
height: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
>
{post.title}
</div>
),
{
...size,
}
)
}
Using Edge runtime with local assetsβ
This example uses the Edge runtime to fetch a local image on the file system and passes it as an ArrayBuffer
to the src
attribute of an <img>
element. The local asset should be placed relative to the example source file location.
import { ImageResponse } from 'next/og'
export const runtime = 'edge'
export default async function Image() {
const logoSrc = await fetch(new URL('./logo.png', import.meta.url)).then(
(res) => res.arrayBuffer()
)
return new ImageResponse(
(
<div
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
>
<img src={logoSrc} height="100" />
</div>
)
)
}
import { ImageResponse } from 'next/og'
export const runtime = 'edge'
export default async function Image() {
const logoSrc = await fetch(new URL('./logo.png', import.meta.url)).then(
(res) => res.arrayBuffer()
)
return new ImageResponse(
(
<div
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
>
<img src={logoSrc} height="100" />
</div>
)
)
}
Using Node.js runtime with local assetsβ
This example uses the Node.js runtime to fetch a local image on the file system and passes it as an ArrayBuffer
to the src
attribute of an <img>
element. The local asset should be placed relative to the root of your project, rather than the location of the example source file.
import { ImageResponse } from 'next/og'
import { join } from 'node:path'
import { readFile } from 'node:fs/promises'
export default async function Image() {
const logoData = await readFile(join(process.cwd(), 'logo.png'))
const logoSrc = Uint8Array.from(logoData).buffer
return new ImageResponse(
(
<div
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
>
<img src={logoSrc} height="100" />
</div>
)
)
}
import { ImageResponse } from 'next/og'
import { join } from 'node:path'
import { readFile } from 'node:fs/promises'
export default async function Image() {
const logoData = await readFile(join(process.cwd(), 'logo.png'))
const logoSrc = Uint8Array.from(logoData).buffer
return new ImageResponse(
(
<div
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
>
<img src={logoSrc} height="100" />
</div>
)
)
}
Version Historyβ
Version | Changes |
---|---|
v13.3.0 | opengraph-image and twitter-image introduced. |