GitHub - async/db: Data-first local database toolkit from JSON fixtures to generated types, local APIs, writable stores, and production persistence.
@async/db gives frontend teams a gradual path from mock JSON to production data contracts. Drop JSON files in db/, infer schema metadata, serve REST, GraphQL, and a local data explorer, then move persistence per resource without rewriting frontend data access.
Use it to:
- Start from editable JSON, JSONC, or CSV data files in
db/. - Infer schema contracts and generate TypeScript types from data files and schemas.
- Model resource identity with
idFieldor compoundidentity.fields, plus log and bytes metadata. - Serve local REST routes, GraphQL, and a lightweight data explorer while the backend contract is still forming.
- Upgrade persistence per resource without rewriting frontend data access.
- Emit schema metadata for admin, CMS, or form-building screens.
@async/db is not a universal key/value driver layer; storage is one boundary inside the JSON-to-contract workflow.
30-Second Start
pnpm add @async/db pnpm exec async-db init pnpm exec async-db serve
Open the local data explorer at http://127.0.0.1:7331/__db and call GET /db/users.json.
No config file is required. init writes a starter JSON file, .gitignore entry for .db/, optional package scripts, and runs the first sync. Prefer a manual one-file start?
mkdir -p db printf '%s\n' '[{"id":"u_1","name":"Ada Lovelace","email":"ada@example.com"}]' > db/users.json pnpm exec async-db serve
serve syncs on startup and watches db/ for changes.
Deno Quick Start
For a Deno-only local project, use Deno's npm package support and let init write deno.json tasks instead of package scripts:
deno run --allow-read=. --allow-write=. --allow-sys=hostname npm:@async/db init --workflow deno --template data-first deno task db:serve
After deno.json exists, pass CLI arguments directly through the task, without npm or pnpm -- forwarding:
deno task db init --workflow deno --template data-first deno task db:sync deno task db:validate
Minimum Deno permissions are --allow-read=. --allow-write=. --allow-sys=hostname for sync and validation, plus --allow-net=127.0.0.1 for local serve.
File Map
| Files | Purpose |
|---|---|
db/*.json, db/*.jsonc, db/*.csv |
Data files |
db/*.schema.json, db/*.schema.jsonc, db/*.schema.js |
Optional stricter schema contracts |
db.schema.js |
Optional root schema registry for all resources |
.db/state/* |
Generated writable JSON store state |
.db/schema.generated.json, .db/types/index.d.ts |
Generated metadata and types |
Install
Add package scripts for the CLI commands you run often:
{
"scripts": {
"db": "async-db",
"db:sync": "async-db sync",
"db:serve": "async-db serve",
"db:types": "async-db types"
}
}Deno projects can skip package.json and use a generated deno.json instead:
{
"nodeModulesDir": "auto",
"tasks": {
"db": "deno run --allow-read=. --allow-write=. --allow-sys=hostname npm:@async/db@0.14.0",
"db:sync": "deno task db sync",
"db:types": "deno task db types",
"db:validate": "deno task db schema validate",
"db:serve": "deno run --allow-read=. --allow-write=. --allow-sys=hostname --allow-net=127.0.0.1 npm:@async/db@0.14.0 serve"
}
}The package import name is @async/db. Helpers are available from @async/db/config, @async/db/schema, @async/db/client, and the compatibility JSON engine subpath @async/db/json. The standalone @async/json package owns direct JSON file/folder database usage.
Five-Minute Start
Create a JSON file:
mkdir -p db cat > db/users.json <<'JSON' [ { "id": "u_1", "name": "Ada Lovelace", "email": "ada@example.com" } ] JSON
Sync generated metadata, types, and runtime state:
Start the local server:
Open the local data explorer at http://127.0.0.1:7331/__db.
Call the REST API:
curl http://127.0.0.1:7331/db/users.json
Create a local record:
curl -X POST http://127.0.0.1:7331/db/users \ -H 'content-type: application/json' \ -d '{"id":"u_2","name":"Grace Hopper","email":"grace@example.com"}'
Default sync output:
.db/schema.generated.json .db/types/index.d.ts .db/state/users.json
Local responses include a small 30-100ms mock delay by default so loading states are visible. It is skipped automatically when NODE_ENV=production. Disable it locally when you want immediate responses:
export default { mock: { delay: false }, };
See docs/getting-started.md for the expanded walkthrough, including async-db init --template schema-first and --template source-file.
Defaults
| Behavior | Default |
|---|---|
| Source data files | Read from ./db |
| App data routes | Exposed under /db, such as GET /db/users.json |
| Runtime writes | Go to the JSON store under .db/state |
| Local server | 127.0.0.1:7331 |
| REST | Enabled |
| GraphQL / Falcor | Disabled until you opt in |
| Schema drift | Warn on unknown fields |
Add Schema When It Pays For It
Data-first JSON files are enough until the shape matters:
pnpm run db -- schema infer users pnpm run db -- schema infer users --out db/users.schema.jsonc pnpm run db -- schema validate
Add db/users.schema.json, db/users.schema.jsonc, or db/users.schema.js when you need stricter behavior, defaults, relations, or Standard Schema validators.
See docs/concepts.md and docs/data-files-and-schemas.md.
Common Commands
pnpm run db -- sync
pnpm run db -- types
pnpm run db -- schema validate
pnpm run db -- doctor
pnpm run db -- create users '{"id":"u_2","name":"Grace Hopper","email":"grace@example.com"}'
pnpm run db -- serve
pnpm run db -- init --template data-first
pnpm run db -- init --template schema-first
pnpm run db -- init --template source-fileSee docs/package-api.md for CLI and package export details.
Going To Production
The default path stays small on purpose: every resource is born a draft, and async-db promote <resource> moves it to production — pinning the seed, capturing the schema, and turning on write-ahead-log durability (--fsync always|everysec|no). async-db status shows each resource's phase; see docs/shape-is-the-contract.md for the full story. When a resource gets serious, follow the ladder:
| Tier | When | Next step |
|---|---|---|
| 0 — JSON files | Prototype with JSON in db/ |
You are here after init or serve |
| 1 — Contracts | Shape, defaults, and types matter | Add schema files and committed generated types |
| 2 — Hardened API | Browser or external clients consume data | Registered operations, server.expose, contracts, doctor --production |
| 3 — Mixed stores | JSON is no longer the right persistence | Per-resource store graduation to SQLite, Postgres, or custom stores |
Production topics:
- Production JSON Database: scoped JSON for flags, settings, and control-plane data
- Prototype To Production REST Guide: move
/db/*to/api/*, registered operation refs, route lockdown - Resource Graduation And Mixed Stores: graduate one resource at a time
- Configuration:
server.expose, operations, contracts, stores, and mock behavior - Contracts CLI:
async-db contracts infer,async-db contracts check,async-db contracts refs
The built-in JSON store is production-appropriate only for file-suitable resources: app settings, feature flags, content, templates, and other small low-write data with a single writer. Writes are fsync-durable atomic file replaces guarded by a per-resource cross-process lock; durability: 'versioned' keeps undoable per-write history with async-db backup/restore on top; REST supports ETag/If-Match/If-None-Match; and GET /__db/health, server.authorize, per-resource audit trails, and AES-256-GCM encryption at rest cover the operational basics. Keep high-write user data, chat, analytics, ledgers, and compliance-heavy records in SQLite, Postgres, or another app-owned store.
@async/db is not an auth layer, an ORM, or a hosted database service. Put production traffic behind registered operations, app-owned auth, rate limits, and observability.
Examples
Run pnpm run examples to open the grouped examples index, or sync and serve one example directly:
pnpm run db -- sync --cwd ./examples/basic pnpm run db -- serve --cwd ./examples/basic
Start here
| Example | What it shows |
|---|---|
examples/data-first |
Plain JSON files before schemas exist |
examples/deno-basic |
Deno-only tasks through npm:@async/db |
examples/basic |
Shortest schema-backed workflow |
examples/schema-first |
Schema-only resources and empty seed records |
examples/csv |
CSV inference and mirror refreshes |
Core workflows
| Example | What it shows |
|---|---|
examples/relations |
Relation metadata, expand, nested select |
examples/rest-client |
createDbClient, REST batching |
examples/diagnostics |
File-specific warnings without breaking valid resources |
examples/computed-fields |
Computed field patterns across several models |
examples/content-collections |
Docs/blog folders as static content collections |
examples/standard-schema |
Standard Schema validators with Async DB overlays |
examples/schema-manifest |
Committed schema metadata for admin/CMS UI |
examples/schema-ui |
Manifest-driven SSR admin templates |
examples/advanced |
Mixed mode, defaults, nested objects |
Production and app patterns
| Example | What it shows |
|---|---|
examples/production-json |
Feature flags and settings behind registered operations |
examples/hono-auth |
Optional Hono auth and write hooks |
examples/cms-json-publish |
App-owned CMS publish flow over branches |
examples/free-plan-upgrade |
Tenant resource graduation from JSON to another store |
examples/local-web-app |
Loopback app state saved directly to db/*.json |
Each example README is the runnable authority for that example.
Docs Map
| Task | Read |
|---|---|
| Start a project | docs/getting-started.md |
| Understand the product story | docs/shape-is-the-contract.md |
| Build a docs site / use MDX | docs/docs-and-mdx.md |
| Understand the model | docs/concepts.md |
| Author data files and schemas | docs/data-files-and-schemas.md |
| Manage generated output | docs/generated-files.md |
| Configure @async/db | docs/configuration.md |
| Use JSON in production safely | docs/json-production.md |
| Serve local data and explore it locally | docs/server-and-viewer.md |
| Graduate REST prototypes | docs/prototype-to-production.md |
| Use the package API or CLI | docs/package-api.md |
| Review public API surface | API_SURFACE.md |
| Integrate with Vite, Hono, or SQLite | docs/integrations.md |
For the full product behavior and acceptance model, see SPEC.md.