DEV Community

VeilAnalytics
VeilAnalytics

Posted on

Best Open-Source Text-to-SQL Tools in 2025 (Ranked by Privacy & Performance)

Best Open-Source Text-to-SQL Tools in 2025 (Ranked by Privacy & Performance)

Text-to-SQL is one of the most practical AI capabilities available today. Instead of writing SELECT region, SUM(revenue) FROM sales GROUP BY region ORDER BY 2 DESC, you ask "What's total revenue by region?" and the tool writes it for you.

The market has exploded. There are now dozens of tools offering natural language SQL, ranging from cloud APIs to fully local open-source stacks. This guide ranks them on what matters most for production use: privacy, accuracy, setup complexity, and database support.


How We Evaluated Them

Each tool was tested on:

  • Standard NL2SQL benchmarks (Spider, BIRD)
  • Complex multi-table joins with ambiguous phrasing
  • Privacy posture (what data leaves your environment)
  • Ease of integration for a working developer

Tier 1: Fully Local, Maximum Privacy

šŸ„‡ VeilAnalytics + DuckDB-WASM

Privacy: ā˜…ā˜…ā˜…ā˜…ā˜… | Accuracy: ā˜…ā˜…ā˜…ā˜…ā˜† | Setup: ā˜…ā˜…ā˜…ā˜…ā˜…

VeilAnalytics takes the unique approach of running everything in the browser — DuckDB-WASM for compute, and a schema-only prompt approach for the LLM. Your actual data rows never leave your device.

What it does:

  • Runs SQL analytics in-browser with natural language input
  • Schema-only context sent to LLM (never actual data rows)
  • Results computed locally by DuckDB-WASM

Ideal for: Business analysts and developers who need quick, private analysis of CSV/Parquet files.

GitHub: In development, targeting open source release


🄈 Vanna.AI (Local Mode)

Privacy: ā˜…ā˜…ā˜…ā˜…ā˜† | Accuracy: ā˜…ā˜…ā˜…ā˜…ā˜… | Setup: ā˜…ā˜…ā˜…ā˜†ā˜†

Vanna.AI is one of the most production-ready open-source Text-to-SQL frameworks. It uses a Retrieval-Augmented Generation (RAG) approach: store your DDL, documentation, and example queries in a local vector store, then use them as context for each query.

from vanna.ollama import Ollama
from vanna.chromadb import ChromaDB_VectorStore

class MyVanna(ChromaDB_VectorStore, Ollama):
    def __init__(self, config=None):
        ChromaDB_VectorStore.__init__(self, config=config)
        Ollama.__init__(self, config=config)

vn = MyVanna(config={'model': 'llama3.1'})
vn.connect_to_duckdb('my_database.db')

# Train on your schema (done once)
vn.train(ddl="CREATE TABLE orders (id INT, customer_id INT, amount FLOAT, date DATE)")

# Query in natural language
sql = vn.generate_sql("What were the top 5 customers by spending last quarter?")
vn.run_sql(sql)
Enter fullscreen mode Exit fullscreen mode

Strengths:

  • Improves over time with RAG training on your own schema
  • Supports local ChromaDB (no cloud vector store required)
  • Works with any LLM backend (Ollama, OpenAI BYOK, etc.)

Weaknesses:

  • More setup than simpler tools
  • RAG accuracy depends on training quality

šŸ„‰ SQLCoder (Defog)

Privacy: ā˜…ā˜…ā˜…ā˜…ā˜… | Accuracy: ā˜…ā˜…ā˜…ā˜…ā˜… | Setup: ā˜…ā˜…ā˜†ā˜†ā˜†

SQLCoder by Defog is a fine-tuned model specifically for Text-to-SQL, trained on real SQL workloads. It significantly outperforms general-purpose models (GPT-4, Llama) on complex queries.

# Run via Ollama (7B parameter quantized model)
ollama pull sqlcoder:7b

# Via Python
import ollama
response = ollama.generate(
    model='sqlcoder',
    prompt=f"""### Task
Generate SQL to answer: "What are total sales by region for Q3 2024?"

### Database Schema
{your_schema_here}

### Answer
SELECT"""
)
Enter fullscreen mode Exit fullscreen mode

Strengths:

  • Best-in-class accuracy on complex multi-table queries
  • Optimized specifically for SQL (not a generalist model)
  • Fully local via Ollama

Weaknesses:

  • Requires GPU for reasonable performance (CPU is slow)
  • No built-in UI — just the model

Tier 2: Cloud-Assisted (Schema Only, Not Data)

Outlines + Constrained Decoding

Privacy: ā˜…ā˜…ā˜…ā˜…ā˜† | Accuracy: ā˜…ā˜…ā˜…ā˜…ā˜† | Setup: ā˜…ā˜…ā˜†ā˜†ā˜†

Outlines enables structured generation — you can constrain any LLM to output valid SQL syntax only, preventing hallucinated table names and invalid syntax:

import outlines
import outlines.models as models

model = models.transformers("mistralai/Mistral-7B-Instruct-v0.2")

sql_generator = outlines.generate.text(model)

# Only generates valid SQL
result = sql_generator(
    f"Schema: {schema}\nQuestion: {question}\nSQL:"
)
Enter fullscreen mode Exit fullscreen mode

This dramatically reduces syntax errors in generated SQL.


LlamaIndex NLSQLTableQueryEngine

Privacy: ā˜…ā˜…ā˜…ā˜…ā˜† | Accuracy: ā˜…ā˜…ā˜…ā˜…ā˜† | Setup: ā˜…ā˜…ā˜…ā˜†ā˜†

LlamaIndex provides a high-level abstraction for Text-to-SQL that works with any SQL database and any LLM:

from llama_index.core import SQLDatabase
from llama_index.core.query_engine import NLSQLTableQueryEngine
from llama_index.llms.ollama import Ollama

llm = Ollama(model="llama3.1")
sql_db = SQLDatabase(engine, include_tables=["orders", "customers"])
query_engine = NLSQLTableQueryEngine(sql_database=sql_db, llm=llm, tables=["orders"])

response = query_engine.query("Which customers placed the most orders?")
Enter fullscreen mode Exit fullscreen mode

Strengths: Easy integration with existing SQLAlchemy databases, supports many LLMs.


Tier 3: Cloud API (Data Leaves Your Environment)

OpenAI GPT-4 with Function Calling

Privacy: ā˜…ā˜…ā˜†ā˜†ā˜† | Accuracy: ā˜…ā˜…ā˜…ā˜…ā˜… | Setup: ā˜…ā˜…ā˜…ā˜…ā˜…

The simplest implementation — but your schema (and potentially data samples) go to OpenAI:

from openai import OpenAI
client = OpenAI()

response = client.chat.completions.create(
    model="gpt-4o",
    messages=[{
        "role": "user",
        "content": f"Schema: {schema}\nGenerate SQL for: {question}"
    }]
)
Enter fullscreen mode Exit fullscreen mode

Best accuracy on complex queries. Worst privacy — every schema call goes to OpenAI. Not suitable for sensitive databases.


Summary Comparison Table

Tool Privacy SQL Accuracy Setup Complexity Best For
VeilAnalytics ā˜…ā˜…ā˜…ā˜…ā˜… ā˜…ā˜…ā˜…ā˜…ā˜† ā˜…ā˜…ā˜…ā˜…ā˜… Browser CSV analysis
Vanna.AI (local) ā˜…ā˜…ā˜…ā˜…ā˜† ā˜…ā˜…ā˜…ā˜…ā˜… ā˜…ā˜…ā˜…ā˜†ā˜† Production apps
SQLCoder (Ollama) ā˜…ā˜…ā˜…ā˜…ā˜… ā˜…ā˜…ā˜…ā˜…ā˜… ā˜…ā˜…ā˜†ā˜†ā˜† High accuracy queries
LlamaIndex ā˜…ā˜…ā˜…ā˜…ā˜† ā˜…ā˜…ā˜…ā˜…ā˜† ā˜…ā˜…ā˜…ā˜†ā˜† Python integrations
Outlines ā˜…ā˜…ā˜…ā˜…ā˜† ā˜…ā˜…ā˜…ā˜…ā˜† ā˜…ā˜…ā˜†ā˜†ā˜† Constrained output
GPT-4 Direct ā˜…ā˜…ā˜†ā˜†ā˜† ā˜…ā˜…ā˜…ā˜…ā˜… ā˜…ā˜…ā˜…ā˜…ā˜… Prototyping only

2025 Recommendation

For maximum privacy + good accuracy: Run SQLCoder via Ollama for the LLM layer, with DuckDB for the execution layer. Schema-only prompts mean no data rows leave your machine.

For zero setup + business users: VeilAnalytics in the browser — no installation, no accounts, no uploads.

For production apps with enterprise databases: Vanna.AI with local ChromaDB + Ollama — the RAG approach learns your schema over time and improves accuracy.

The open-source Text-to-SQL landscape in 2025 is genuinely mature enough to replace cloud tools for most use cases, with full data privacy. The performance gap with GPT-4 has closed significantly with fine-tuned models like SQLCoder.


VeilAnalytics — Natural language analytics for your data. In-browser, open, private.

Top comments (1)

Collapse
 
ashish_sinha_5241c7673d93 profile image
Ashish sinha

One correction worth making, since this is a ranking people will act on: Vanna is archived. The repo is read-only -- archived: true as of this morning, 23.8k stars, 2.5k forks, last push 2 February. It is still good engineering and the RAG approach is sound, but "for production apps with enterprise databases" is a hard recommendation to make about a project that cannot take a security patch, and the 2,513 forks have nowhere to file the issue asking for one.

The other thing worth adding, since this list is ranked on privacy specifically: schema-only is not the same as private, and the gap has nothing to do with rows.

The schema is often the sensitive artifact. hr_compensation_2027_layoffs discloses something whether or not a single row ever leaves the machine, and a schema-only prompt sends the name.

And schema-only in practice means whole-schema: every caller gets every table, so the prompt is identical for the analyst and the intern. Row-level security does not close this, because RLS acts when the query runs and the table names reached the model long before that. The failure is quiet -- the model writes correct SQL against a table the caller may not read, RLS strips every row, and the user is told "no records found", which is indistinguishable from "this data does not exist".

It is a scale problem as much as a policy one. At 260 tables the whole schema does not fit in the prompt at all, so something already has to choose which tables to send. That chooser is the thing that should be taking the caller's identity, and in most stacks it takes nothing.

Disclosure: I wrote an Apache-2.0 library for that selection step (pip install schemagate), so I am not neutral on the last two paragraphs. The Vanna archive status is just a fact worth checking before someone picks it for production.