Menu

Multi-node @graph

Ship several related nodes in one script tag.

Arrays become @graph

A page usually has more than one thing to say — the page’s main entity plus breadcrumbs is the common pair. Pass an array and toJsonLd wraps it:

toJsonLd([article, breadcrumbs]);
// {"@context":"https://schema.org/","@graph":[{...},{...}]}

One script tag with a @graph and separate script tags per node are both valid; the graph form keeps related nodes together and the page’s head tidy.

A home page graph

The home page is a natural place to declare site-wide nodes — the WebSite, the owner, and (for a code-centric site) the repository:

const person = createPersonSchema({
  "@id": "https://example.com/#person",
  name: "Ada Lovelace",
  url: "https://example.com",
});

const website = createWebSiteSchema({
  "@id": "https://example.com/#website",
  name: "Ada Lovelace",
  url: "https://example.com",
  inLanguage: "en",
  author: person,
  publisher: person,
});

const repo = createSoftwareSourceCodeSchema({
  name: "example-site",
  codeRepository: "https://github.com/ada/example-site",
  programmingLanguage: "TypeScript",
  author: person,
});

toJsonLd([website, person, repo]);

Cross-page references

Nodes declared in one page’s graph can be referenced from any other page by @id:

// On /blog/some-post — no need to redeclare the website node:
const post = createArticleSchema({
  headline: "...",
  datePublished: "...",
  isPartOf: createNodeRef("https://example.com/#website"),
});

Keep @id values boring and stable: your canonical origin plus a short fragment (#person, #website). They’re identifiers, not links — but making them resolvable URLs on your own domain is good practice.