Appearance
Quad Runtime
FreshThe Quad Runtime concept describes a paradigm shift: instead of querying a database with a query language, you work with a plain JavaScript array of RDF quads, using standard JavaScript as your graph traversal and transformation language.
The Core Insight
Text → Quad[] → TextEverything flows through this loop. The document is the source. The array is the runtime. The text output is the result. No database engine, no query processor, no ORM, no schema migration, no connection string.
Quad[] as a Universal Semantic Runtime
An RDF quad is an object with four fields:
javascript
{
subject: { termType: 'NamedNode', value: 'http://example.org/alice' },
predicate: { termType: 'NamedNode', value: 'http://xmlns.com/foaf/0.1/knows' },
object: { termType: 'NamedNode', value: 'http://example.org/bob' },
graph: { termType: 'DefaultGraph', value: '' }
}An array of these is already a graph. JavaScript already knows how to work with arrays. No translation layer needed.
JavaScript as the Query Language
Replace SQL/SPARQL with standard JavaScript:
javascript
// SPARQL: SELECT ?person WHERE { ?person rdf:type prov:Person }
const persons = quads
.filter(q =>
q.predicate.value === 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' &&
q.object.value === 'http://www.w3.org/ns/prov#Person'
)
.map(q => q.subject.value);
// SPARQL: SELECT ?email WHERE { ex:alice ex:email ?email }
const aliceEmails = quads
.filter(q =>
q.subject.value === 'http://example.org/alice' &&
q.predicate.value === 'http://example.org/email'
)
.map(q => q.object.value);The query syntax is the same JavaScript you already know. No new language. No parser. No optimizer. Direct array operations.
Building Indexes On Demand
When you need performance, build a Map:
javascript
// Build subject index: IRI → array of quads about that subject
const bySubject = new Map();
for (const quad of quads) {
const key = quad.subject.value;
if (!bySubject.has(key)) bySubject.set(key, []);
bySubject.get(key).push(quad);
}
// Now O(1) lookup
const aliceQuads = bySubject.get('http://example.org/alice');Build any index the problem requires. Discard it when done. No schema declaration required.
Graph Traversal in Plain JavaScript
Follow relationships across the graph:
javascript
function getProperties(quads, iri) {
return quads
.filter(q => q.subject.value === iri)
.reduce((acc, q) => {
const key = q.predicate.value.split(/[#/]/).pop();
acc[key] = q.object.value;
return acc;
}, { iri });
}
function follow(quads, startIRI, predicateIRI) {
return quads
.filter(q =>
q.subject.value === startIRI &&
q.predicate.value === predicateIRI
)
.map(q => q.object.value);
}
// Who does Alice know?
const aliceKnows = follow(quads, 'http://example.org/alice', 'http://example.org/knows');
// Get full profile for each person Alice knows
const profiles = aliceKnows.map(iri => getProperties(quads, iri));Integration with the Entire JS Ecosystem
Because quads are plain JS objects in a plain array, they integrate with everything:
javascript
// Filter by type
import { quads } from './parsed-document.js';
const activities = quads.filter(q =>
q.predicate.value.endsWith('#type') &&
q.object.value.endsWith('#Activity')
);
// Serialize to Turtle using n3.js
import { Writer } from 'n3';
const writer = new Writer({ prefixes: context });
writer.addQuads(quads);
writer.end((error, result) => console.log(result));
// Query with sparqljs
import { translate } from 'sparqljs';
const query = translate('SELECT * WHERE { ?s ?p ?o }');
// Apply query to quads
// Validate with shacl-engine
import SHACLEngine from 'shacl-engine';
const report = SHACLEngine.validate(quads, shapesQuads);The Document-First Architecture
The MD-LD approach inverts the typical database-first architecture:
Database-first (traditional):
- Design schema
- Configure database
- Write ORM models
- Write queries
- Convert results to objects
- Render to users
Document-first (MD-LD):
- Write documents
- Parse to quads
- Operate on quads with JavaScript
- Generate back to documents
The document is the schema, the storage, and the display format. The array is the database, the ORM, and the query engine.
Local-First by Default
Because quads live in memory as JavaScript objects:
- No network round-trips for queries
- No connection management
- No authentication to a database
- No serialization/deserialization overhead
Everything runs locally, in the same JavaScript runtime as the rest of your application.
Merge as Database JOIN
javascript
import { merge } from 'mdld-parse';
// Combine multiple knowledge documents
const { quads } = merge([doc1, doc2, doc3]);
// The merged quads are a single array
// Retractions are resolved automatically
// Duplicates (same triple from multiple docs) are deduplicatedThe merge() function replaces database JOINs for the common case of combining knowledge from multiple sources. It handles polarity (retractions) automatically.
Streaming and Workers
For large quad sets, use Web Workers or Node.js worker_threads:
javascript
// In a worker
import { parse } from 'mdld-parse';
self.onmessage = ({ data: { text } }) => {
const { quads, primary } = parse({ text });
self.postMessage({ quads, primary });
};The quads are transferable objects — they can cross the thread boundary without copying.
When to Use a Real Triple Store
The Quad Runtime is designed for:
- Single-file or small-collection knowledge bases (under ~50K quads in memory)
- Local-first applications
- Applications where the document is the primary artifact
- LLM agent contexts where knowledge needs to be in the prompt
For truly large-scale graph databases (millions of triples, complex SPARQL queries, federation), use n3.js with a real triple store. The quads produced by MD-LD are RDF/JS compatible and work with any standard RDF tooling.