Code-first database toolkit for SurrealDB. Type-safe query builder, schema/migration engine, orchestrator, and surql CLI — all from TypeScript, for Deno and Node.js.
- Fluent Query Builder — Chainable API for SELECT/INSERT/UPDATE/DELETE with full generics;
typeRecord,timeNow,mathSum,countIf,stringLowerand friends render inline in both expression andSETcontexts. - Code-first Schema + Migrations —
DEFINEemitters withIF NOT EXISTS, structured schema parser, migration runner, squash, rollback, and drift detection. - SurrealDB v3 correctness — Buffered
BEGIN ... COMMIT, unrolledGraphQuerydepth, v3-validtype::record()everywhere. surqlCLI —migrate,schema,db,orchestrate,settingssubcommands (built on@cliffy/command).- Multi-runtime — JSR for Deno, npm for Node.js 18+.
- Layered settings — env +
.env+surql.yaml+surql.tomlvialoadSettings(). - Auth & CRUD — Root/Namespace/Database/Scope sign-in, JSON Patch (RFC 6902), merge, upsert, aggregations, pagination.
- Input sanitisation — Identifier validation, injection prevention, rich error types.
=== "Deno (JSR)"
```ts
import { SurQLClient, query } from 'jsr:@oneiriq/surql'
```
Or via an import map in `deno.json`:
```json
{ "imports": { "surql": "jsr:@oneiriq/surql" } }
```
=== "Node.js (npm)"
```bash
npm install @oneiriq/surql
```
```ts
import { SurQLClient, query } from '@oneiriq/surql'
```
import {
aggregateRecords,
count,
countIf,
createRecord,
getRecord,
mathSum,
SurQLClient,
timeNow,
typeRecord,
updateRecord,
} from 'jsr:@oneiriq/surql'
const client = new SurQLClient({
host: 'localhost',
port: '8000',
namespace: 'myapp',
database: 'prod',
username: 'root',
password: 'root',
})
await client.signin({ type: 'root', username: 'root', password: 'root' })
const db = await client.getConnection()
// First-class record references — render as type::record('task:abc').
const task = typeRecord('task', 'abc')
// time::now() / math::sum() render inline in SET clauses.
await createRecord(db, 'audit', { at: timeNow(), action: 'start' })
await updateRecord(db, task, { status: 'done', finishedAt: timeNow() })
// typeRecord works for reads too.
const row = await getRecord<Task>(db, task)
// Typed aggregation — no hand-rolled SurrealQL.
const buckets = await aggregateRecords({
table: 'memory_entry',
select: {
total: count(),
failed: countIf('status = "failed"'),
strengthSum: mathSum('strength'),
},
groupBy: ['network'],
client: db,
})
await client.close()# Run from a clone
deno task cli --help
# Apply pending migrations
deno task cli migrate up
# Inspect live schema vs snapshot
deno task cli schema diff --schema db/snapshot.json
# Orchestrate across environments (JSON config)
deno task cli orchestrate deploy --environments staging,production --strategy rolling --batch-size 2The full reference lives at docs/cli.md (rendered on the docs site).
- Full docs site: https://oneiriq.github.io/surql
- Upgrade guide — v1.1.0 → v1.2.0 → v1.3.x
- SurrealDB v3 patterns
- Query UX —
typeRecord, function factories,aggregateRecords, overloads - CLI
- Changelog
- Deno 2.x or Node.js 18+
- SurrealDB v3 (integration tests pinned to
surrealdb/surrealdb:v3.0.5)
Local gating is enforced by .githooks/pre-push (mirrors CI). Enable once per clone:
git config core.hooksPath .githooksSee CONTRIBUTING.md.
MIT — see LICENSE.
Looking for SurrealDB tooling in Python? See surql-py — the code-first schema, migration, and query toolkit for SurrealDB built for Python 3.12+.
- Issues: GitHub Issues
- Changelog: CHANGELOG.md