Metadata API
The metadata API lets you control the <head> tags for each page — title, description, OpenGraph, Twitter cards, canonical URLs, and more.
# generateMetadata()
Export a generateMetadata function from page.ts:
// src/app/blog/[slug]/page.ts
import type { PageMetadata } from "@deijose/nix-js-kit";
export const generateMetadata = async ({ params, data }): Promise<PageMetadata> => {
return {
title: `${data.title} — My Blog`,
description: data.description,
canonical: `https://example.com/blog/${params.slug}`,
openGraph: {
type: "article",
title: data.title,
description: data.description,
image: `/og/${params.slug}.jpg`,
url: `https://example.com/blog/${params.slug}`,
},
twitter: {
card: "summary_large_image",
title: data.title,
image: `/og/${params.slug}.jpg`,
},
};
};# PageMetadata interface
interface PageMetadata {
title?: string;
description?: string;
canonical?: string;
robots?: string; // e.g. "index, follow" or "noindex"
openGraph?: OpenGraphMetadata;
twitter?: TwitterMetadata;
other?: Record<string, string>; // additional meta tags
}# OpenGraphMetadata
interface OpenGraphMetadata {
type?: string; // "website", "article", "profile"
title?: string; // falls back to page title
description?: string; // falls back to page description
url?: string;
image?: string;
siteName?: string;
locale?: string; // e.g. "en_US"
}# TwitterMetadata
interface TwitterMetadata {
card?: "summary" | "summary_large_image" | "player" | "app";
title?: string;
description?: string;
image?: string;
}# Metadata sources
Metadata is collected from three sources, merged in this priority:
generateMetadata()export frompage.ts(highest priority)metadatafield from the page loader (page.data.ts)metadatafield from the layout loader (layout.data.ts)
// src/app/page.data.ts
export const load = async () => {
return {
title: "Home",
metadata: {
title: "My Site — Home",
description: "Welcome to my site",
},
};
};# MetadataContext
interface MetadataContext extends LoadContext {
data?: unknown; // loader data, if a loader exists
}# Head tag generation
buildHeadTags() generates the HTML for all head tags:
import { buildHeadTags } from "@deijose/nix-js-kit";
const tags = buildHeadTags({
title: "About",
description: "About us",
openGraph: { type: "website", image: "/og.jpg" },
});
// → '<title>About</title><meta name="description" content="About us">...'# SPA head merge
All generated head tags are marked with data-nix-js-head:
<title data-nix-js-head>About</title>
<meta name="description" data-nix-js-head content="About us" />
<meta property="og:title" data-nix-js-head content="About" />On SPA navigation, the client router:
- Removes all
data-nix-js-headtags from<head> - Inserts the new page's head tags
- Updates
document.title
This keeps metadata in sync with the current page during SPA navigation.