Architecture
One engine, seen from above.
Five ways to ask, one request path, and the right engine for your data. Zoom into a card to see inside it; click a piece to see what it does and what it talks to.
Loading the map…
How a question travels.
- You ask in plain English — from the chat, an HTML element, the CLI, an agent over MCP, or the SDK. Same endpoint either way.
- The edge router picks up the request at the nearest Cloudflare location, and auth & quota decide who you are (anonymous is fine) and what you may spend.
- The plan cache looks up the question by (schema_hash, query_hash). On a hit — the majority of traffic — the LLM is never involved.
- On a miss, the NL→plan compiler asks the LLM for a typed plan, and the validator checks it against an allowlist before it can run. The model never writes raw SQL.
- The executor runs the plan on the engine your data lives in and streams back the answer, the rows, and a trace with per-step timings.
You ask — five surfaces, one call.
Every surface is a projection of the same engine — the web chat, the <nlq-data> element, the CLI, the MCP server, and the SDK all end up making the same POST /v1/ask call with a goal in plain English.
- Chat web app
- nlqdb.com/app — every reply comes back as a one-sentence answer, the raw data, and a trace you can open.
- <nlq-data> element
- One HTML tag on any site: a goal in plain English in, rendered data out. The whole client is ≤ 6 KB.
- nlq CLI
- A single static Go binary. `nlq "how many signups today"` — goal-first, starts in milliseconds.
- MCP server
- Claude, Cursor, Windsurf, and Zed talk to nlqdb as agent memory over MCP — typed rows the agent writes as it learns.
- SDK / HTTP API
- POST /v1/ask { goal } — the one endpoint every SDK wraps, from TypeScript to Swift, Ruby, and Rust.
The engine — one request path, no backend to write.
One edge-routed request path: authenticate, check the plan cache, and only on a miss ask the LLM for a typed plan — which is validated before anything touches your data. The LLM never emits raw SQL.
- Edge router
- Cloudflare Workers at the edge — under 50 ms from anywhere. Every surface lands here first.
- Auth & quota
- Better Auth + Workers KV. Anonymous works out of the box; rate limits fire before any model spends a token.
- Plan cache
- Plans are content-addressed by (schema_hash, query_hash) — no invalidation, ever. 60–80% of queries skip the LLM entirely.
- NL→plan compiler
- On a cache miss, the LLM router turns English into a typed query plan — never a raw SQL string.
- Validator
- An AST allowlist between the model and your data: reads stay reads, writes are previewed, and DDL only ever comes from our deterministic compiler.
- Executor
- Runs the validated plan on the right engine and streams rows back — with the trace that shows every step and its timing.
Your data — the right engine per workload.
Storage is a routing decision, not your problem. Postgres is the default home; ClickHouse serves analytics-shaped workloads; the adapter layer is engine-agnostic so more engines slot in behind the same executor.
- Postgres
- The default home for your data — Neon under the hood, one schema per tenant, row-level security on.
- ClickHouse
- Bring the warehouse you already run — ClickHouse or Tinybird — and question it in English.
- More engines roadmap
- The adapter is engine-agnostic: a workload analyser watches your query shapes and proposes the engine that fits (Redis, D1, …).