Skip to content

Schemas Overview

A schema is a TypeScript definition that describes the shape of your data. Every node in xNet conforms to a schema.

import { defineSchema, text, select, date } from '@xnet/data'
export const TaskSchema = defineSchema({
name: 'Task',
namespace: 'xnet://my-app/',
properties: {
title: text({ required: true }),
status: select({
options: [
{ id: 'todo', name: 'To Do' },
{ id: 'done', name: 'Done' }
] as const
}),
dueDate: date({ includeTime: true })
}
})

This gives you:

  • Type safetytask.status is 'todo' | 'done', not string
  • Validation — required fields are enforced, values are range-checked
  • Identity — the schema has a unique IRI: xnet://my-app/Task
  • Coercion — values are normalized on creation (trimming, type conversion)

The type inference flows from schema definition through every hook:

defineSchema({ properties: { title: text(), ... } })
useQuery(TaskSchema) → { data: { id, title, ... }[] }
useMutate().create(TaskSchema, { title: '...' })
useNode(TaskSchema, id) → { data: { id, title, ... } }

You define types once. Every hook infers from the schema.

Every schema has:

FieldRequiredDescription
nameYesDisplay name (e.g., 'Task', 'Page').
namespaceYesMust match `xnet://${string}/`. Groups related schemas.
propertiesYesRecord of property builders (e.g., text(), select()).
extendsNoParent schema to inherit properties from.
documentNoCRDT document type: 'yjs' for rich text editing.

The schema IRI is computed as ${namespace}${name} — e.g., xnet://my-app/Task.