XDB is an agent-first data layer. Model once, store anywhere. Simple URIs, structured tuples, and a pipe-friendly CLI that agents and humans both get right on the first try.
Read about the motivation behind XDB in Introducing XDB.
For in-depth documentation on each concept, see docs/concepts.
The XDB data model can be visualized as a tree of Namespaces, Schemas, Records, and Tuples.
┌─────────────────────────────────┐
│ Namespace │
└────────────────┬────────────────┘
↓
┌─────────────────────────────────┐
│ Schema │
└────────────────┬────────────────┘
↓
┌─────────────────────────────────┐
│ Record │
└────────────────┬────────────────┘
↓
┌─────────────────────────────────┐
│ Tuple │
├─────────────────────────────────┤
│ ID | Attr | Value | Options │
└─────────────────────────────────┘
A Tuple is the fundamental building block in XDB. It combines:
- ID: a string that uniquely identifies the record
- Attr: a string that identifies the attribute. It supports dot-separated nesting.
- Value: The attribute's value
- Options: Key-value pairs for metadata
One or more Tuples, with the same ID, make up a Record. Records are similar to objects, structs, or rows in a database. Records typically represent a single entity or object of domain data.
A Namespace (NS) groups one or more Schemas. Namespaces are typically used to organize schemas by domain, application, or tenant.
A Schema defines the structure of records and groups them together. Schemas can be "strict" or "flexible". Strict schemas enforce a predefined structure on the data, while flexible schemas allow for arbitrary data. Each schema is uniquely identified by its name within a namespace.
XDB URIs are valid Uniform Resource Identifiers (URI) according to RFC 3986. URIs are used to uniquely identify resources in XDB.
The general format of a URI is:
[SCHEME]://[DOMAIN] [ "/" PATH] [ "?" QUERY] [ "#" FRAGMENT]
XDB URIs follow the following format:
xdb:// NS [ "/" SCHEMA ] [ "/" ID ] [ "#" ATTRIBUTE ]
xdb://com.example/posts/123-456-789#author.id
└─┬──┘└────┬────┘└──┬─┘└─────┬─────┘└─────┬─────┘
scheme NS SCHEMA ID ATTRIBUTE
└───────────┬───────────┘
path
The components of the URI are:
- NS: The namespace.
- SCHEMA: The schema name.
- ID: The unique identifier of the record.
- ATTRIBUTE: The name of the attribute.
- path: NS, SCHEMA, and ID combined uniquely identify a record (URI without xdb://)
Valid examples:
Namespace: xdb://com.example
Schema: xdb://com.example/posts
Record: xdb://com.example/posts/123-456-789
Attribute: xdb://com.example/posts/123-456-789#author.id
| Type | PostgreSQL | SQLite | Description |
|---|---|---|---|
| String | TEXT | TEXT | UTF-8 string |
| Integer | BIGINT | INTEGER | 64-bit signed integer |
| Float | DOUBLE PRECISION | REAL | 64-bit floating point number |
| Boolean | BOOLEAN | INTEGER | True or False |
| Timestamp | TIMESTAMPZ | INTEGER | Date and time in UTC |
| JSON | JSONB | TEXT | JSON data type |
| Bytes | BYTEA | BLOB | Binary data |
| Array | []T | TEXT | Array of T |
go install github.com/xdb-dev/xdb/cmd/xdb@latestxdb --version# Create schema
xdb make-schema xdb://com.example/posts --schema posts.json
# List schemas
xdb ls xdb://com.example
# Get schema
xdb get xdb://com.example/posts
# Remove schema
xdb rm xdb://com.example/posts
# Put record
xdb put xdb://com.example/posts/post-123 --file post.json
# Get record
xdb get xdb://com.example/posts/post-123
# List records
xdb ls xdb://com.example/posts
# Filter records
xdb ls xdb://com.example/posts --filter "title~Hello"
# Remove record
xdb rm xdb://com.example/posts/post-123# Create schema from definition file
xdb make-schema xdb://com.example/posts --schema ./posts.json
# Create flexible schema (no definition file)
xdb make-schema xdb://com.example/usersmake-schema creates or updates a schema at the given URI. The URI must include both NS and Schema components (e.g., xdb://com.example/posts).
If no schema definition file is provided, a flexible schema is created. Flexible schemas allow arbitrary data without validation. Schema definitions enforce structure and types on all Tuple and Record operations.
Note: You can update a schema by calling make-schema again with the same URI and a new schema definition.
# List schemas in namespace
xdb ls xdb://com.example
# List with pagination
xdb ls xdb://com.example/users --limit 10
xdb ls xdb://com.example/users --limit 10 --offset 20
# List all (default limit is 100)
xdb ls xdb://com.example
# Filter records by attribute
xdb ls xdb://com.example/users --filter "age>30"
xdb ls xdb://com.example/users --filter "name=alice"
# Multiple filters (AND logic)
xdb ls xdb://com.example/users --filter "age>=25" --filter "status!=inactive"
# Contains filter
xdb ls xdb://com.example/posts --filter "title~hello"
# Combine filters with pagination
xdb ls xdb://com.example/users --filter "age>30" --limit 10ls lists namespaces, schemas, or records depending on the URI. If no URI is provided, it lists all namespaces. Filters are only applied when listing records.
Flags:
--limit N: Maximum number of results to return (default: 100)--offset N: Number of results to skip (default: 0)--filter EXPR: Filter records by attribute (repeatable). Supported operators:=,!=,>,>=,<,<=,~(contains). Multiple filters are combined with AND logic. Filtering is applied before pagination.
# Get Namespace
xdb get xdb://com.example
# Get Schema
xdb get xdb://com.example/posts
# Get Record
xdb get xdb://com.example/posts/post-123
# Get Attribute
xdb get xdb://com.example/posts/post-123#titleget retrieves a Namespace, Schema, Record, or Attribute from the given URI.
# Put Record from JSON file
xdb put xdb://com.example/posts/post-123 --file post.json
# Put Record from stdin (JSON)
echo '{"title":"Hello","content":"World"}' | xdb put xdb://com.example/posts/post-123
# Put Record from YAML file
xdb put xdb://com.example/posts/post-123 --file post.yaml --format yaml
# Put with explicit format
echo 'title: Hello
content: World' | xdb put xdb://com.example/posts/post-123 --format yamlput creates or updates a Record at the given URI from a JSON or YAML file, or from stdin.
Flags:
--file,-f: Path to file (reads from stdin if omitted)--format: Input format: json (default) or yaml
# Remove record (with confirmation prompt)
xdb remove xdb://com.example/posts/post-123
# Remove without confirmation
xdb rm xdb://com.example/posts/post-123 --force
# Remove schema
xdb rm xdb://com.example/posts --forceremove (aliases: rm, delete) deletes a Record, Attribute, or Schema at the given URI.
Flags:
--force,-f: Skip confirmation prompt
# Start the daemon
xdb daemon start
# Check daemon status
xdb daemon status
# Stop the daemon
xdb daemon stop
# Force stop the daemon
xdb daemon stop --force
# Restart the daemon
xdb daemon restartThe daemon runs an HTTP server that handles all XDB operations. By default it listens on localhost:8147 and a Unix socket at ~/.xdb/xdb.sock.
These flags are available for all commands:
--output,-o: Output format (json, table, yaml). Auto-detected by default (table for TTY, JSON for pipes)--config,-c: Path to config file (defaults to~/.xdb/config.json)--verbose,-v: Enable verbose logging (INFO level)--debug: Enable debug logging with source locations
By default, XDB automatically selects the appropriate format:
- Table format: When output is a terminal (TTY) - human-readable tables
- JSON format: When output is piped or redirected - machine-parseable
json: Indented JSON output (machine-readable)table: Human-readable tables with bordersyaml: YAML output
# Uses table format (interactive terminal)
xdb get xdb://com.example/users/123
# Uses JSON format (piped to jq)
xdb get xdb://com.example/users/123 | jq '.name'
# Force JSON output even in terminal
xdb get xdb://com.example/users/123 --output json
# Force table output even when piping
xdb ls xdb://com.example/users --output tableXDB commands work well with Unix pipes:
# Get record and pipe to jq
xdb get xdb://com.example/posts/post-123 | jq '.title'
# List schemas and count them
xdb ls xdb://com.example | jq '. | length'
# Export records to file
xdb get xdb://com.example/posts/post-123 --output json > backup.json
# Import from file
cat backup.json | xdb put xdb://com.example/posts/post-123XDB uses a JSON config file at ~/.xdb/config.json. A default config is created automatically on first run.
{
"dir": "~/.xdb",
"daemon": {
"addr": "localhost:8147",
"socket": "xdb.sock"
},
"log_level": "info",
"store": {
"backend": "memory"
}
}- memory (default): In-memory store, data is lost on restart
- sqlite: SQLite database, stored in
<dir>/data/ - redis: Redis server, requires
addrto be configured - fs: Filesystem store, stored in
<dir>/data/by default
Example with SQLite:
{
"store": {
"backend": "sqlite",
"sqlite": {
"dir": "",
"name": "xdb.db"
}
}
}Example with Redis:
{
"store": {
"backend": "redis",
"redis": {
"addr": "localhost:6379"
}
}
}See xdb.example.yaml for a full reference of all configuration options.
