# nlqdb > Analytical memory for AI agents. A real database your agent connects to over > MCP and queries in English — GROUP BY, JOIN, aggregate over what it remembered, > not just the top-k a vector store recalls. Also a natural-language database for > any app. nlqdb gives an AI agent a real Postgres database it uses as memory: it writes typed rows as it learns and asks questions in plain English, so it can analyse its memory (counts, top-N, per-group rollups) instead of only recalling similar chunks. The LLM never emits SQL — it returns a typed plan, the compiler emits parameterised SQL, `libpg_query` re-validates it, and every answer carries the exact SQL it ran. The same engine is also a generalist natural-language database: state a goal in English and the system materialises the database that fits the workload, migrating engines underneath as it evolves. Five surfaces share one engine: an HTML element (``), a typed SDK, a CLI (`nlq`), an MCP server (`mcp.nlqdb.com`), and a chat web app at app.nlqdb.com. ## For coding agents Setting up memory for the app you build with? One command connects nlqdb over MCP: ```bash claude mcp add --transport http nlqdb https://mcp.nlqdb.com/mcp ``` That hosted route authenticates with a browser OAuth on the first tool call — no API key to paste, but it does need a human at a browser. **With nobody at a browser, take the headless route instead:** the same five tools run locally over stdio against the same production API, authenticated by a key, so no browser ever opens. Mint an `sk_mcp_` MCP key at https://app.nlqdb.com/app/keys (one signed-in visit) — scoped to MCP, not your whole account, and revocable on its own — then: ```bash claude mcp add --env NLQDB_API_KEY=sk_mcp_REPLACE_ME --transport stdio nlqdb -- npx -y @nlqdb/mcp ``` Other hosts (Codex, Cursor, VS Code, Claude Desktop, Windsurf, Zed), both routes per host, and the full machine-followable guide — expected tools, a verification query, what to do on failure — are at https://docs.nlqdb.com/agent-memory/. Two write paths, both live for signed-in keys: `nlqdb_query` (provision + query in English, always on) and the typed `nlqdb_remember` verb over the `agent_memory_v1` preset — create one with `POST /v1/databases { "preset": "agent_memory_v1" }` (or the dashboard), pass its id as `db`, and fact `kind` + `tags` become your GROUP BY columns. Building this into a repo with Claude Code? The plugin wires the server AND the instructions in one step, replacing the connect command above — run both lines inside Claude Code: ```bash /plugin marketplace add nlqdb/nlqdb /plugin install nlqdb-memory@nlqdb ``` The plugin is nlqdb's published artifacts directory itself, so its two skills are the same files below, never copies. It authenticates by the hosted route (browser OAuth once); for a headless host use the stdio command above. On any other host, one command installs the skill alone (Cursor, Codex, and 15 more — via the public repo, no account, no publish): ```bash npx skills add https://github.com/nlqdb/nlqdb/tree/main/apps/web/public/agent-artifacts/nlqdb-memory ``` It writes `.agents/skills/nlqdb-memory/SKILL.md` — the cross-agent skill directory Cursor and Codex read directly — plus a `.claude/skills/` symlink to it (Claude Code documents only `.claude/skills/`) and a `skills-lock.json` (verified against the live CLI 2026-07-25). It does NOT write a `.cursor/rules/` file and does NOT edit `AGENTS.md`; a host that reads only `AGENTS.md` still needs the snippet below appended by hand. Or drop a ready-made file into the codebase by hand — every connect string in them is pinned by a test to nlqdb's own source of truth, so they can't drift: - Host-neutral `AGENTS.md`: append https://nlqdb.com/agent-artifacts/AGENTS.snippet.md - Claude Code skill: save https://nlqdb.com/agent-artifacts/nlqdb-memory/SKILL.md to `.claude/skills/nlqdb-memory/SKILL.md` - Cursor: save https://nlqdb.com/agent-artifacts/nlqdb-memory.mdc to `.cursor/rules/nlqdb-memory.mdc` - Codex: merge https://nlqdb.com/agent-artifacts/codex-config.toml into `~/.codex/config.toml` Working in a repo whose `docs/` hold its operating state? A second skill points the same memory at those docs — it extracts the *structure* (decision ids + statuses, open questions with dates, queues, trackers, and the references between them), never prose, so "which features have open questions older than 30 days" and "which decisions reference GLOBAL-013" become one query. One-way: markdown stays the source of truth, nlqdb never writes it. ```bash npx skills add https://github.com/nlqdb/nlqdb/tree/main/apps/web/public/agent-artifacts/nlqdb-docs-memory ``` Or by hand: save https://nlqdb.com/agent-artifacts/nlqdb-docs-memory/SKILL.md to `.claude/skills/nlqdb-docs-memory/SKILL.md`. ## Integrate Add nlqdb to an app. Every surface calls the same `/v1/ask` engine — pick one; each snippet is the smallest runnable shape, and the link is the page to read next. Full machine-readable docs index: https://docs.nlqdb.com/llms.txt ### HTML element drop a tag, ship the page. [Docs →](https://docs.nlqdb.com/tutorials/html/) ```html ``` ### TypeScript SDK fetch is the SDK — zero deps, runs anywhere. [Docs →](https://docs.nlqdb.com/sdk/) ```ts npm i @nlqdb/sdk import { createClient } from "@nlqdb/sdk"; const client = createClient({ apiKey: process.env.NLQDB_KEY! }); const res = await client.ask({ goal: "today's orders, newest first", dbId: "orders" }); ``` ### CLI one binary, two verbs. [Docs →](https://docs.nlqdb.com/cli/) ```bash curl -fsSL https://nlqdb.com/install | sh nlq "an orders tracker for my coffee shop" ``` ### MCP server talk to your data from Claude, Cursor, Zed, Windsurf. [Docs →](https://docs.nlqdb.com/mcp/) ```json { "mcpServers": { "nlqdb": { "url": "https://mcp.nlqdb.com/mcp" } } } ``` ### HTTP API raw POST /v1/ask, no SDK required. [Docs →](https://docs.nlqdb.com/reference/http-api/) ```bash curl -X POST https://app.nlqdb.com/v1/ask \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{"goal":"today orders, newest first","dbId":"orders"}' ``` ## Pages - [Homepage](https://nlqdb.com/): Pitch, embed demo, live carousel. - [Agents](https://nlqdb.com/agents/): Analytical memory for AI agents — give an agent a real Postgres it can GROUP BY, JOIN, and aggregate over, not just top-k vector recall. - [Agent-memory benchmark landscape](https://nlqdb.com/agent-memory-benchmarks/): What LoCoMo, LongMemEval, DMR, Mem0 and Zep actually measure, whose numbers are self-reported or disputed, and the analysis-over-memory gap none of them test — every figure linked to its source. - [Manifesto](https://nlqdb.com/manifesto/): Nine non-negotiables that decide every nlqdb design choice. - [Architecture](https://nlqdb.com/architecture/): How nlqdb works — five surfaces, one edge-routed engine, the right data engine per workload — as an interactive 3D map with a full prose walkthrough. - [Integrations](https://nlqdb.com/integrations/): Frameworks, MCP hosts, and surfaces nlqdb already plugs into. - [Comparisons](https://nlqdb.com/vs/): Honest side-by-side against adjacent tools (Supabase, Vanna, Mem0, Outerbase, …). - [Solve pages](https://nlqdb.com/solve/): One page per recurring search query; each answers the question with a working snippet and names what nlqdb doesn't do. - [Blog](https://nlqdb.com/blog/): Engineering notes from building nlqdb — SQL traps, LLM-pipeline debugging, honest comparisons. - [Pricing](https://nlqdb.com/pricing/): Free forever; upgrade when you need more. No credit card for the free tier. ## Comparisons - [nlqdb vs Supabase](https://nlqdb.com/vs/supabase/): Pick Supabase if you want a full BaaS — auth, storage, edge functions, and a SQL Studio you'll write queries in yourself. Pick nlqdb if you want to ship data features by writing English, with the schema, engine, and indexes invisible. - [nlqdb vs Neon](https://nlqdb.com/vs/neon/): Pick Neon if you want best-in-class serverless Postgres — instant branching, scale-to-zero, and an AI coding agent that manages the database for you. Pick nlqdb if you want the answer itself: one HTML element that turns an English question into validated SQL, in your product, for your users. - [nlqdb vs Vanna AI](https://nlqdb.com/vs/vanna/): Pick Vanna if you have an existing database and want an OSS layer that translates English into SQL against it. Pick nlqdb if you also want the database itself — provisioned, schema-managed, and queryable via SDK / CLI / MCP from day one. - [nlqdb vs Mem0](https://nlqdb.com/vs/mem0/): Pick Mem0 if you want an opinionated memory primitive — add / search / forget — tuned for LLM agent contexts. Pick nlqdb if your agent also needs to query structured data, run reports, and migrate its own schema. - [nlqdb vs Outerbase](https://nlqdb.com/vs/outerbase/): Pick Outerbase if you already run a production database and want an AI-assisted admin UI — spreadsheet edits, EZQL natural-language queries, dashboards — sitting on top of it. Pick nlqdb if you want the database itself provisioned, schema evolved via English, and one HTML element rendering answers in your own app. - [nlqdb vs Wren AI](https://nlqdb.com/vs/wrenai/): Pick Wren AI if you already run a warehouse (BigQuery, Snowflake, PostgreSQL, DuckDB) and want a semantic model — models, metrics, cubes, RLAC/CLAC — governing every English question an AI agent asks. Pick nlqdb if you want the database itself provisioned, schema evolved via English, and answers rendered inside your app from one HTML element. - [nlqdb vs AskYourDatabase](https://nlqdb.com/vs/askyourdatabase/): Pick AskYourDatabase if you already run BigQuery, MSSQL, MySQL, PostgreSQL, or Snowflake and want a chat assistant — desktop or embedded — answering English questions over that warehouse with charts and a dashboard builder. Pick nlqdb if you want the database itself provisioned, schema evolved via English, and answers rendered inside your product from one HTML element. - [nlqdb vs Zep](https://nlqdb.com/vs/zep/): Pick Zep if your agent needs a temporal knowledge graph — point-in-time fact recall and entity resolution tuned for conversation. Pick nlqdb if your agent also needs to aggregate that memory: GROUP BY, JOIN, and HAVING over structured rows it provisions and migrates itself in plain English. - [nlqdb vs Letta](https://nlqdb.com/vs/letta/): Pick Letta if you want a stateful agent runtime that manages its own memory like an OS — self-editing core blocks plus a searchable archive. Pick nlqdb if your agent also needs to aggregate that memory: GROUP BY, JOIN, and HAVING over structured rows it provisions and migrates itself in plain English. - [nlqdb vs LangMem](https://nlqdb.com/vs/langmem/): Pick LangMem if you want long-term memory wired into a LangGraph agent — semantic, episodic, and procedural memory the LLM extracts and consolidates for you. Pick nlqdb if your agent also needs to aggregate that memory: GROUP BY, JOIN, and HAVING over structured rows it provisions and migrates itself in plain English. - [nlqdb vs Pinecone](https://nlqdb.com/vs/pinecone/): Pick Pinecone if your agent retrieves by semantic similarity — nearest-neighbour search over embeddings with metadata filters, plus hosted embedding and reranking. Pick nlqdb if your agent must aggregate what it stored: GROUP BY, JOIN, and HAVING over typed rows it provisions and migrates itself in plain English. Pinecone finds the similar; nlqdb counts, groups, and ranks. - [nlqdb vs Chroma](https://nlqdb.com/vs/chroma/): Pick Chroma if your agent recalls by similarity and you want an open-source store you can run embedded or self-hosted — nearest-neighbour plus full-text and metadata filtering. Pick nlqdb if your agent must aggregate what it stored: GROUP BY, JOIN, and HAVING over typed rows it provisions in plain English. Chroma finds the similar; nlqdb counts, groups, and ranks. - [nlqdb vs Weaviate](https://nlqdb.com/vs/weaviate/): Pick Weaviate if your agent recalls by hybrid search — BM25 keyword fused with vector similarity — at enterprise scale with multi-tenancy, replication, and RBAC. Pick nlqdb if your agent must aggregate what it stored: GROUP BY, JOIN, and HAVING over typed rows it provisions in plain English. Weaviate ranks the relevant; nlqdb counts, groups, and reports. - [nlqdb vs Qdrant](https://nlqdb.com/vs/qdrant/): Pick Qdrant if your agent recalls by fast, memory-efficient vector search — quantized HNSW with dense-plus-sparse hybrid ranking, self-hostable on Apache-2.0. Pick nlqdb if your agent must aggregate what it stored: GROUP BY, JOIN, and HAVING over typed rows it provisions in plain English. Qdrant ranks the relevant cheaply; nlqdb counts, groups, and reports. - [nlqdb vs Cognee](https://nlqdb.com/vs/cognee/): Pick Cognee if your agent recalls by reasoning over a knowledge graph — entities and relationships fused with vector similarity for context-rich semantic recall. Pick nlqdb if your agent must aggregate what it stored: GROUP BY, JOIN, and HAVING over typed rows it provisions in plain English. Cognee connects and recalls the relevant; nlqdb counts, groups, and reports. - [nlqdb vs Julius AI](https://nlqdb.com/vs/julius/): Pick Julius AI if you're an analyst who wants to upload a spreadsheet and chat your way to charts and a Python notebook. Pick nlqdb if you're building a product or agent that needs English-to-SQL over a database it provisions — embeddable, API-first, with every write diff-previewed. - [nlqdb vs Retool](https://nlqdb.com/vs/retool/): Pick Retool if you want to build internal admin tools and dashboards — visually, on top of a database you already run — with AI that scaffolds the app and writes the queries. Pick nlqdb if you want to skip building the UI entirely: provision the database, ask in English, and render the answer inline in your own product or agent. - [nlqdb vs Basedash](https://nlqdb.com/vs/basedash/): Pick Basedash if you want governed BI dashboards and daily AI briefings over data you already store across 750+ sources. Pick nlqdb if you want to own the database itself — provision Postgres, ask in English, write and migrate with diff-previews, and embed the answer inline in your product or agent. - [nlqdb vs Metabase](https://nlqdb.com/vs/metabase/): Pick Metabase if you want an open-source BI tool to build dashboards and let analysts ask charts in chat over your existing warehouse. Pick nlqdb if you're building a product or agent that needs English-to-SQL over a database it provisions — embeddable, API-first, every write diff-previewed. - [nlqdb vs Hex](https://nlqdb.com/vs/hex/): Pick Hex if you're an analyst or data team that wants a collaborative SQL + Python notebook over your existing warehouse, with AI-written code, charts, and published data apps. Pick nlqdb if you're building a product or agent that needs English-to-SQL over a database it provisions — embeddable, API-first, with every write diff-previewed. - [nlqdb vs Milvus](https://nlqdb.com/vs/milvus/): Pick Milvus if your agent recalls by similarity at scale — billions of embeddings, ANN search with metadata filters and hybrid dense + sparse ranking. Pick nlqdb if your agent must aggregate what it stored: GROUP BY, JOIN, and HAVING over typed rows it provisions in plain English. Milvus ranks the nearest vectors; nlqdb counts, groups, and reports over the rows. - [nlqdb vs Supermemory](https://nlqdb.com/vs/supermemory/): Pick Supermemory if you want a best-in-class memory API — fact extraction, hybrid recall, and connectors that top the memory benchmarks. Pick nlqdb if your agent also needs to run analytical queries (counts, group-bys, reports) over the structured rows it remembers. - [nlqdb vs Honcho](https://nlqdb.com/vs/honcho/): Pick Honcho if you want a memory layer that models how each user reasons — communication style, decision patterns — for personalization. Pick nlqdb if your agent also needs to run analytical queries (counts, group-bys, reports) over the structured rows it remembers. - [nlqdb vs Mode](https://nlqdb.com/vs/mode/): Pick Mode if you're a data team that wants a SQL editor with connected Python/R notebooks and shareable reports over your existing warehouse. Pick nlqdb if you're building a product or agent that needs English-to-SQL over a database it provisions — embeddable, API-first, with every write diff-previewed. - [nlqdb vs Fabi.ai](https://nlqdb.com/vs/fabi/): Pick Fabi.ai if you're a data team that wants AI-assisted Python + SQL notebooks and scheduled dashboards over a warehouse you already run. Pick nlqdb if you're building a product or agent that needs English-to-SQL over a database it provisions — embeddable, API-first, every write diff-previewed. - [nlqdb vs Count](https://nlqdb.com/vs/count/): Pick Count if you're a data team that wants a collaborative AI canvas for SQL, Python and visuals over a warehouse you already run. Pick nlqdb if you're building a product or agent that needs English-to-SQL over a database it provisions — embeddable, API-first, every write diff-previewed. - [nlqdb vs MindsDB](https://nlqdb.com/vs/mindsdb/): Pick MindsDB if you need one endpoint to query across many existing data sources — and to train ML models in SQL — self-hosted and open source. Pick nlqdb if you want a Postgres provisioned from plain English, queried in English with the compiled SQL shown, no sources to connect first. - [nlqdb vs LangChain SQL agent](https://nlqdb.com/vs/langchain-sql-agent/): Pick the LangChain SQL agent if you want to build and own the agent loop — its prompts, tools, retries, and deployment — over a database you already run. Pick nlqdb if you want NL→SQL working today as a hosted pipeline you embed, with the SQL shown, writes diff-previewed, and a Postgres provisioned for you. - [nlqdb vs LlamaIndex](https://nlqdb.com/vs/llamaindex/): Pick LlamaIndex if you want to assemble your own text-to-SQL query engine — its schema retrieval, prompt, and guardrails — over a database you already run. Pick nlqdb if you want NL→SQL working today as a hosted pipeline you embed, with the SQL shown, writes diff-previewed, and a Postgres provisioned for you. - [nlqdb vs Dataherald](https://nlqdb.com/vs/dataherald/): Pick Dataherald if you have a data warehouse and want an open-source engine that answers it in English, tuned with business context and golden-SQL pairs you curate. Pick nlqdb if you want the database itself — a Postgres provisioned from English, the compiled SQL shown, and writes diff-previewed, with nothing to host. - [nlqdb vs PandasAI](https://nlqdb.com/vs/pandasai/): Pick PandasAI if you already have DataFrames, CSVs, or a warehouse and want to chat with them in Python — generating code, charts, and cleaned data. Pick nlqdb if you want the database itself: a Postgres provisioned from English, the compiled SQL shown and validated, and writes diff-previewed — no code to run and nothing to load first. ## Solve pages - [How do I give Claude or Cursor a SQL database it can create and query?](https://nlqdb.com/solve/database-claude-cursor-can-query/): If you want Claude Desktop, Cursor, or any MCP host to have a SQL database — not just a connection to one you configured yourself — point it at nlqdb's hosted MCP server. The `nlqdb_query` tool provisions Postgres from the agent's first English goal (no connection string, no schema) and answers in English with the SQL shown. - [How do I build an internal dashboard without per-seat pricing?](https://nlqdb.com/solve/cheap-internal-dashboard/): If you need an internal view over your data and per-seat tooling is out of budget, drop an `` tag in any HTML page and ask for the report in English — no SQL, no schema setup, no per-viewer fee. - [How do I give my AI agent persistent memory across sessions?](https://nlqdb.com/solve/give-ai-agent-persistent-memory/): If your agent needs to remember facts across sessions and later *aggregate* them, give it a real database via MCP — nlqdb's `nlqdb_query` tool provisions Postgres from the agent's first English goal and answers `GROUP BY` / top-N / per-period questions over what it stored. Retrieval gets you one fact; analytics gets you the report. - [How do I run reports over what my AI agent remembered?](https://nlqdb.com/solve/analytical-queries-over-agent-memory/): If your agent stores what it learns and you now need *reports* over that memory — counts, top-N, averages per group — point an MCP-aware agent at nlqdb and ask in English. It runs the `GROUP BY` in Postgres and returns rows plus the SQL. A vector store recalls one fact; a database answers 'top 10 this month.' - [How do I add a database to a side project without setting up Postgres?](https://nlqdb.com/solve/skip-postgres-setup-side-project/): If your side project needs a database but you don't want to provision Postgres, choose an engine, or wire migrations, drop one `` tag in any HTML page — nlqdb mints the database, infers the schema from your first English query, and exposes the same data via SDK / CLI / MCP. - [How do I run natural-language queries on a database without training a model on my schema?](https://nlqdb.com/solve/natural-language-sql-without-training-data/): If you want English → SQL on your data but don't want to maintain a training corpus or RAG layer, point `` at your goal — nlqdb prompts directly from the live schema fingerprint, caches the plan, and shows the compiled SQL so you can verify before trusting it. - [How do I add a leaderboard to a small product without writing SQL?](https://nlqdb.com/solve/ship-leaderboard-no-sql/): If your product needs a leaderboard, a top-N table, or a ranked list and you don't want to author SQL or wire a ranking ORM call, write the goal in English in one `` tag — the database, the schema, and the index decisions are all behind the element. - [How do I store and query my chatbot's conversation history?](https://nlqdb.com/solve/store-query-chatbot-conversation-history/): If your chatbot needs to keep its conversation history and answer questions like 'messages per day' or 'most active users this week', give it a real database. nlqdb provisions Postgres from your first English goal and runs the GROUP BY in SQL — a vector store recalls one message, a database counts them all. - [How do I track and query my AI app's token usage and cost per user?](https://nlqdb.com/solve/track-ai-token-usage-and-cost/): If your LLM app needs to track token usage and cost — per user, per model, per day — log each call as a row and ask in English. nlqdb provisions Postgres from your first goal and runs the GROUP BY in SQL, so 'spend per user this month' is a real query, not arithmetic over a JSON log. - [How do I log my AI agent's tool calls and query which tool fails most?](https://nlqdb.com/solve/analyze-agent-tool-call-logs/): If your agent calls tools and you need to know which tool fails most and how slow each one is — log every tool call as a row and ask in English. nlqdb provisions Postgres from your first goal and runs the GROUP BY in SQL, so 'error rate per tool' is a real query, not a grep over traces. - [How do I log my RAG retrievals and query which sources get used most?](https://nlqdb.com/solve/analyze-rag-retrieval-logs/): If your RAG agent retrieves chunks and you need to know which sources get used most — log each retrieval as a row and ask in English. nlqdb provisions Postgres from your first goal and runs the GROUP BY in SQL, so 'retrievals per source this week' is a real query, not a scan over a vector-store log. - [How do I track and query my LLM eval scores across prompt versions?](https://nlqdb.com/solve/track-llm-eval-scores-across-prompt-versions/): If you run LLM evals and need to know which prompt version regressed — log each scored case as a row and ask in English. nlqdb provisions Postgres from your first goal and runs the GROUP BY in SQL, so 'pass rate per prompt version this month' is a real query, not a spreadsheet pivot. - [How do I safely give an AI agent database access without it running dangerous SQL?](https://nlqdb.com/solve/safely-give-ai-agent-database-access/): If you want an AI agent to use a database without handing it a connection string and hoping it never emits a DROP, nlqdb keeps the agent on the data side of a trust boundary: writes are server-built parameterised inserts, read SQL passes a fail-closed three-stage validator, Postgres RLS isolates every row, and the compiled SQL is always shown. - [How do I give multiple AI agents shared, persistent memory?](https://nlqdb.com/solve/share-memory-across-multiple-ai-agents/): If you want a crew of agents to share one memory instead of each keeping its own, nlqdb gives them a single Postgres they all write to with `nlqdb_remember` and recall in English — every row tagged with the agent that wrote it, so you can roll the team's memory up per agent. - [How do I isolate AI agent memory per tenant so accounts can't read each other?](https://nlqdb.com/solve/isolate-ai-agent-memory-per-tenant/): If your agent stores memory for many customers and one tenant's rows must stay invisible to another, nlqdb enforces it in the database: every provisioned Postgres carries a row-level-security policy keyed on the tenant, set per request, and fails closed — a missing scope returns no rows, never someone else's. - [How do I add a natural-language query layer over my existing Postgres?](https://nlqdb.com/solve/query-existing-postgres-in-natural-language/): If you already run Postgres and want to ask it questions in English — without building or training a text-to-SQL stack — connect it to nlqdb with `nlq db connect` (or `POST /v1/db/connect`). nlqdb introspects your live schema, compiles English to SQL, runs it on your own database, and shows the SQL every time. Your data never leaves your Postgres. - [How do I store and query form submissions without a backend?](https://nlqdb.com/solve/store-form-submissions-without-backend/): If your landing page needs to capture form submissions — a waitlist, contact form, or survey — without running a backend, give nlqdb a database: write each submission with the SDK or a `POST /v1/run` insert, then ask 'signups per day' or 'replies by source' in plain English. - [How do I answer ad-hoc data questions without waiting on the data team?](https://nlqdb.com/solve/answer-data-questions-without-the-data-team/): If a simple number means filing a data ticket and waiting days, ask the question in English instead — drop an `` tag in any page or open the chat, and nlqdb compiles the SQL, runs it, and returns the rows plus the query to audit. No ticket, no analyst in the loop. - [How do I add an ask-your-data feature to my app without building text-to-SQL?](https://nlqdb.com/solve/add-ask-your-data-feature-without-building-text-to-sql/): If you want to ship an 'ask your data' feature in your app but don't want to build and maintain a text-to-SQL pipeline, embed nlqdb: drop the `` element (or call `POST /v1/ask` from your backend), and it compiles English to SQL, runs it, and returns rows plus the SQL — buy the pipeline, don't build it. - [How do I store webhook events in a database I can query in plain English?](https://nlqdb.com/solve/store-and-query-webhook-events/): If you receive webhooks from Stripe, GitHub, or Twilio and want to ask 'how many events per type this week' without standing up a database first, write each verified payload to an nlqdb-provisioned Postgres and ask the report in English — the compiled SQL is shown underneath. - [How do I track product usage events and query them without a data warehouse?](https://nlqdb.com/solve/track-product-usage-without-a-data-warehouse/): If you want to track product usage — signups, feature clicks, retention — and ask 'active users this week' without standing up Snowflake or paying Mixpanel per event, give nlqdb a database: emit each event with the SDK or a `POST /v1/run` insert, then ask the rollup in plain English with the SQL shown. - [How do I log my background jobs and query which one fails most?](https://nlqdb.com/solve/track-background-job-run-history/): If your cron and background jobs fail silently and you need to know which one fails most — log every run as a row and ask in English. nlqdb provisions Postgres from your first goal and runs the GROUP BY in SQL, so 'failure rate per job this week' is a real query, not a grep over scheduler logs. - [How do I find duplicate rows in my data without writing SQL?](https://nlqdb.com/solve/find-duplicate-rows-in-my-data/): If you need to find duplicate rows — the same email twice, an import that ran twice, a customer entered three times — ask in plain English instead of hand-writing GROUP BY ... HAVING. nlqdb compiles the dedup query, runs it in Postgres, and shows the SQL, so you see exactly which rows repeat and how many times. - [How do I get the top N rows per category without window-function SQL?](https://nlqdb.com/solve/find-top-n-rows-per-group/): If you need the top N rows in each group — the 3 best-selling products per category, or the latest order per customer — ask in plain English instead of hand-writing a window function. nlqdb compiles the ranked query, runs it in Postgres, and shows the SQL so you trust the partition and tiebreak. - [How do I pivot rows into columns in SQL without writing a crosstab query?](https://nlqdb.com/solve/pivot-rows-into-columns/): If you need a pivot table — rows turned into columns, like revenue per product with one column per month — ask in plain English instead of hand-writing a crosstab. nlqdb compiles the conditional aggregation, runs it in Postgres, and shows the SQL so you can verify the buckets. - [How do I do a COUNTIF or SUMIF (conditional count or sum) in SQL?](https://nlqdb.com/solve/countif-sumif-conditional-aggregate-in-sql/): If you need a COUNTIF or SUMIF — count or total only the rows that meet a condition, like paid orders or signups from one plan — ask in plain English instead of hand-writing the aggregate. nlqdb compiles `COUNT(*) FILTER (WHERE ...)`, runs it in Postgres, and shows the SQL so you can verify the condition. - [How do I calculate a running total or cumulative sum in SQL?](https://nlqdb.com/solve/running-total-cumulative-sum-in-sql/): If you need a running total — a cumulative sum that grows row by row, like revenue-to-date by day — ask in plain English instead of hand-writing a window function. nlqdb compiles the `SUM(...) OVER (ORDER BY ...)`, runs it in Postgres, and shows the SQL so you can verify the ordering and frame. - [How do I calculate month-over-month growth or period-over-period change in SQL?](https://nlqdb.com/solve/month-over-month-growth-in-sql/): If you need month-over-month growth — this period's value versus the previous one, as a percentage — ask in plain English instead of hand-writing a LAG window function. nlqdb compiles the `LAG(...) OVER (ORDER BY ...)` and the growth formula, runs it in Postgres, and shows the SQL so you can verify the order and the divide-by-zero guard. - [How do I calculate a median or percentile in SQL?](https://nlqdb.com/solve/calculate-median-or-percentile-in-sql/): If you need a median or a percentile — the middle value, or the p90 of response times — ask in plain English instead of remembering Postgres has no `MEDIAN` function. nlqdb compiles the ordered-set aggregate `PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY value)`, runs it in Postgres, and shows the SQL so you can check the order. - [How do I calculate each row's percentage of the total in SQL?](https://nlqdb.com/solve/calculate-percentage-of-total-in-sql/): If you want each row as a share of the whole — a product's revenue as a percent of all revenue — ask in plain English instead of self-joining to a total. nlqdb compiles the window aggregate `100.0 * revenue / SUM(revenue) OVER ()`, runs it in Postgres, and shows the SQL so you can check the denominator. - [How do I find rows in one table with no match in another (anti-join) in SQL?](https://nlqdb.com/solve/find-rows-with-no-match-in-another-table/): If you need the rows in one table with no match in another — customers who never placed an order — ask in plain English instead of hand-writing an anti-join. nlqdb compiles the `LEFT JOIN ... WHERE b.id IS NULL` (or `NOT EXISTS`), runs it in Postgres, and shows the SQL so you can dodge the `NOT IN` NULL trap. - [How do I count rows per day in SQL, including days with zero rows?](https://nlqdb.com/solve/count-rows-per-day-including-missing-dates/): If your per-day counts skip the days with no rows — a signup chart with holes where the zeros should be — ask in plain English. nlqdb compiles the `generate_series` calendar spine, LEFT JOINs your rows onto it, runs it in Postgres, and shows the SQL, so quiet days come back as 0 instead of vanishing. - [How do I group numbers into ranges (buckets) in SQL?](https://nlqdb.com/solve/group-numbers-into-ranges-in-sql/): If you want a count per range — orders under $50, $50–$200, over $200 — instead of one row per exact value, ask in plain English. nlqdb compiles the bucket expression, GROUP BYs the bucket, orders the ranges by their lower bound, and shows the SQL, so 5–10 sorts before 10–20 instead of after. - [How do I count a streak of consecutive days in SQL?](https://nlqdb.com/solve/count-consecutive-days-streak-in-sql/): If you want each user's longest run of consecutive active days — not just their total active days — ask in plain English. nlqdb compiles the gaps-and-islands query (the date-minus-row-number trick that turns each unbroken run into one group), counts the days per run, and shows the SQL. - [How do I combine multiple rows into one comma-separated value in SQL?](https://nlqdb.com/solve/combine-multiple-rows-into-one-value-in-sql/): If you want one row per customer with their products rolled into a single comma-separated list — not one row per order line — ask in plain English. nlqdb compiles the string aggregate (`STRING_AGG` in Postgres, `GROUP_CONCAT` in MySQL), orders the items inside the aggregate so the list is stable, and shows the SQL. - [How do I calculate the time between two dates in SQL?](https://nlqdb.com/solve/calculate-time-between-two-dates-in-sql/): If you need the time between two dates — days from signup to first order, hours to resolve a ticket — ask in plain English. nlqdb compiles the date arithmetic (`end - start` for an interval, `EXTRACT(EPOCH FROM (end - start))/86400` for whole days), runs it in Postgres, and shows the SQL so the unit is the one you meant. - [Should I build my own agent memory on Postgres or buy it?](https://nlqdb.com/solve/build-vs-buy-agent-memory/): If you already run Postgres and are deciding whether to hand-roll agent memory, a `memories` table is easy to start and expensive to get right at scale. nlqdb is the buy answer: one MCP command gives your agent a real database it writes rows to and queries in English, with tenant isolation enforced in the engine. - [What's the best way to store what my AI agent remembers?](https://nlqdb.com/solve/best-way-to-store-agent-memory/): If you're choosing how to store what your AI agent remembers, the storage shape decides what you can ask later — a vector store recalls one fact but can't count them. Store memory as typed rows in a real database: one command (`claude mcp add --transport http nlqdb https://mcp.nlqdb.com/mcp`) gives your agent one it writes to and queries in English. - [How do I expire old agent memory automatically instead of writing a cron?](https://nlqdb.com/solve/expire-old-agent-memory/): If stale agent memory is piling up, give it an `expires_at` timestamp on typed rows in a real database — then expiry is a one-line `WHERE expires_at < now()` predicate you query in English, not a bespoke cron. One command (`claude mcp add --transport http nlqdb https://mcp.nlqdb.com/mcp`) gives your agent that database. - [Is there an MCP server that gives my AI agent memory?](https://nlqdb.com/solve/agent-memory-mcp-server/): If you want an MCP server that gives your AI agent memory, point your coding agent at nlqdb's hosted one with one command — `claude mcp add --transport http nlqdb https://mcp.nlqdb.com/mcp`. Unlike a blob-store memory server, it's a real Postgres your agent writes to and queries in English, so 'how many' and 'top N' are SQL, not guesses. ## Blog - [Your link checker can't see your JavaScript.](https://nlqdb.com/blog/link-checker-cant-see-your-javascript/): A dead-link sweep over built HTML read '0 dead' while real clicks 307-redirected. The navigations were client-side location.assign() calls a checker never parses out of dist/. - [Row-level security has a flavour. The default one is a silent breach.](https://nlqdb.com/blog/restrictive-rls-agent-memory-scoping/): Postgres RLS policies default to PERMISSIVE, so they OR together — a per-agent policy beside a tenant policy widens access instead of narrowing it. The one keyword that fixes it, and four traps. - [Your docs promised a tool your server never shipped.](https://nlqdb.com/blog/guard-advertised-capabilities-against-code/): An agent product advertised a tool it never built — a new user's first call hit 'tool not found.' The fix isn't a better list; it's deriving the advertised set from the shipped artifact. - [The redesign shipped. The smoke test kept walking the old UI.](https://nlqdb.com/blog/smoke-test-walks-the-old-ui/): Acceptance walkers that pin literal UI copy catch regressions — until a redesign turns them into a 0/9 that mixes real breakage with pure test-drift. The triage cost is the trap, not the literals. - [Your recovery code runs once. Your failure doesn't.](https://nlqdb.com/blog/one-shot-recovery-permanent-outage/): A best-effort repair that runs once turns one silent skip into a permanent outage. Fix the root, keep it idempotent, and re-trigger from the steady-state symptom — the event never recurs. - [A green checkmark has a half-life.](https://nlqdb.com/blog/green-checkmark-has-a-half-life/): When an expensive test suite can't run on every push, passing stops being a state and becomes an event. Score each suite pass × freshness with a linear decay so the number rots until it re-runs. - [We rebuilt staging's database every run. The registry remembered everything.](https://nlqdb.com/blog/ephemeral-staging-persistent-registry/): An environment is only as ephemeral as the most persistent store that references it. Enumerate every store that outlives the rebuild and reset it at spin-up — teardown can't be the invariant. - [Ownership transfer was a one-row UPDATE. Then we added least-privilege.](https://nlqdb.com/blog/ownership-transfer-outlives-least-privilege/): Hardening queries to per-tenant roles and RLS quietly broke our ownership transfer: it retargeted one authorization store out of four. Transfer must move them all — idempotently, in one batch. - [Your most active user is your test suite.](https://nlqdb.com/blog/most-active-user-is-your-test-suite/): Pre-launch, synthetic traffic IS your traffic: e2e walkers register users and run real queries, so every dashboard quietly measures your robots. Three places it bit us, three fixes. - [Your five fallback models are one point of failure.](https://nlqdb.com/blog/five-fallback-models-one-provider/): A model-diverse fallback list on one gateway saturates as a unit — five models, one rack. Make the fallback unit a lane (base URL, key, candidates), not a longer list on the same pool. - [An "open question" that's already decided is worse than one that's still open.](https://nlqdb.com/blog/decided-questions-rot-in-your-decision-log/): Decision logs rot at the seam between open and answered: a decided-but-unmarked bullet makes readers re-litigate closed calls. Make resolved a greppable state and count unmarked bullets as debt. - [Your metric is only as honest as the layer you emit it from.](https://nlqdb.com/blog/emit-metrics-where-the-distinction-is-certain/): A destructive-op retry rate emitted at the HTTP route can go negative — the route can't tell reads from writes. Emit metrics at the lowest layer where the distinction is certain. - [You need to rotate an encryption key. You don't need a key-version column.](https://nlqdb.com/blog/rotate-encryption-key-without-a-version-column/): Rotating a key-encryption key feels like it needs a key_version column. It doesn't — the ciphertext already describes itself, so put the version in the blob prefix and rotate with zero migration. - [You added a second SQL engine. Your text-to-SQL model is still being told it's the first one.](https://nlqdb.com/blog/text-to-sql-planner-told-wrong-dialect/): A text-to-SQL planner emits whatever dialect you name it. Add a second engine and the bug is one hardcoded dialect literal the type never forced you to fix — so ClickHouse gets Postgres SQL. - [You added ClickHouse. Your Postgres SQL validator now rejects valid queries — quietly.](https://nlqdb.com/blog/postgres-validator-rejects-valid-clickhouse-sql/): A Postgres-pinned AST validator false-rejects valid ClickHouse grammar as parse_failed — a silent veto of correct SQL. The fix: split the security allowlist from the dialect parser. - [We published 20 blog posts and never shipped a feed. Nothing could subscribe.](https://nlqdb.com/blog/blog-without-a-feed-is-a-dead-end/): A blog with no RSS feed is a one-way street: feed readers and dev.to/Medium 'import from RSS' both need a feed URL. Without one, every venue re-post is a manual copy-paste that quietly stops. - [We read the agent-memory benchmarks. Almost none measure analysis.](https://nlqdb.com/blog/agent-memory-benchmarks-measure-recall-not-analysis/): Agent-memory benchmarks score end-to-end recall of facts on mostly self-reported numbers. Almost nobody measures analysis over memory — the gap we found reading the papers. - [We shipped 18 SEO pages and got 1 referral. The links only pointed one way.](https://nlqdb.com/blog/one-way-internal-links-leak-yield/): The page count climbed; referrals stayed flat at ~1/week. Our internal link graph was a tree, not a mesh. The fix was one reciprocal link, derived from a field we already had. - [Your database scales to zero. Your retry loop doesn't know that.](https://nlqdb.com/blog/serverless-db-cold-start-retry/): A scale-to-zero Postgres branch fails the first query while its compute wakes. Instant retries replay the cold connection. The fix: back off the DB stage, not the LLM stages. - [The timeout that looked like a hallucination](https://nlqdb.com/blog/llm-timeout-looks-like-hallucination/): Our NL→SQL benchmark scored a frontier model as junk on 5 hard questions. It never hallucinated — a 5s prod timeout aborted it mid-answer and the handler mislabeled the abort as a parse failure. - [Your "best model" toggle quietly serves the cheap model. Ship a 409 instead.](https://nlqdb.com/blog/model-preset-fail-loud/): When the premium lane isn't available, the tempting branch is to silently serve the default chain. A placebo knob is worse than no knob. The honest contract: pin, upgrade, or fail loud. - [Your LLM health probe passed. Your agent still starved.](https://nlqdb.com/blog/llm-preflight-probe-health/): Six straight LLM-agent CI runs failed while our pre-flight probe stayed green. Lessons on gating CI on an LLM provider: probe the real shape, read the body not the status, never trust one model. - [Your text-to-SQL model isn't as wrong as your benchmark says. The gold SQL is.](https://nlqdb.com/blog/bird-gold-noise-distinct/): We bucketed 238 BIRD-dev losses with a structural differ: 46 differ from gold only by a DISTINCT the model rightly added. Audit gold quality before writing prompt directives, or you overfit to noise. - [Your LLM fused the two columns you asked for — and the eval marked it wrong](https://nlqdb.com/blog/llm-concatenates-columns-text-to-sql/): Gold SQL returns first_name, last_name as two columns; the model returns one concatenated full name. Positional-tuple EX scoring can never match them, so a semantically right answer scores as a miss. - [Your text-to-SQL eval is lying: the gateway returns HTTP 200 with the error in the body](https://nlqdb.com/blog/http-200-error-in-body/): A gateway commits 200 OK before the upstream model fails, so the error rides in the 200 body. A res.ok-only client counts it as a wrong answer, not an outage. res.ok is necessary, not sufficient. - [Top N per group is the query `LIMIT` can't write](https://nlqdb.com/blog/top-n-rows-per-group/): "Top 3 per category" reads like ORDER BY … LIMIT 3, but LIMIT caps the whole result set, not each group. The fix is ROW_NUMBER() OVER (PARTITION BY …) — and the hidden decision is how ties break. - [Your BI tool got acquired. Your data layer shouldn't have to care.](https://nlqdb.com/blog/your-bi-tool-got-acquired-data-layer/): BI notebooks get rolled up — Mode → ThoughtSpot, Looker → Google, Periscope → Sisense. Fine when it's a destination humans log into; a liability when your product's runtime calls its API. - [The duplicate-rows query you re-Google every six weeks](https://nlqdb.com/blog/find-duplicate-rows-you-re-google-every-time/): Find duplicates hasn't changed in thirty years: GROUP BY the suspect columns, HAVING COUNT(*) > 1. Wanting the whole row, not just the key, quietly changes it to a window function. - [The text-to-SQL demo takes an afternoon. The other 90% is why you should buy it.](https://nlqdb.com/blog/text-to-sql-build-vs-buy/): Prompt + model + run the SQL is 10% of an 'ask your data' feature. The fail-closed validator, plan cache, and eval harness are the rest — yours forever. The real question: do you want that stack? - [Your sitemap is advertising redirects — and your canonical tag points at one](https://nlqdb.com/blog/sitemap-advertising-redirects/): A static host that serves route/index.html 307-redirects the bare path. Our sitemap advertised 27 redirecting URLs and every canonical tag pointed at one. The fix is one path-normalize helper. - [Your offline LLM eval isn't measuring your model — it's measuring your rate limits](https://nlqdb.com/blog/offline-llm-eval-rate-limits/): A free-model NL-to-SQL bench scored 17/20, then 6/20 ninety seconds later. The model didn't change — the providers got tired. How to keep availability out of your accuracy number. - [AI made the internal-tool builder faster. It didn't ask whether you needed the tool.](https://nlqdb.com/blog/ai-internal-tool-builder-faster/): Low-code AI scaffolds the admin tool in a prompt. But the output is still a destination a human operates — and often the answer belongs inline in your product, or the asker is an agent. - [Your text-to-SQL accuracy is measured on schemas your users will never build](https://nlqdb.com/blog/text-to-sql-accuracy-schemas-your-users-never-build/): BIRD and Spider score NL-to-SQL over messy academic schemas. The same free-model chain that scores 0.52 on BIRD scores 0.96 on the schema shapes our users actually build — so we report both. - [Every data tool shipped an MCP server this year. Your agent still can't build on most of them.](https://nlqdb.com/blog/mcp-server-what-does-the-agent-own/): Two shapes of MCP server look identical in a feature matrix: a window into a human's app, or infrastructure the agent owns. The tell is what the agent owns after the call returns. - [Your agent's memory is a vector store. Ask it "how many" and watch it fall over.](https://nlqdb.com/blog/agent-memory-vector-store-aggregation-gap/): A vector store returns the top-k most similar memories — there is no GROUP BY, COUNT, or JOIN. Recall is similarity; reporting is aggregation. Agent memory needs both machines, not one. - [You don't need a backend to store form submissions. You need a place to ask "how many."](https://nlqdb.com/blog/store-form-submissions-without-a-backend/): Storing a signup is a trivial insert — no server needed. The part that wants a database is the reporting: "signups per day," "which referrer converted" — aggregations that want a query planner. - [NOT IN returned zero rows. It wasn't your data — it was one NULL.](https://nlqdb.com/blog/not-in-subquery-null-trap/): Why WHERE id NOT IN (SELECT …) silently returns nothing when the subquery contains a NULL, and the two anti-join shapes (NOT EXISTS, LEFT JOIN … IS NULL) that never lie to you. - [Zep gives my agent perfect recall. It still can't answer "average per group" about its own memory.](https://nlqdb.com/blog/zep-recall-vs-analytical-agent-memory/): A temporal knowledge graph is genuinely good at recall — and has no query planner. When the question about agent memory is a GROUP BY, retrieval and aggregation are different machines. - [The NULL timestamp that broke a TTL sweep and a funnel metric at the same time](https://nlqdb.com/blog/null-timestamp-ttl-sweep-funnel-metric/): A backfill is not a default: one nullable timestamp column made an age-based eviction a silent no-op and pinned a funnel metric at zero — the same NULL, two different failure modes. ## Optional - [Sign in](https://nlqdb.com/auth/sign-in/): Magic-link / GitHub / Google. - [Anonymous start](https://nlqdb.com/app/new/): Try a database without an account (72h). ## Status Pre-beta, open — start anonymously. Phase 0 shipped; Phase 1 onboarding in progress. Free chain forever (BYO-LLM at 0% markup). Source is public under FSL-1.1-ALv2 (source-available, self-hostable for any non-competing use), auto-converting to Apache-2.0 two years after each release; no turnkey GA self-host container yet. ## Contact Email: hello@nlqdb.com