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

KeywordPurpose
@contextMaps terms to IRIs — defines the vocabulary
@idIdentifies the subject (IRI or blank node)
@typeRDF type — shorthand for rdf:type
@valueExplicit literal value inside a value object
@languageBCP47 language tag for a string
@directionText direction: "ltr", "rtl", or null
@graphNamed graph container
@listOrdered list (RDF list semantics)
@setUnordered collection — forces array output
@reverseExpresses an inverse property relationship
@indexMarks a container as indexed by arbitrary keys
@nestGroups properties without creating graph edges
@noneFallback index key for unmapped values
@vocabDefault IRI prefix for unknown terms
@baseBase IRI for resolving relative references
@versionProcessing mode — 1.1 to enable JSON-LD 1.1
@prefixWhether a term can be used as a compact IRI prefix
@protectedPrevents a term definition from being overridden
@propagateControls whether a context propagates into nested nodes
@importMerges an external context into the current one
@includedSecondary node objects embedded in a top-level node
@jsonDatatype 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

ValueEffect
@listTreat property value as an ordered RDF list
@setAlways represent value as an array
@languageKeys are language tags, values are strings (language map)
@indexKeys are arbitrary string indices (no graph semantics)
@idKeys are @id values of the associated node objects
@typeKeys are @type IRIs of the associated node objects
@graphValue 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

AlgorithmWhat it does
ExpansionRemoves all context; every term becomes a full IRI. Canonical intermediate form.
CompactionApplies a context to produce short, readable terms.
FlatteningNormalizes into a flat @graph array — one entry per node, no nesting.
FramingShapes expanded data into a specific tree structure using a frame document.
RDF SerializationConverts 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

LanguageLibrary
JavaScriptjsonld (digitalbazaar)
Pythonpyld
Javatitanium-json-ld
Rubyjson-ld gem
PHPphp-json-ld
Gogojsonld
Rustjson-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