JSON-LD
6 min read
W3C standard for expressing Linked Data in JSON. A @context maps plain JSON keys to globally unambiguous IRIs, making data self-describing and interoperable across systems without changing JSON structure.
See also: schema.org
Core Keywords
| Keyword | Purpose |
|---|---|
@context | Maps terms to IRIs — defines the vocabulary |
@id | Identifies the subject (IRI or blank node) |
@type | RDF type — shorthand for rdf:type |
@value | Explicit literal value inside a value object |
@language | BCP47 language tag for a string |
@direction | Text direction: "ltr", "rtl", or null |
@graph | Named graph container |
@list | Ordered list (RDF list semantics) |
@set | Unordered collection — forces array output |
@reverse | Expresses an inverse property relationship |
@index | Marks a container as indexed by arbitrary keys |
@nest | Groups properties without creating graph edges |
@none | Fallback index key for unmapped values |
@vocab | Default IRI prefix for unknown terms |
@base | Base IRI for resolving relative references |
@version | Processing mode — 1.1 to enable JSON-LD 1.1 |
@prefix | Whether a term can be used as a compact IRI prefix |
@protected | Prevents a term definition from being overridden |
@propagate | Controls whether a context propagates into nested nodes |
@import | Merges an external context into the current one |
@included | Secondary node objects embedded in a top-level node |
@json | Datatype for JSON literals (rdf:JSON) |
@context
Simple form
json
{ "@context": "https://schema.org/" }
Inline map
json
{
"@context": {
"@vocab": "https://schema.org/",
"@base": "https://example.com/",
"@language": "en",
"@version": 1.1,
"name": "http://xmlns.com/foaf/0.1/name",
"knows": { "@id": "http://xmlns.com/foaf/0.1/knows", "@type": "@id" }
}
}
Array context (merge multiple)
json
{
"@context": [
"https://schema.org/",
{ "ex": "https://example.com/vocab#" }
]
}
Term definition options
json
{
"@context": {
"title": { "@id": "http://purl.org/dc/terms/title" },
"homepage": { "@id": "http://xmlns.com/foaf/0.1/homepage", "@type": "@id" },
"tags": { "@id": "http://example.com/tag", "@container": "@set" },
"labels": { "@id": "http://www.w3.org/2000/01/rdf-schema#label", "@container": "@language" },
"index": { "@id": "http://example.com/item", "@container": "@index" },
"parent": { "@reverse": "http://example.com/child" },
"dc": { "@id": "http://purl.org/dc/terms/", "@prefix": true }
}
}
@container Values
| Value | Effect |
|---|---|
@list | Treat property value as an ordered RDF list |
@set | Always represent value as an array |
@language | Keys are language tags, values are strings (language map) |
@index | Keys are arbitrary string indices (no graph semantics) |
@id | Keys are @id values of the associated node objects |
@type | Keys are @type IRIs of the associated node objects |
@graph | Value is a named graph |
["@graph", "@id"] | Array — named graph indexed by @id |
["@graph", "@index"] | Named graph indexed by arbitrary key |
Value Objects
Typed literal:
json
{ "@value": "2024-01-15", "@type": "xsd:date" }
Language-tagged string:
json
{ "@value": "Hola", "@language": "es" }
With text direction:
json
{ "@value": "مرحبا", "@language": "ar", "@direction": "rtl" }
JSON literal (JSON-LD 1.1):
json
{ "@value": { "foo": [1, 2] }, "@type": "@json" }
Language Maps
With @container: @language, a map of language → value compacts to a clean object:
json
{
"@context": {
"label": { "@id": "rdfs:label", "@container": "@language" }
},
"label": {
"en": "Hello",
"fr": "Bonjour",
"de": "Hallo"
}
}
Index Maps
With @container: @index, arbitrary string keys act as an index without RDF meaning:
json
{
"@context": {
"post": { "@id": "ex:post", "@container": "@index" }
},
"post": {
"en": { "title": "Hello" },
"fr": { "title": "Bonjour" }
}
}
@reverse
Express inverse relationships without changing the graph:
json
{
"@context": {
"children": { "@reverse": "ex:parent" }
},
"@id": "ex:parent1",
"children": [
{ "@id": "ex:child1" },
{ "@id": "ex:child2" }
]
}
This asserts ex:child1 ex:parent ex:parent1 in the RDF graph.
Named Graphs
json
{
"@context": { "@vocab": "https://schema.org/" },
"@graph": [
{
"@id": "https://example.com/me",
"@type": "Person",
"name": "Angelo"
}
]
}
Multiple named graphs with @id:
json
[
{
"@id": "https://example.com/graph1",
"@graph": [ { "@id": "ex:a", "ex:p": "value" } ]
}
]
Blank Nodes
Nodes without a dereferenceable IRI. Identified by _: prefix:
json
{
"@id": "_:b0",
"@type": "ex:Thing",
"ex:label": "anonymous node"
}
Blank nodes are auto-assigned if @id is omitted entirely.
@nest
Group properties visually without creating graph structure:
json
{
"@context": {
"metadata": "@nest",
"name": "schema:name",
"author": "schema:author"
},
"metadata": {
"name": "Article Title",
"author": "Angelo"
}
}
The metadata key is invisible in the expanded form.
Scoped Contexts (JSON-LD 1.1)
Type-scoped context
A context activated automatically when a node has a given @type:
json
{
"@context": {
"@vocab": "https://schema.org/",
"Person": {
"@id": "schema:Person",
"@context": {
"name": "schema:givenName"
}
}
},
"@type": "Person",
"name": "Angelo"
}
Property-scoped context
A context activated when a specific property is processed:
json
{
"@context": {
"address": {
"@id": "schema:address",
"@context": {
"street": "schema:streetAddress",
"city": "schema:addressLocality"
}
}
},
"address": { "street": "123 Main St", "city": "Aachen" }
}
@protected and @propagate (JSON-LD 1.1)
json
{
"@context": {
"@protected": true,
"name": "schema:name"
}
}
Prevents downstream contexts from redefining name. Useful for credential and ontology contexts that must not be overridden.
@propagate: false on a type-scoped context prevents it from leaking into sibling or parent nodes.
Algorithms
| Algorithm | What it does |
|---|---|
| Expansion | Removes all context; every term becomes a full IRI. Canonical intermediate form. |
| Compaction | Applies a context to produce short, readable terms. |
| Flattening | Normalizes into a flat @graph array — one entry per node, no nesting. |
| Framing | Shapes expanded data into a specific tree structure using a frame document. |
| RDF Serialization | Converts to/from N-Quads or Turtle. |
Framing example
Frame document defines the desired shape — @type and properties act as match criteria:
json
{
"@context": { "@vocab": "https://schema.org/" },
"@type": "Person",
"name": {},
"knows": {
"@type": "Person",
"name": {}
}
}
The framing algorithm picks matching nodes from a flat graph and nests them into the frame's structure.
Embedding in HTML
html
<script type="application/ld+json">
{
"@context": "https://schema.org/",
"@type": "Article",
"headline": "My Article",
"author": {
"@type": "Person",
"name": "Angelo"
},
"datePublished": "2024-01-15",
"image": "https://example.com/photo.jpg"
}
</script>
Google, Bing, and other search engines read this for rich results (rich snippets). Validate at search.google.com/test/rich-results.
Common Patterns
Compact IRIs (prefixes)
json
{
"@context": {
"schema": "https://schema.org/",
"foaf": "http://xmlns.com/foaf/0.1/"
},
"@type": "schema:Person",
"foaf:name": "Angelo"
}
@vocab fallback
Any term not explicitly defined falls back to @vocab:
json
{
"@context": { "@vocab": "https://schema.org/" },
"@type": "Person",
"name": "Angelo",
"jobTitle": "Engineer"
}
Both name and jobTitle expand to https://schema.org/name and https://schema.org/jobTitle.
Aliasing @type and @id
json
{
"@context": {
"type": "@type",
"id": "@id"
},
"id": "https://example.com/me",
"type": "Person"
}
Playground
Interactive tool at json-ld.org/playground — paste JSON-LD and view expanded, compacted, flattened, framed, and N-Quads output in real time. Supports JSON-LD 1.0 and 1.1.
Libraries
| Language | Library |
|---|---|
| JavaScript | jsonld (digitalbazaar) |
| Python | pyld |
| Java | titanium-json-ld |
| Ruby | json-ld gem |
| PHP | php-json-ld |
| Go | gojsonld |
| Rust | json-ld crate |
Use Cases
• SEO / Rich snippets — schema.org types embedded in HTML for Google Knowledge Graph, breadcrumbs, FAQs, product cards
• Verifiable Credentials — W3C VC Data Model uses JSON-LD for credential types and proof formats
• ActivityPub — the federated social web protocol (Mastodon, etc.) uses JSON-LD for activity types
• Linked Data APIs — express REST responses with machine-readable semantics without client-side schema knowledge