The Complete Production SOP: How to Deploy and Run Next.js Dynamic Open Graph (OG) Image Generation in Autonomous AI Agents
Deploy Next.js Dynamic Open Graph (OG) Image Generation in Codex, Claude Code, and Cursor. Fix Satori CSS bugs, load custom fonts, and build dynamic social cards.
Technical Overview & Architectural Context
Autonomous coding agents like Claude Code, Codex, and Cursor frequently fail when generating dynamic Open Graph images in Next.js App Router applications. Without structured boundary constraints, agents routinely introduce unsupported CSS properties (such as grid layouts, standard CSS transforms, or external CSS modules) that break Satori, the underlying SVG-to-PNG engine inside `next/og`. Furthermore, agents often misplace dynamic parameters, trigger hydration mismatches by attempting client component rendering inside `opengraph-image.tsx`, or fail to handle asynchronous ArrayBuffer font loading correctly within Edge or Node runtimes. By mounting the `nextjs-dynamic-og-image-generation` skill, the agent operates under deterministic standard operating procedures. The skill enforces the exact runtime requirements: exporting constant image dimensions (`export const size = { width: 1200, height: 630 }`), restricting styles strictly to Satori-compatible Flexbox inline subsets, and verifying standard route segment signatures. The result is zero-shot, build-passing social cards without context bloat or runtime render crashes.
Prerequisites & Environment Requirements
Verified Search Intents & Long-Tail Queries Solved
This operational tutorial is engineered to provide deterministic solutions for these developer search queries:
Step-by-Step Execution Playbook
Local Environment Setup & SKILL.md Mounting
Create the local skill manifest directory and inject verified procedural rules.
Autonomous agents discover domain skills by scanning predefined configuration directories (`.agents/skills` or `.cursor/rules`). To mount this skill, create the directory structure in your project root or user config path and mirror the canonical SKILL.md manifest. This provides the agent with deterministic routing rules and triggers.
mkdir -p .agents/skills/nextjs-dynamic-og-image-generation && curl -fsSL https://askills.dev/api/skills/nextjs-dynamic-og-image-generation/raw -o .agents/skills/nextjs-dynamic-og-image-generation/SKILL.md---
name: "nextjs-dynamic-og-image-generation"
description: "Generate branded, dynamic Open Graph social card images on-the-fly using @vercel/og and JSX."
metadata:
author: "Vercel"
version: "1.0.0"
runtime_compatibility:
- "codex"
- "claude-code"
- "cursor"
- "windsurf"
triggers:
- "generate dynamic og image nextjs"
- "create opengraph-image.tsx"
- "load custom font vercel og"
permissions:
fs_read: true
fs_write: "workspace"
shell_exec: false
net_access: false
---
# Execution SOP
1. Use ImageResponse from 'next/og'.
2. Export size ({ width: 1200, height: 630 }) and contentType ('image/png').
3. Use inline flexbox styling only. Disallow CSS grid or float.Setting net_access: false prevents agents from attempting unnecessary external runtime font queries, forcing them to use local fonts or optimized static fetches.
Do not rename the target file from opengraph-image.tsx to route.tsx if you intend Next.js to automatically manage metadata meta tags.
Environment Secrets & Dependency Validation
Inject required environment variables safely without leaking secrets into conversation history.
Dynamic OG generation often references asset CDNs, site URLs, or private CMS tokens. Ensure that NEXT_PUBLIC_SITE_URL or private CMS API keys are supplied through `.env.local` while strictly isolating sensitive credentials from LLM prompt histories.
test -f .env.local || echo 'NEXT_PUBLIC_SITE_URL=http://localhost:3000' >> .env.localimport { ImageResponse } from 'next/og';
export const runtime = 'edge';
export const alt = 'Article Social Image';
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;
return new ImageResponse(
(
<div
style={{
height: '100%',
width: '100%',
display: 'flex',
flexDirection: 'column',
alignItems: 'flex-start',
justifyContent: 'space-between',
backgroundColor: '#0a0a0a',
padding: '60px',
color: '#ffffff',
}}
>
<div style={{ fontSize: 28, color: '#888888', textTransform: 'uppercase' }}>
Engineering Blog
</div>
<div style={{ fontSize: 64, fontWeight: 700, lineHeight: 1.1 }}>
{slug.replace(/-/g, ' ')}
</div>
<div style={{ display: 'flex', alignItems: 'center', fontSize: 24, color: '#444444' }}>
askills.dev
</div>
</div>
),
{ ...size }
);
}In Next.js 15, route segment parameters `params` return a Promise. Always await `params` inside dynamic image route handlers.
Never import React client hooks (e.g., useState, useEffect) or client components into `opengraph-image.tsx`.
Intent Matching & Trigger Invocation
Verify deterministic activation using tested natural language prompts.
Instruct your autonomous agent using one of the validated trigger phrases. The agent matches frontmatter trigger strings and initiates the standardized dynamic OG layout SOP without hallucinating arbitrary styling frameworks.
claude-code "generate dynamic og image nextjs for our dynamic documentation routes with custom Inter font"import { ImageResponse } from 'next/og';
export const runtime = 'edge';
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 interSemiBold = await fetch(
new URL('../../../assets/Inter-SemiBold.ttf', import.meta.url)
).then((res) => res.arrayBuffer());
return new ImageResponse(
(
<div
style={{
height: '100%',
width: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#09090b',
color: '#f4f4f5',
fontFamily: 'Inter',
}}
>
<h1 style={{ fontSize: 56 }}>{slug}</h1>
</div>
),
{
...size,
fonts: [
{
name: 'Inter',
data: interSemiBold,
style: 'normal',
weight: 600,
},
],
}
);
}Loading local font files using `import.meta.url` via `fetch` guarantees compatibility across both Node.js and Edge runtimes on Vercel.
Satori only accepts `.ttf`, `.otf`, or `.woff` fonts. `.woff2` files are not supported and will trigger an instant decode failure.
Verification, Linting & Output Quality Gate
Execute automated self-healing checks before accepting agent deliverables.
Require the agent to run Next.js type checking and a headless build step. This verifies that Satori inline CSS styles conform to `React.CSSProperties` and dynamic promise unwrapping matches Next.js App Router specifications.
pnpm next build --no-lint && pnpm tsc --noEmit#!/usr/bin/env bash
set -euo pipefail
echo "Validating Open Graph Image exports..."
if ! grep -q "export const size" app/**/opengraph-image.tsx; then
echo "Error: Missing mandatory 'export const size' declaration."
exit 1
fi
echo "Verification passed successfully."Instruct the agent to inspect its own `git diff` to confirm that no Tailwind JIT classes leaked into the Satori JSX container without proper inline styles.
Using `calc()` inside inline styles in `ImageResponse` can cause Satori rendering errors; use hardcoded integer pixel values or percentages instead.
Real-World Scenario: Automating Multi-Tenant Dynamic Documentation Social Previews
“Claude Code, generate dynamic og image nextjs for our dynamic documentation at app/docs/[section]/[slug]/opengraph-image.tsx. Use a dark theme with slate-950 background, display the section tag above the title, and load custom Geist font.”
Runtime Troubleshooting & Failure Modes
Root Cause: The agent loaded a .woff2 font file via fetch or local filesystem. Satori does not support Brotli-compressed WOFF2 formats.
Convert your font to .ttf or .woff using fonttools or ttf2woff, and update the font loading path:
const fontData = await fetch(new URL('./Geist-Regular.ttf', import.meta.url)).then(res => res.arrayBuffer());Root Cause: Next.js 15 upgraded route params and searchParams to asynchronous promises, causing TypeScript compilation errors in legacy synchronous route implementations.
export default async function Image({ params }: { params: Promise<{ slug: string }> }) {
const resolvedParams = await params;
const slug = resolvedParams.slug;
// ...
}Frequently Asked Questions (Next.js Dynamic Open Graph (OG) Image Generation SOP)
Q:Can I use Next.js Dynamic Open Graph (OG) Image Generation across Codex, Claude Code, and Cursor simultaneously?
Yes. The skill conforms to the universal SKILL.md specification supported across all modern agent runtimes. Simply place it in the `.agents/skills` or `.cursor/rules` directory, and each runtime will parse the triggers and adhere to the procedural boundaries.
Q:How does Next.js Dynamic Open Graph (OG) Image Generation prevent context window overflow during long agent sessions?
By establishing concise procedural boundaries and deterministic validation gates rather than polluting system prompts with redundant rules. It strictly isolates CSS-in-JS limitations and Satori rules into targeted SOP checkpoints that activate only when relevant files are touched.
Q:Does this skill require escalated root or container permissions?
No. It is audited with a security score of 98/100 and runs safely within workspace-scoped sandboxes. It requires file reading and writing within the project workspace, but has shell execution and external network access disabled by default.
Ready to equip your autonomous agent with Next.js Dynamic Open Graph (OG) Image Generation?
Copy the complete audited SKILL.md specification or download the 1-click zip bundle directly from our verified registry.