Next.js¶
@easeo/next converts an easeo payload into a native Next.js Metadata
object. Use it inside generateMetadata; there is no HTML manipulation.
Prerequisites¶
- Node 20 or newer.
- Next.js 13 or newer (App Router).
- A site-wide
SEOConfig.
Install¶
Quick start¶
// app/products/[slug]/page.tsx
import { easeoMetadata } from "@easeo/next";
export async function generateMetadata({ params }) {
const product = await getProduct(params.slug);
return easeoMetadata({
entity: {
entityType: "product",
title: product.name,
description: product.description,
},
route: `/products/${product.slug}`,
config: {
canonicalHost: "example.com",
publicBaseUrl: "https://example.com",
},
});
}
Function signature¶
config is required; the core rejects an empty canonicalHost.
What it returns¶
| Next.js key | Source |
|---|---|
title |
payload.title |
description |
payload.description |
alternates.canonical |
payload.canonical |
robots |
payload.robots |
openGraph |
title, description, url, siteName, images, locale, type |
twitter |
card, title, description, images, site, creator |
Images are only set when the payload has one; otherwise the images key is
undefined and Next.js omits it.
Patterns¶
Share the config¶
Keep the config in one module so every route uses the same settings:
// lib/seo.ts
import type { SEOConfig } from "@easeo/core";
export const config: SEOConfig = {
canonicalHost: "shop.example.com",
publicBaseUrl: "https://shop.example.com",
siteName: "Example Shop",
titleTemplate: "{title} - Example Shop",
defaultOgImage: "https://shop.example.com/assets/og-image.png",
};
Use the payload beyond the head¶
generateMetadata covers the head. When you also need the JSON-LD or the hash
for caching, build the payload directly:
import { buildSeoPayload } from "@easeo/core";
const payload = buildSeoPayload(entity, route, config);
payload.renderHtml();
payload.schemaJsonLd;
payload.etag();
Static metadata¶
For pages that never change, return the object synchronously:
export function generateMetadata() {
return easeoMetadata({ entity: { entityType: "page", title: "About" }, route: "/about", config });
}
Troubleshooting¶
| Symptom | Cause |
|---|---|
canonicalHost required error |
config is missing or canonicalHost is empty |
| Social preview has no image | No defaultOgImage and the entity has no image; see EASEO108 |
| Title has the site suffix twice | titleTemplate applied in the app and in easeo |