MCPcopy Index your code
hub / github.com/LalitMaganti/syntaqlite

github.com/LalitMaganti/syntaqlite @v0.6.0

Chat with this repo
repository ↗ · DeepWiki ↗ · release v0.6.0 ↗ · + Follow
6,600 symbols 20,469 edges 438 files 1,619 documented · 25% updated 1d agov0.6.0 · 2026-06-17★ 79010 open issues
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

  syntaqlite

A parser, formatter, validator, and language server for SQLite SQL, built on SQLite's own grammar and tokenizer. If SQLite accepts it, syntaqlite parses it. If SQLite rejects it, so does syntaqlite.

Docs · Playground · VS Code Extension

Note: syntaqlite is at 0.x. APIs and CLI flags may change before 1.0.

Why syntaqlite

Most SQLite tools build a generic SQL parser and bolt SQLite on as a "flavor" with hand-written grammars, regex-based tokenizers, or subsets that approximate the language. That falls apart because SQLite has a deep surface area of syntax that generic parsers don't handle.

syntaqlite uses SQLite's own Lemon-generated grammar and tokenizer, compiled from C. Its parser is that grammar compiled into a reusable library, not an approximation of it.

SQLite SQL is also not one fixed language. It has 22 compile-time flags that change what syntax the parser accepts, another 12 that gate built-in functions, and the language evolves across versions. Because SQLite is embedded, you can't assume everyone is on the latest version (Android 15 ships SQLite 3.44.3, seven major versions behind latest). syntaqlite tracks all of this:

syntaqlite --sqlite-version 3.32.0 validate \
  -e "DELETE FROM users WHERE id = 1 RETURNING *;"
error: syntax error near 'RETURNING'
 --> <stdin>:1:32
  |
1 | DELETE FROM users WHERE id = 1 RETURNING *;
  |                                ^~~~~~~~~

RETURNING was added in SQLite 3.35.0; Android 13 still ships SQLite 3.32.2.

We've tested against ~396K statements from SQLite's upstream test suite with ~99.7% agreement on parse acceptance. See the detailed comparison for how syntaqlite stacks up against other tools.

What it does

Validate (docs)

Finds unknown tables, columns, and functions against your schema, the same errors sqlite3_prepare would catch but without needing a database. Unlike sqlite3, syntaqlite finds all errors in one pass:

CREATE TABLE orders (id, status, total, created_at);

WITH
  monthly_stats(month, revenue, order_count) AS (
    SELECT strftime('%Y-%m', o.created_at), SUM(o.total)
    FROM orders o WHERE o.status = 'completed'
    GROUP BY strftime('%Y-%m', o.created_at)
  )
SELECT ms.month, ms.revenue, ms.order_count,
  ROUDN(ms.revenue / ms.order_count, 2) AS avg_order
FROM monthly_stats ms;

sqlite3 stops at the first error and misses the function typo entirely:

Error: in prepare, table monthly_stats has 2 values for 3 columns

syntaqlite finds both the CTE column count mismatch and the ROUDN typo, with source locations and suggestions:

error: table 'monthly_stats' has 2 values for 3 columns
  |
2 | monthly_stats(month, revenue,
  | ^~~~~~~~~~~~~

warning: unknown function 'ROUDN'
   |
14 | ROUDN(ms.revenue / ms.order_count,
   | ^~~~~
   = help: did you mean 'round'?

Format (docs)

Deterministic formatting with configurable line width, keyword casing, and indentation:

echo "select u.id,u.name, p.title from users u join posts p on u.id=p.user_id
where u.active=1 and p.published=true order by p.created_at desc limit 10" \
  | syntaqlite fmt
SELECT u.id, u.name, p.title
FROM users u
  JOIN posts p ON u.id = p.user_id
WHERE u.active = 1
  AND p.published = true
ORDER BY p.created_at DESC
LIMIT 10;

Version and compile-flag aware (docs)

Pin the parser to a specific SQLite version or enable compile-time flags to match your exact build:

# Reject syntax your target SQLite version doesn't support
syntaqlite --sqlite-version 3.32.0 validate query.sql

# Enable optional syntax from compile-time flags
syntaqlite --sqlite-cflag SQLITE_ENABLE_MATH_FUNCTIONS validate query.sql

Validate SQL inside other languages (experimental)

SQL lives inside Python and TypeScript strings in most real codebases. syntaqlite extracts and validates it, handling interpolation holes:

# app.py
def get_user_stats(user_id: int):
    return conn.execute(
        f"SELECT nme, ROUDN(score, 2) FROM users WHERE id = {user_id}"
    )
syntaqlite analyze --experimental-lang python app.py
warning: unknown function 'ROUDN'
 --> app.py:3:23
  |
3 |         f"SELECT nme, ROUDN(score, 2) FROM users WHERE id = {user_id}"
  |                       ^~~~~
  = help: did you mean 'round'?

sqlite3 shell scripts

Scripts for the sqlite3 CLI mix SQL with dot-commands like .read and .print. syntaqlite recognizes the dot-commands and skips over them rather than reporting a syntax error, so the surrounding SQL still formats and validates. The editor integration handles them the same way.

syntaqlite fmt schema.sql
.read tables.sql
.read views.sql

CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT);

Project configuration

Create a syntaqlite.toml in your project root to configure schemas and formatting. The LSP, CLI, and all editor integrations read it automatically:

# Map SQL files to schema DDL files for validation and completions.
[schemas]
"src/**/*.sql" = ["schema/main.sql", "schema/views.sql"]
"tests/**/*.sql" = ["schema/main.sql", "schema/test_fixtures.sql"]
"migrations/*.sql" = []  # no schema validation for migrations

# Default schema for SQL files that don't match any glob above.
# schema = ["schema.sql"]

# Formatting options (all optional, shown with defaults).
[format]
line-width = 80
indent-width = 2
keyword-case = "upper"    # "upper" | "lower"
semicolons = true

The config file is discovered by walking up from the file being processed, same as rustfmt.toml or ruff.toml. CLI flags override config file values.

Editor integration (docs)

Full language server with no database connection required. Diagnostics, format on save, completions, and semantic highlighting.

VS Code — install the syntaqlite extension from the marketplace.

Other editors — point your LSP client at:

syntaqlite lsp

Claude Codeclaude plugin install syntaqlite@lalitmaganti-plugins (docs)

Parse (docs)

Full abstract syntax tree with side tables for tokens, comments, and whitespace, for code generation, migration tooling, or static analysis.

syntaqlite parse -e "SELECT 1 + 2"

Web Playground

Want to try syntaqlite without installing anything? The web playground runs entirely in your browser via WASM. Parse, format, and validate SQL instantly.

Install (all methods)

Download and run (all platforms, no install)

curl -sSf https://raw.githubusercontent.com/LalitMaganti/syntaqlite/main/tools/syntaqlite | python3 - fmt -e "select 1"

Downloads the binary on first run, caches it, auto-updates weekly.

mise

mise use github:LalitMaganti/syntaqlite

pip (all platforms, bundled binary)

pip install syntaqlite

Homebrew (macOS)

brew install LalitMaganti/tap/syntaqlite

Cargo

cargo install syntaqlite-cli

Use as a library (docs)

Rust (API docs)

[dependencies]
syntaqlite = { version = "0.6.0", features = ["fmt"] }

Python (API docs)

pip install syntaqlite

JavaScript / WASM (API docs)

npm install syntaqlite

C — the parser, tokenizer, formatter, and validator all have C APIs. See the C API docs.

Architecture (docs)

The parser and tokenizer are written in C, directly wrapping SQLite's own grammar. Everything else (formatter, validator, LSP) is written in Rust with C bindings available.

The split is intentional. The C parser is as portable as SQLite itself: it can run inside database engines, embedded systems, or anywhere SQLite runs. The Rust layer moves fast for developer tooling where the standard library and crate ecosystem matter.

Building from source

tools/install-build-deps
tools/cargo build

Contributing

See the contributing guide for architecture overview and testing instructions.

License

Apache 2.0. SQLite components are public domain under the SQLite blessing. See LICENSE for details.

Extension points exported contracts — how you extend this code

GrammarNodeType (Interface)
Trait for AST node views that can be materialized from arena IDs. Implemented by generated node wrappers and used by ge [74 …
syntaqlite-syntax/src/ast.rs
SemanticVisitor (Interface)
A walk-time visitor: receives pre-resolved events from the walker and decides what to do with them. Every hook has an em [6 …
syntaqlite/src/analysis/engine/walker.rs
CliApp (Interface)
Configuration trait for a `syntaqlite` CLI binary. Implementors describe the program name, default dialect, and which d [4 …
syntaqlite-cli/src/lib.rs
CflagEntry (Interface)
(no doc)
web/syntaqlite-js/src/engine.ts
SwitchOption (Interface)
(no doc)
web/playground/src/components/switch.ts
TypedNodeId (Interface)
Trait for typed node IDs generated per AST node kind. IDs are cheap, storable handles that can later be resolved agains [86 …
syntaqlite-syntax/src/ast.rs
ModuleResolver (Interface)
Module resolution for `INCLUDE` statements during analysis. Callback for resolving `INCLUDE PERFETTO MODULE` (or similar [4 …
syntaqlite/src/analysis/resolver.rs
Sink (Interface)
Output strategy for parsed statements. Adding a new `--output` mode is a new struct + `impl Sink`; the parse loop and to [3 …
syntaqlite-cli/src/commands/parse.rs

Core symbols most depended-on inside this repo

expect
called by 397
syntaqlite-buildtools/src/util/synq_parser.rs
get
called by 393
syntaqlite-syntax/src/ast.rs
iter
called by 322
syntaqlite-syntax/src/ast.rs
line
called by 322
syntaqlite-buildtools/src/dialect_codegen/python_codegen.rs
push
called by 267
syntaqlite-syntax/src/ast.rs
len
called by 252
syntaqlite-syntax/src/ast.rs
map
called by 241
syntaqlite-syntax/src/parser/types.rs
append
called by 184
syntaqlite-buildtools/src/util/c_transformer.rs

Shape

Method 2,634
Function 2,432
Class 1,301
Enum 176
Interface 57

Languages

Rust51%
Python31%
C7%
C++6%
TypeScript4%

Modules by API surface

syntaqlite-syntax/src/sqlite/ast.rs338 symbols
syntaqlite-syntax/include/syntaqlite_sqlite/sqlite_node.h257 symbols
syntaqlite-buildtools/sqlite-vendored/sources/lemon.c204 symbols
python/syntaqlite/nodes.py197 symbols
syntaqlite-syntax/src/parser/session.rs130 symbols
tests/fmt_diff_tests/operator_precedence.py129 symbols
syntaqlite/src/analysis/ffi/tests.rs101 symbols
syntaqlite-syntax/src/parser/ffi.rs93 symbols
tests/fmt_diff_tests/comments.py86 symbols
syntaqlite-syntax/src/parser/mod.rs81 symbols
syntaqlite-syntax/csrc/sqlite/dialect_builder.h79 symbols
syntaqlite/tests/cflags.rs76 symbols

For agents

$ claude mcp add syntaqlite \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact