When you start adding more than one type of schema to a page (Organization, WebSite, WebPage, Article, BreadcrumbList), the JSON-LD can get messy fast. You either end up with deeply nested objects that are hard to read, or several separate <script> blocks that don't clearly relate to each other.
@graph solves this. It lets you describe every entity on a page in one structured data block and connect them with references, so search engines see one coherent picture instead of a pile of disconnected snippets.
In this guide, I'll explain what @graph is, when to use it, and how to build one step by step.
What is @graph?
@graph is a JSON-LD keyword that holds a list of entities (called "nodes") within a single JSON-LD document. Instead of wrapping one entity inside another, you place each entity side by side in an array and link them using @id.
@graph is not a Schema.org type or property. It comes from the JSON-LD specification itself, which is why it starts with @ like @context, @type and @id.
Here is the basic structure:
Why use @graph?
Think of your structured data as a small knowledge graph for the page. The page is about an article, the article is written by a person, the person works for an organisation, and the organisation publishes the website. These are relationships between entities, and @graph is designed to express exactly that.
The main benefits are:
- One entity, defined once. Your Organization appears as the publisher of the Article, the publisher of the WebSite and the author's worksFor. With nesting, you would repeat the full Organization object three times. With @graph, you define it once and reference it with its @id.
- Cleaner, easier maintenance. Each entity is a flat, self-contained block. Updating your logo or sameAs links means editing one node, not hunting through nested objects.
- Clear relationships. References like "author": { "@id": "https://example.com/#person" } make the connections explicit, which supports entity understanding rather than just rich result eligibility.
- Easier to generate programmatically. If your CMS or templates output schema, it's much simpler to build an array of nodes than to assemble a deeply nested tree. This is also why plugins like Yoast SEO output their schema as a @graph.
@graph vs nesting vs multiple script tags
There are three common ways to add several schema types to one page.
- Nesting places one entity inside another's property. It works well for small, one-directional relationships, such as an Offer inside a Product or a PostalAddress inside a LocalBusiness. It becomes hard to manage once the same entity is needed in several places.
- Multiple <script> blocks keep each type separate. This is easy to add (for example, one block from your theme and another from Google Tag Manager), but the blocks don't describe how the entities relate unless you consistently reference the same @id values across them.
- @graph puts all entities in one block and connects them by @id. It's the tidiest option when a page has several related entities.
In practice, most well-built implementations mix these: a @graph for the main entities, with small, page-specific details (like an Offer or ImageObject) nested inside the relevant node.
Google supports all three formats, so @graph is not a ranking factor or a requirement for rich results. It's a way to make your markup more accurate and maintainable.
How @id connects nodes in a @graph
@graph only becomes useful when you pair it with @id. The @id is a unique identifier for an entity, usually a URL with a fragment such as https://example.com/#organization.
Once a node has an @id, any other node can point to it:
"publisher": { "@id": "https://example.com/#organization" }The reference object contains only the @id. Search engines and validators resolve it to the full Organization node elsewhere in the graph.
A few rules of thumb:
- Use absolute URLs, not relative ones.
- Keep the same @id for the same entity across your whole site. Your Organization should have one @id on every page, not a new one per page.
- Don't give two different entities the same @id.
I covered this in more detail in How to choose @id for Schema.
A full @graph example for a blog post
Here's a realistic @graph for a blog article page. It includes the Organization, WebSite, WebPage, BreadcrumbList, BlogPosting and Person, all connected by @id.
{
"@context": "https://schema.org",
"@graph": [
{
"@type": "Organization",
"@id": "https://example.com/#organization",
"name": "Example Co",
"url": "https://example.com/",
"logo": {
"@type": "ImageObject",
"url": "https://example.com/logo.png"
},
"sameAs": [
"https://www.linkedin.com/company/example-co"
]
},
{
"@type": "WebSite",
"@id": "https://example.com/#website",
"url": "https://example.com/",
"name": "Example Co",
"publisher": { "@id": "https://example.com/#organization" }
},
{
"@type": "Person",
"@id": "https://example.com/about/#person",
"name": "Jane Doe",
"url": "https://example.com/about/",
"worksFor": { "@id": "https://example.com/#organization" }
},
{
"@type": "WebPage",
"@id": "https://example.com/schema-graph/#webpage",
"url": "https://example.com/schema-graph/",
"name": "What is @graph in Schema Markup?",
"isPartOf": { "@id": "https://example.com/#website" },
"breadcrumb": { "@id": "https://example.com/schema-graph/#breadcrumb" }
},
{
"@type": "BreadcrumbList",
"@id": "https://example.com/schema-graph/#breadcrumb",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"name": "Home",
"item": "https://example.com/"
},
{
"@type": "ListItem",
"position": 2,
"name": "Schema Markup",
"item": "https://example.com/schema-markup/"
},
{
"@type": "ListItem",
"position": 3,
"name": "What is @graph in Schema Markup?"
}
]
},
{
"@type": "BlogPosting",
"@id": "https://example.com/schema-graph/#article",
"headline": "What is @graph in Schema Markup?",
"datePublished": "2026-09-24",
"dateModified": "2026-09-24",
"mainEntityOfPage": { "@id": "https://example.com/schema-graph/#webpage" },
"author": { "@id": "https://example.com/about/#person" },
"publisher": { "@id": "https://example.com/#organization" }
}
]
}Reading it as relationships: the BlogPosting is the main content of the WebPage, the WebPage is part of the WebSite, the article is written by the Person, and both the WebSite and the article are published by the Organization. Every entity is defined once.
The Organization and WebSite nodes are the same on every page, so you can output them from a site-wide template and only swap the page-level nodes (WebPage, BreadcrumbList, BlogPosting). For the site-wide nodes, you can use my Organization schema generator and Website schema generator as a starting point.
How to build a @graph step by step
- List the entities on the page. Start with what the page is about (Article, Product, Service, LocalBusiness), then add the supporting entities: WebPage, WebSite, Organization, Person, BreadcrumbList.
- Assign a stable @id to each entity. Site-wide entities use the homepage URL plus a fragment (/#organization, /#website). Page-level entities use the page URL plus a fragment (/page/#webpage, /page/#article).
- Write each entity as its own node. Add the properties you'd normally include, such as name, url, logo and sameAs.
- Replace repeated entities with references. Anywhere you'd nest a full entity that exists elsewhere in the graph, use { "@id": "..." } instead.
- Wrap everything in one @graph array with a single @context at the top.
- Validate. Test the page in the Schema Markup Validator and Google's Rich Results Test. See How to Check Schema Markup for a walkthrough.
Common @graph mistakes
Adding extra properties next to @graph. The top-level object should contain only @context and @graph. If you add something like @type or name at the top level alongside @graph, JSON-LD treats it as a named graph, which is almost never what you want and can confuse validators.
Broken references. If a node points to https://example.com/#organisation but the Organization is defined as #organization, the reference goes nowhere. One letter matters. Copy and paste your @id values or generate them from a single variable in your templates.
Changing @id values between pages. If your Organization is #organization on the homepage and #org on blog posts, you are describing two different entities. Pick one and use it everywhere.
Orphan nodes. A node that nothing references and that references nothing isn't wrong, but it's a sign the graph isn't telling a connected story. Check whether it should be linked via mainEntityOfPage, isPartOf, publisher, author or about.
Referencing nodes that aren't on the page. Pointing to an @id defined on another URL is valid JSON-LD, but Google won't follow it to fetch the missing properties. If a property is needed for rich results (for example, the publisher's name), the node should be on the same page.
Duplicating entities across plugins. If an SEO plugin already outputs a @graph and you add a separate block with another Organization under a different @id, you've created two competing organisations. Extend the existing graph, or reuse the plugin's @id values in your custom markup.
Does @graph help SEO?
@graph itself doesn't unlock rich results. Google reads the same entities whether they're nested, split across blocks or combined in a graph. What @graph does is make it easier to describe your entities accurately and consistently across the whole site, and that consistency is what supports entity understanding, clearer author and publisher signals for E-E-A-T, and fewer validation errors as your markup grows.
If you only have one or two schema types on a page, nesting is perfectly fine. Once you have several related entities, especially ones that repeat across your site, @graph is the cleaner choice.
Conclusion
@graph lets you describe all the entities on a page in one JSON-LD block and connect them with @id references. Define each entity once, keep your @id values stable site-wide, keep the top level limited to @context and @graph, and validate after every change. Your markup will be easier to maintain, and search engines will get a clearer picture of who you are and what each page is about.
FAQs about @graph in schema markup
Is @graph required by Google?
No. Google accepts nested JSON-LD, multiple script blocks and @graph. It's an implementation choice, not a requirement for rich results.
Can I use @graph with microdata or RDFa?
No, @graph is a JSON-LD keyword. If you're using RDFa or microdata, you connect entities using their own attributes (such as resource or itemid) instead.
Can I nest objects inside a @graph node?
Yes. Small objects that only belong to one entity, like an ImageObject for a logo, a PostalAddress or an Offer, are usually simplest to nest. Use @id references for entities that appear in more than one place.
Should I put all my schema in one @graph?
For most pages, yes. One @graph per page is easier to debug than several blocks. If some markup comes from a plugin you can't edit, reuse its @id values in your own block so the entities stay connected.

