Docs · Why a Product Graph?
Why a Product Graph?
The runtime has to understand your product. Not parse it — understand it.
That means every object has meaning, every relationship has meaning, every workflow has meaning, and every policy has meaning. A pile of source code has none of that: the meaning lives in your head, your docs, and your onboarding calls. A product graph puts it in the artifact itself.
Closure's thesis is that the product exists as governed data. Pages, workflows, skills, and connectors are typed objects on one graph that people and AI evolve together. That's what lets the runtime render the same product as a portal, an assistant, or an agent team — and what lets AI ask questions that are almost impossible against TypeScript:
- Why does this workflow exist?
- Which experiences depend on it?
- Which policies govern it?
- Can I improve it without breaking a seal?
JSON-LD is the implementation, not the point
Nobody buys JSON-LD. You buy a product graph; JSON-LD is simply how the meaning is represented. Representing it puts hard requirements on the format:
- Global identity. Objects reference each other across orgs, packs, and
time. Every object needs an ID that survives export, import, and merge.
- Self-describing meaning. An agent (or another company's runtime) must be
able to look at an object and know what it *is* — not guess from a table
name or file path.- Typed but open. Schemas must validate payloads without freezing the
world; new object kinds appear weekly.
- Plain JSON at rest. Everything downstream — GraphQL, renderers, diffs,
version control, LLM context windows — speaks JSON.
The alternatives, honestly
| Candidate | Where it falls short for a product graph |
|---|---|
| YAML | A syntax, not a data model. No identity, no linking, no types. Fine for config; wrong for a graph of cross-referencing objects. |
| SQL / Postgres | Closure does persist in Postgres. But relational schemas freeze shape at migration time — a graph where AI adds new object kinds weekly can't live behind ALTER TABLE. Tables are the storage, not the model. |
| Document DB (Mongo etc.) | Flexible documents, but no shared semantics: nothing says what a document means, and references are conventions, not contracts. |
| RDF / OWL full stack | Semantically rigorous, practically hostile — triple stores and ontology tooling are a poor fit for product engineering and LLM workflows. |
| Proprietary format | Every low-code platform has one. It locks you in and means nothing outside that vendor's runtime. |
JSON-LD is the overlap: plain JSON any tool can read, with the three things plain JSON lacks — stable identity (@id), shared vocabulary (@context), and type (schemaRef). It is a W3C standard, so a Closure object is meaningful outside Closure.
What this buys you in practice
- One store, one API. Every object kind is the same
DataObjectshape in
GraphQL — no endpoint per feature.
- AI-native authoring. LLMs read and write JSON natively. Your IDE mutates
the same objects the console edits, via Platform MCP.
- Portable packs. An Experience Pack is a set of graph objects. Install
copies them into your org; identity and references survive the trip.
- Governance on the object, not the app. Identity, policy, and audit attach
to typed objects — which is what makes human + AI co-evolution auditable.
The 30-second anatomy
{
"@context": "https://closureapps.com/schema/context.jsonld",
"@id": "urn:uuid:7c9e6679-7425-40de-944b-e07fc1f90ae7",
"schemaRef": "schema:experience",
"name": "CRM Lite",
"orgId": "org_acme",
"data": { "slug": "crm-lite", "homePath": "/" }
}@id is who it is. schemaRef is what it is. data is the payload the schema validates. That's the whole trick — applied uniformly to everything product-shaped.
Next
- Everything is JSON-LD — the paradigm in depth
- GraphQL API — query the graph live in the playground
- The Product Graph — the longer essay