Open-source project
tobymao/sqlglot avatar
tobymao/sqlglot

SQLGlot: a Python SQL parser and transpiler for translating between 30+ dialects

Python SQL Parser and Transpiler

9,646 stars1,306 forksPythonMIT

At a glance

What is it?
SQLGlot reads SQL into an abstract syntax tree and writes it back out in another dialect, with no runtime dependencies. It is a transpiler, not a validator, and that distinction decides whether it fits your pipeline.
Who is it for?
Adopt SQLGlot if you need to move SQL text between engines, format it, or walk its structure programmatically, and you can name the source and target dialects explicitly. Do not adopt it as a query validator or as an execution engine for production workloads; the parser is intentionally lenient and the engine is a convenience.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What SQLGlot actually solves for data and platform engineers

SQL dialects diverge in ways that break copy-paste. Date functions, identifier quoting, and type names differ between engines, so a query written for one warehouse often will not run on another without edits. SQLGlot exists to absorb that difference in code rather than by hand. The README states the aim plainly: it reads a wide variety of SQL inputs and outputs syntactically and semantically correct SQL in the targeted dialects.

The audience is developers who handle SQL as text. Migration projects that move workloads from Spark to DuckDB, linting and formatting tools, lineage and metadata extraction, and platforms that accept user-written SQL and must rewrite it for a different backend. The README lists usage categories including formatting, transpiling, metadata analysis, expression tree traversal, and programmatic SQL construction. If your job is to run queries, SQLGlot is not the layer you want. If your job is to read, rewrite, or inspect them, it is built for exactly that.

How the parser, AST and generator fit together

The pipeline has three stages. A parser turns SQL text into an abstract syntax tree of expression nodes. Transformations, either built-in or yours, operate on that tree. A generator walks the tree and emits SQL for a target dialect. The README points readers to an expression tree primer in the repository, and the AST is the surface you work against for introspection and modification.

Dialect handling is the part worth understanding before you commit. Without a source dialect, parse_one assumes the SQLGlot dialect, described in the README as a superset of all supported dialects. That default is generous, and it is also why a query can parse when it should not. The target dialect is equally explicit: parse_one(sql, dialect="spark").sql(dialect="duckdb"), or transpile(sql, read="spark", write="duckdb"). Nothing is inferred from context.

Dialects live in sqlglot/dialects/__init__.py, and the README says there are over 30. The project also supports custom dialects by subclassing an existing one, or shipping a dialect as a separate package. That extension path is real, but it comes with a caveat the README states directly: subclassing may not work properly with sqlglot[c] installed, so custom dialects may require the pure Python version.

Installing SQLGlot and transpiling your first query

Installation is a single pip command. The README gives two variants, and the difference matters for speed.

bash
# Pure python version
pip3 install sqlglot

# C extensions compiled with mypyc
# prebuilt wheel if available for your platform, otherwise builds from source
pip3 install "sqlglot[c]"

The plain install pulls no dependencies. The bracketed variant installs sqlglotc, compiled with mypyc. The setup.py in the repository notes that this compiles from source on the user's machine and requires Python 3.10 or newer, because the build dependency dropped 3.9. On Python 3.9, the README's install section still works, but the extra is a no-op and you get pure Python SQLGlot. If you are on 3.9, do not expect the speedup.

A first real use is translating a function call between engines. The README uses DuckDB to Hive, where date and time functions differ enough to be annoying by hand.

python
import sqlglot
sqlglot.transpile("SELECT EPOCH_MS(1618088028295)", read="duckdb", write="hive")[0]

The returned string is the Hive equivalent, with the epoch conversion rewritten into FROM_UNIXTIME and a division by a power of ten. The same call works on custom time formats, so STRFTIME patterns from DuckDB come out as DATE_FORMAT patterns for Hive.

For readable output, pass pretty and identify. The README example converts a query to Spark SQL, formats it, and delimits every identifier with backticks, which is what Spark requires.

python
sqlglot.transpile(sql, write="spark", identify=True, pretty=True)[0]

What you should see is the same query with backticked identifiers, REAL rewritten as FLOAT, and each join clause on its own line. If your input dialect is not named, expect surprises rather than errors.

Where SQLGlot will let you down

The README answers its own hardest question. Why does SQLGlot parse invalid SQL without complaining? Because the parser is intentionally lenient, so it can accept queries a real engine would reject. The project describes itself as a transpiler, not a validator, and states that a query which parses successfully may still fail at execution time. Anyone planning to gate a deployment on whether SQLGlot parses is building on the wrong guarantee.

Formatting is the second trap. Because output is generated from the AST, meaning is preserved and exact text is not. Cosmetic details can change, including casing and quoting. Comments survive only on a best-effort basis. If you need byte-stable output for diffing or caching, this design will fight you, and pretty=True does not restore the original layout.

The engine is a convenience, not a production database. The README lists SQL execution among its examples, and it is useful for testing transpiled queries, but nothing in the project's documentation suggests it is intended to replace a real warehouse. Treat it as a development aid.

Finally, the dialect coverage is broad but not universal. If your engine is missing, you subclass or ship a plugin, and the README warns that custom dialects may require the pure Python build. That is a direct trade against the compiled speedup.

SQLGlot compared with SQLAlchemy and dbt-adjacent tooling

SQLAlchemy is the comparison people reach for, and the difference is one of purpose. SQLAlchemy is an ORM and database toolkit: you build queries from Python objects and it handles connection pooling, transactions, and result mapping against a live database. SQLGlot never connects to anything. It takes SQL text in and gives SQL text, or an expression tree, back. If you want to execute against PostgreSQL from Python, SQLAlchemy is the layer. If you want to take the SQL your analysts already wrote and emit a Snowflake-compatible version, SQLGlot is the layer. They can sit in the same application without overlapping.

The second comparison is against engine-side translation. Some warehouses offer their own conversion tooling, and it is authoritative for that vendor's syntax. SQLGlot's advantage is that it is a library you can embed, call in a loop, and extend, and its dialect set spans engines from different vendors rather than one. The cost is that correctness depends on community-maintained dialect definitions rather than the engine vendor, and the README's own FAQ admits that if parsing fails on valid SQL, you should file an issue. That is an honest description of a community project, and it tells you to test your specific query shapes rather than trust the dialect list.

Maintenance, versioning and the MIT licence

The repository is not archived, and the last push was on 2026-09-21, so the codebase is being changed. That is a statement about activity, not about the quality of any particular release, and there are no release notes available to read through.

Versioning is documented and worth reading before you pin. Given MAJOR.MINOR.PATCH, PATCH is incremented for backwards-compatible changes, MINOR for backwards-incompatible changes, and MAJOR for significant backwards-incompatible changes. That is the inverse of the convention many Python developers expect, where a minor bump is usually safe. If you pin to a minor range, you are pinning across breaking changes. Pin exactly, or read the changelog before moving.

The project is MIT licensed, with license-files = ["LICENSE"] declared in pyproject.toml. MIT is permissive and imposes no copyleft obligation on your code, but the repository does not cover attribution requirements or how the licence interacts with the optional sqlglotc component, so check the LICENSE file and the sqlglotc package terms yourself rather than assuming a single licence covers everything you install. This is not legal advice.

Upgrade cost is mostly the versioning policy plus dialect drift. A dialect definition can change between releases as engines change, so a query that transpiles cleanly today may produce different output after an upgrade. Keep a small fixture set of the queries you actually transpile and run it after each bump.

Deciding whether SQLGlot belongs in your stack

The fit is narrow and clear. You have SQL as text, you know which dialect it is written in, and you need it in another dialect, formatted, inspected, or rebuilt. You are comfortable reading an AST and writing tree transformations. You can pin versions and rerun a fixture set on upgrade.

The misfit is equally clear. You want validation before execution, and you need the parser to reject bad queries. You want byte-identical formatting for diffing. You need a production query engine. You are on Python 3.9 and were counting on the compiled speedup, or you plan to subclass a dialect and want sqlglot[c] at the same time, which the README says may not work properly.

Before adopting, confirm your dialect is among those in sqlglot/dialects/__init__.py, and run your three or four most awkward queries through transpile with explicit read and write values. If those come out correct, the rest of the library is a matter of learning the expression tree.

Editorial conclusion

Adopt SQLGlot if you need to move SQL text between engines, format it, or walk its structure programmatically, and you can name the source and target dialects explicitly. Do not adopt it as a query validator or as an execution engine for production workloads; the parser is intentionally lenient and the engine is a convenience. Verify first that your dialect appears in the dialects module, and decide whether you need the pure Python install or sqlglot[c], because custom dialects may not work properly with the compiled version installed.

Frequently asked questions

Is SQLGlot open source?

Yes. The repository is licensed under MIT, and pyproject.toml declares license = "MIT" with license-files = ["LICENSE"]. The source is on GitHub at tobymao/sqlglot.

How do I install SQLGlot?

Install the pure Python version with pip3 install sqlglot, or install the mypyc-compiled extensions with pip3 install "sqlglot[c]". The compiled variant requires Python 3.10 or newer, and on Python 3.9 the extra is a no-op.

What is SQLGlot used for?

It parses SQL into an abstract syntax tree, transpiles between over 30 dialects, formats SQL, analyzes query metadata, and lets you build or modify SQL programmatically. The README also lists SQL execution among its examples.

How do I use SQLGlot to convert one SQL dialect to another?

Call transpile with explicit read and write dialects, for example sqlglot.transpile(sql, read="duckdb", write="hive")[0]. The target dialect must always be specified, because the generated SQL is not inferred from the input.

Is SQLGlot safe to use?

The project does not make a security claim. What the README does state is that the parser is intentionally lenient and that SQLGlot is a transpiler, not a validator, so a query that parses may still fail when a real engine runs it.

What is the AST in SQLGlot?

It is the expression tree that the parser produces from SQL text and that the generator walks to emit SQL for a target dialect. The repository includes an expression tree primer, and the README lists AST introspection and AST diff among the available operations.

Official sources

  1. Issues
  2. License: MIT
  3. Project website
  4. README
  5. tobymao/sqlglot on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/tobymao-sqlglot.svg)](https://hysenlabs.com/projects/tobymao-sqlglot)