Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

nlp2sql logo

PyPI Downloads License: MIT Python 3.9+ Code style: black

nlp2sql

DSL-first natural language to SQL for PostgreSQL and Redshift

nlp2sql turns a natural language question into SQL through a reusable Python DSL:

  • await connect(...)
  • await nlp.ask(...)
  • optional few-shot examples
  • optional semantic context
  • optional validation and repair

The library is designed for both simple schemas and large warehouses, but all public examples in this repository use the local e-commerce domain shipped with the project itself.

Features

  • DSL-first API: connect() returns an NLP2SQL client with ask(), validate(), explain(), and suggest()
  • Business-aware generation: optional SemanticContext adds canonical tables, metrics, dimensions, rules, and mappings
  • Execution modes: generate only, generate plus validate, and generate plus validate plus repair
  • Few-shot examples: pass example lists directly or use an example repository implementation
  • Large schema support: FAISS plus TF-IDF hybrid retrieval, schema filters, and disk-backed caches
  • Multiple providers: OpenAI, Anthropic, and Gemini
  • Database support: PostgreSQL and Amazon Redshift
  • Async by default: built for services, APIs, notebooks, and workers

Documentation

Document Description
Architecture Runtime flow, services, ports, and diagrams
API Reference Python API, CLI, hooks, and metadata reference
Configuration Environment variables, examples, semantic context, cache behavior
Enterprise Guide Governed usage, scale, and deployment patterns
Redshift Support Redshift-specific notes using public examples
Examples Safe public examples based on the local e-commerce domain
Contributing Contribution guidelines

Installation

# With UV (recommended)
uv add nlp2sql

# With pip
pip install nlp2sql

# With specific providers
pip install nlp2sql[anthropic,gemini]
pip install nlp2sql[all-providers]

# With embeddings
pip install nlp2sql[embeddings-local]
pip install nlp2sql[embeddings-openai]

Quick Start

1. Set a Provider Key

export OPENAI_API_KEY="your-openai-key"
# or ANTHROPIC_API_KEY / GOOGLE_API_KEY

2. Use the DSL

import asyncio

import nlp2sql
from nlp2sql import ProviderConfig


async def main():
    nlp = await nlp2sql.connect(
        "postgresql://testuser:testpass@localhost:5432/testdb",
        provider=ProviderConfig(provider="openai", api_key="sk-..."),
    )

    result = await nlp.ask("Show active users by region")
    print(result.sql)
    print(result.confidence)
    print(result.metadata["sql_intent_plan"])


asyncio.run(main())

connect() loads the schema, initializes retrieval indexes, and returns a reusable NLP2SQL client. ask() returns a typed QueryResult.

3. Add Few-Shot Examples

Pass examples directly to connect(). The library handles indexing for you.

nlp = await nlp2sql.connect(
    "postgresql://testuser:testpass@localhost:5432/testdb",
    provider=ProviderConfig(provider="openai", api_key="sk-..."),
    examples=[
        {
            "question": "Show revenue by source category for the flagship store",
            "sql": (
                "SELECT d.metric_date, mc.source_category, SUM(d.revenue) AS revenue "
                "FROM daily_channel_metrics d "
                "JOIN stores s ON d.store_id = s.id "
                "JOIN marketing_channels mc ON d.channel_id = mc.id "
                "WHERE s.code = 'na_flagship' "
                "GROUP BY d.metric_date, mc.source_category"
            ),
            "database_type": "postgres",
        }
    ],
)

4. Add In-Memory Semantic Context

Use semantic context when the same question could map to multiple plausible tables or dimensions.

from nlp2sql import (
    DimensionDefinition,
    DomainRule,
    MetricDefinition,
    SemanticContext,
    SemanticEntityMapping,
)

semantic_context = SemanticContext(
    domain="ecommerce_channel_performance",
    canonical_tables=["daily_channel_metrics"],
    required_filters=["s.code = 'na_flagship'", "s.region = 'North America'"],
    entity_mappings=[
        SemanticEntityMapping(
            source_term="North America flagship store",
            target="store_scope",
            resolved_value="na_flagship / North America",
            filter_expression="s.code = 'na_flagship' AND s.region = 'North America'",
        )
    ],
    metric_definitions=[
        MetricDefinition(name="revenue", description="Revenue by day and source category."),
        MetricDefinition(name="orders_count", description="Orders by day and source category."),
    ],
    dimension_definitions=[
        DimensionDefinition(name="metric_date", description="Daily grain."),
        DimensionDefinition(name="source_category", description="Channel grouping."),
    ],
    rules=[
        DomainRule(
            name="preserve_source_breakdown",
            description="Keep source_category when the question asks for a source breakdown.",
            required_dimensions=["source_category"],
            preferred_tables=["daily_channel_metrics"],
        )
    ],
)

result = await nlp.ask(
    "Show daily revenue and order count by source category for the North America flagship store",
    semantic_context=semantic_context,
)

5. Validate and Repair

ask() supports execution-aware modes directly.

result = await nlp.ask(
    "Show revenue by source category for the flagship store",
    validate=True,
    repair=True,
)
  • generate_only: generate SQL only
  • generate_and_validate: execute readonly validation when execution is wired
  • generate_validate_repair: retry on semantic or execution failures when repair hooks are available

6. CLI Parity

The CLI exposes the same concepts:

nlp2sql query \
  --database-url postgresql://testuser:testpass@localhost:5432/testdb \
  --question "Show daily revenue by source category for the North America flagship store" \
  --examples-file examples.json \
  --semantic-context-file semantic-context.json \
  --validate \
  --repair \
  --show-semantic-context \
  --show-sql-intent-plan \
  --show-selected-examples

How It Works

flowchart TD
    userCode[UserCodeOrCLI] --> dsl[connectAndAskDSL]
    dsl --> analysis[QueryAnalysisService]
    analysis --> semantic[SemanticResolutionService]
    semantic --> retrieval[SchemaRetrievalAndExampleSelection]
    retrieval --> intent[SqlIntentPlanningService]
    intent --> prompt[PromptAssemblyAndAdapters]
    prompt --> llm[LLMGeneration]
    llm --> semval[SemanticValidation]
    semval --> exec[OptionalExecutionAndRepair]
    exec --> result[QueryResultMetadata]

At runtime the library:

  1. analyzes the question
  2. optionally resolves and merges semantic context
  3. retrieves relevant schema and examples
  4. builds a structured SQL intent plan
  5. assembles the prompt
  6. generates SQL
  7. optionally validates, executes, and repairs
  8. returns a QueryResult with debug metadata

See Architecture for the full breakdown.

Public Example Domain

This repository ships a local e-commerce integration domain used in tests and docs. It includes:

  • stores
  • marketing_channels
  • users
  • products
  • orders
  • order_items
  • daily_channel_metrics

The public examples intentionally stay inside that domain to avoid leaking any private warehouse schema.

To start it locally:

cd docker
docker compose up -d postgres

The default URL is:

postgresql://testuser:testpass@localhost:5432/testdb

Provider Comparison

Provider Default Model Context Size Max Output Best For
OpenAI gpt-5.6-luna 1.05M (922K input) 128K Fast, low-cost general purpose usage
Anthropic claude-sonnet-5 1M 128K Larger schemas and long prompts
Gemini gemini-3.6-flash 1M 64K High-volume and very large contexts

Defaults are pinned snapshot IDs, not floating aliases. Override any of them through ProviderConfig(model=...); for example gpt-5.6-terra is the higher-quality OpenAI option.

Lower-Level API

connect() is the recommended path. Lower-level entry points still exist for advanced wiring:

from nlp2sql import DatabaseType, ProviderConfig, create_and_initialize_service

service = await create_and_initialize_service(
    database_url="postgresql://testuser:testpass@localhost:5432/testdb",
    provider_config=ProviderConfig(provider="openai", api_key="sk-..."),
    database_type=DatabaseType.POSTGRES,
)

result = await service.generate_sql(
    "Count active users by region",
    database_type=DatabaseType.POSTGRES,
)
print(result["sql"])

Development

git clone https://github.com/luiscarbonel1991/nlp2sql.git
cd nlp2sql
uv sync

# Start the local public e-commerce database
cd docker && docker compose up -d postgres

# Integration tests without llm
cd ..
uv run pytest -m "integration and not llm"

# Optional llm integration tests
uv run pytest -m "integration and llm"

MCP Server

nlp2sql includes a Model Context Protocol server for assistant integration.

{
  "mcpServers": {
    "nlp2sql": {
      "command": "python",
      "args": ["/path/to/nlp2sql/mcp_server/server.py"],
      "env": {
        "OPENAI_API_KEY": "${OPENAI_API_KEY}",
        "NLP2SQL_DEFAULT_DB_URL": "postgresql://testuser:testpass@localhost:5432/testdb"
      }
    }
  }
}

See mcp_server/README.md for details.

Contributing

See CONTRIBUTING.md.

License

MIT License. See LICENSE.

Release files for nlp2sql 0.2.0rc15

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

Source distribution (sdist)

Source distribution for nlp2sql 0.2.0rc15
File Size Uploaded
nlp2sql-0.2.0rc15.tar.gz 624.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for nlp2sql 0.2.0rc15
File Interpreter ABI Platform
nlp2sql-0.2.0rc15-py3-none-any.whl Python 3 none any Details

Total release size: 762.6 kB

Release files / nlp2sql-0.2.0rc15.tar.gz

Download URL nlp2sql-0.2.0rc15.tar.gz
Size 624.6 kB
Tags Source
SHA-256 checksum
How to use checksums
fcb3cb6d73bc8ebdb4694c7e8ca9f1467b9a593d5296858871f21d1ef021742a
BLAKE2b-256 checksum
How to use checksums
dd58a1da23f8daf5072c5da5b73f6a2d24eff5d66b70b65dc5c52a1afd153897
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 19, 2026.

Transparency log

Release files / nlp2sql-0.2.0rc15-py3-none-any.whl

Download URL nlp2sql-0.2.0rc15-py3-none-any.whl
Size 138.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
dfb63f09898d0a1a39129e5261716cb8444072cb7d2f42eb1c18c0c4bc99f1d0
BLAKE2b-256 checksum
How to use checksums
b56047b6cc38b561aff24da79d984eaabefa3efd34847cd889688aa88e6db109
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 19, 2026.

Transparency log
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