Skip to main content

nl2sql-engine

Ask a database questions in English. The model writes a typed query plan, never SQL text; the plan is checked against the real schema and the caller's role before any SQL is generated.

This distribution is the engine: the LangGraph pipeline, the nl2sql CLI with its browser playground, and the database adapters (PostgreSQL, MySQL, SQL Server, SQLite, DuckDB). The REST server is the separate nl2sql-api package. Full README and docs: https://github.com/nadeem4/nl2sql.

Try it in your browser

https://nl2sql.codewithnk.com — the playground on three sample databases, nothing to install.

Ask a database in plain English; the model plans, the code writes the SQL

The server holds no API key: you paste your own into the page, one per provider, and it stays in that browser tab, is used in memory for the question that needs it, and is never stored, logged or traced. Settings also puts each of the six model-using steps on a provider and model of its own.

The nl2sql playground on its Ask page: the search index over three databases and a switcher for whichever of their schemas to read on the left, the question box and the guided questions on the right

How it works

  • The question is checked for answerability and routed to one of the registered databases, then split into sub-queries, and each gets the part of the schema it needs.
  • The model returns a typed plan (a Pydantic PlanModel), never SQL. It may only name a function from an allow-list, and date work is written portably and rendered by each adapter in its own dialect.
  • The logical validator checks every table and column against the schema, joins against the declared foreign keys, and every table against the caller's role (RBAC); it also builds the query tree the generator would build, so an unjoinable plan is caught while the planner can still be asked to fix it. A refused plan never becomes SQL.
  • Only a plan that passes is rendered to SQL, deterministically, with sqlglot, then executed and summarised.

The whole pipeline is 14 steps, six of them decided by a model; the playground's Pipeline page lists them. The first, matching a verified query from curated.yaml, runs only when curated answers are configured.

Quickstart

Requires Python 3.12 or newer.

pip install "nl2sql-engine[demo]"
nl2sql demo

That writes a demo project into ./nl2sql-demo, copies in three SQLite databases -- Chinook, support and webanalytics -- indexes their schemas locally (no key; the first run downloads a ~79 MB ONNX embedding model) and opens the playground on http://127.0.0.1:8765/.

Answering a question needs a model: --api-key, or OPENAI_API_KEY, OPENROUTER_API_KEY or ANTHROPIC_API_KEY in the environment (Claude needs pip install "nl2sql-engine[demo,anthropic]"), a key pasted into the playground's Settings page, or a reachable Ollama. Without one the demo runs in replay mode, which has no recorded answers out of the box, so it can show the schema and the index but answers nothing. nl2sql demo --record (with an OpenAI, OpenRouter or Anthropic key) records the guided questions for later key-free runs.

nl2sql demo --hosted runs the public variant above yourself: the server holds no API key, each visitor pastes their own into the page for that question only (without one, the guided questions replay recorded runs), the sample databases are opened read-only, questions are rate limited per visitor and capped per session, and Settings, Rebuild, ratings and --record are refused. See Hosted demo in the full docs.

The playground shows each answer's plan, validation checks, SQL, rows and cost, a per-node Debug view, a Pipeline page listing every step of a run with the model each used, a Retrieval inspector over the live index, and a right/wrong rating per answer that nl2sql feedback stats reports on.

CLI

Every command reads one config: --config PATH, else NL2SQL_CONFIG, else ./nl2sql.yaml, and loads the .env next to it. From the demo folder (cd nl2sql-demo):

nl2sql run "How many customers do we have, by country?"
nl2sql run --role viewer "Who are the top 5 customers by total spend?"   # refused
nl2sql run --no-exec "Which artist has the most albums?"                 # plan only
nl2sql index                       # re-index the schema
nl2sql config check --connect      # the whole config, by file; exit 1 on a problem
nl2sql doctor                      # drivers, provider keys, and the engine's check
nl2sql benchmark --tier 1          # gold plans, no key
nl2sql benchmark --tier 2 --model gpt-5.4 --max-cost 5
nl2sql benchmark retrieval         # retrieval recall, no key
nl2sql feedback stats              # ratings and guardrail rates

Your own database: nl2sql init writes nl2sql.yaml and one file per section (edit datasources/example.yaml), then nl2sql index.

Every command: CLI reference.

Python

from nl2sql import NL2SQL, UserContext

engine = NL2SQL.demo()               # the bundled databases; reads OPENAI_API_KEY (or another provider's key)
engine.index.build()                 # once: builds the index under .nl2sql-demo/
# Your own config instead:  engine = NL2SQL.from_config("nl2sql.yaml")
result = engine.run_query(
    "How many customers are there?",
    user_context=UserContext(roles=["admin"]),
)
for sq in result.sub_queries:
    print(sq.sql, [c.name for c in sq.validation if c.passed])
print(result.final_answer["summary"] if result.final_answer else result.errors)

Pass a user_context with a role: with none, run_query currently raises a validation error, and an unknown role is refused.

Install extras

pip install "nl2sql-engine[postgres]"        # or [mysql], [mssql], [duckdb]
pip install "nl2sql-engine[all]"             # every database driver; not [demo] or [anthropic]

SQLite needs no extra.

Security

  • The LLM provider receives the question, the schema the planner needs, sample column values of tables the role may read, and the result rows (for the written answer).
  • RBAC is a per-role table allowlist; a plan touching a forbidden table is refused. No column masking or row-level security.
  • Read-only is not checked by the executor: only SELECTs are generated, and a SQLite datasource can be opened read-only with options.read_only: true (the three sample databases are), but no other dialect is. Give the engine a read-only database user.
  • No authentication: the caller supplies the role.
  • No cross-database questions and no conversation yet: each sub-query is planned against one datasource, and each question is answered on its own.

Status

0.1.x. nl2sql-sdk, nl2sql-engine and nl2sql-api share one version and are released together. Known limitations, benchmark results and the roadmap: https://github.com/nadeem4/nl2sql#project-status-limitations-and-roadmap. MIT licensed.

Metadata

Release files for nl2sql-engine 0.5.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for nl2sql-engine 0.5.0
File Size Uploaded
nl2sql_engine-0.5.0.tar.gz 6.2 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for nl2sql-engine 0.5.0
File Interpreter ABI Platform
nl2sql_engine-0.5.0-py3-none-any.whl Python 3 none any Details

Total release size: 12.5 MB

Release files / nl2sql_engine-0.5.0.tar.gz

Download URL nl2sql_engine-0.5.0.tar.gz
Size 6.2 MB
Tags Source
SHA-256 checksum
How to use checksums
07ad2e0cb6ca5cf95e54927dbdd2e4af17f1fc12385686bfdee98372e0bb2322
BLAKE2b-256 checksum
How to use checksums
c5a997b67b00cb85c850b843d205f6fd45e11da12c3a5857aa993e756e3d8579
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / nl2sql_engine-0.5.0-py3-none-any.whl

Download URL nl2sql_engine-0.5.0-py3-none-any.whl
Size 6.3 MB
Tags Python 3
SHA-256 checksum
How to use checksums
0e91ccb4650fa8ecc5aacafd7b12f1f5b95a856a3f07d79deefcc932e87c0b35
BLAKE2b-256 checksum
How to use checksums
0a3edf58fcb33989ddca7e2e7cf0947ea88e6d85992cd5f6604de07cc0992a29
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Release history Release notifications | RSS feed

0.7.0

2 release files

0.6.0

2 release files

This release

0.5.0 This release

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.4

2 release files

0.2.3

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page