Convert SQL schema DDL between dialects using a compact intermediate representation.
xsql is a lightweight CLI and TUI that parses, diffs, and emits SQL schema DDL for MySQL, PostgreSQL, and SQLite. It relies on an experimental IR v2 to improve portability, enable round-tripping and linting, and to pave the way for future ALTER-statement generation.
What it does (today)
- Parses schema DDL from:
- MySQL
- PostgreSQL
- SQLite
- Emits schema DDL to:
- MySQL
- PostgreSQL
- SQLite
- Converts:
- a single
.sqlfile → another.sqlfile - a whole folder tree of
.sqlfiles → a destination folder (preserves relative paths)
- a single
- Includes an interactive TUI (
xsql tui).
Quickstart
Install and run quickly (recommended):
# one-line install (clones, builds, installs to $HOME/.cargo/bin) curl -fsSL https://raw.githubusercontent.com/Dawaman43/xsql/main/install.sh | sh # then run the tool xsql --help
Build from source
If you prefer to build locally:
cargo build --release
The development binary will be at target/release/xsql.
There is also an installer script at install.sh in this repo; the curl one-liner above runs it.
xsql
Convert SQL schema DDL between dialects (focused on CREATE TABLE) via a small intermediate representation (IR).
Quickstart
Install and run quickly (recommended):
# one-line installer (clones, builds, installs xsql) curl -fsSL https://raw.githubusercontent.com/Dawaman43/xsql/main/install.sh | sh # then run the tool xsql --help
Design
IR v2 (experimental)
IR v2 is an opt-in richer intermediate representation for schema portability. It captures:
- Table-level constraints (
UNIQUE,FOREIGN KEY,CHECK) - Column-level constraints (
NOT NULL,DEFAULT,AUTO_INCREMENT/identity) - Portable data types (
Integer,Boolean,Float,Varchar,Text,Timestamp) - Free-form
metadataandannotationsfor tools to add hints
Parsers can output V2 JSON and emitters can read V2 JSON to produce dialect SQL. This is useful for round-tripping, linting, and future ALTER-generation.
CLI examples (v2):
# Parse a Postgres SQL file into V2 JSON xsql v2-parse schema.sql --dialect postgres > schema.v2.json # Emit MySQL SQL from a V2 JSON file xsql v2-emit schema.v2.json --dialect mysql > schema.mysql.sql # Diff two V2 JSON files (human output) xsql v2-diff old.v2.json new.v2.json # Diff two V2 JSON files (machine JSON output) xsql v2-diff old.v2.json new.v2.json --json > diff.json
Notes and limitations:
- V2 is still experimental: some vendor-specific types and complex CHECK expressions
may be preserved as
Custom/annotationsand not always round-trippable. - ALTER-statement generation is planned; currently emitters output
CREATE TABLE.
Architecture
xsql uses a small intermediate representation (IR) to separate parsing from emitting:
- Parser crates (in
crates/xsql-parser) read dialect-specific SQL into the IR. - The IR crate (
crates/xsql-ir) contains a minimal typed model for tables, columns and basic constraints. - Emitter crates (in
crates/xsql-emitter) produce dialect-specific SQL from the IR.
This design makes it straightforward to add new dialects and to centralize mapping logic between types and constraints.
Why an IR?
- Bidirectional conversion: parse → IR → emit avoids ad-hoc text transforms.
- Easier testing: round-trip tests (parse → IR → emit → parse) validate correctness.
- Incremental growth: start with CREATE TABLE and expand IR for indexes, constraints and more.
Build from source
If you prefer to build locally:
cargo build --release --manifest-path crates/xsql-cli/Cargo.toml
The development binary will be at crates/xsql-cli/target/release/xsql (or in the workspace target/release).
There is also an installer script at install.sh in this repo; the curl one-liner above runs it.
CI snippet (example)
Use v2-parse/v2-emit in CI to validate schema round-trips and detect portability issues. Example GitHub Actions step:
- name: Validate schema roundtrip uses: actions/checkout@v4 - name: Setup Rust uses: actions-rs/toolchain@v1 with: toolchain: stable - name: Build xsql run: cargo build --release --manifest-path crates/xsql-cli/Cargo.toml - name: Parse and emit (roundtrip) run: | ./target/release/xsql v2-parse examples/postgres.sql --dialect postgres > /tmp/schema.v2.json ./target/release/xsql v2-emit /tmp/schema.v2.json --dialect mysql > /tmp/schema.mysql.sql - name: Compute v2 diff run: | ./target/release/xsql v2-parse examples/postgres.sql --dialect postgres > /tmp/old.v2.json ./target/release/xsql v2-parse examples/mysql.sql --dialect mysql > /tmp/new.v2.json ./target/release/xsql v2-diff /tmp/old.v2.json /tmp/new.v2.json --json > /tmp/diff.json
Installer notes
- The installer runs a quiet build and shows a spinner animation while compiling.
- It will try to move the installed
xsqlbinary into/usr/local/bin(this may prompt forsudo) so the tool is immediately available system-wide. - If moving to
/usr/local/binis not possible, the installer adds$HOME/.cargo/binto your shell RC (prefers~/.zshrc, then~/.bashrc, then~/.profile) soxsqlwill be available in future sessions. - If the installer cannot move the binary, you can make it available immediately in your current shell by running:
export PATH="$HOME/.cargo/bin:$PATH" # or source the updated rc, e.g.: source ~/.zshrc
Do not run the curl+sh command with sudo — the installer handles any required privilege escalation when moving the binary to /usr/local/bin.
CLI usage
Start the TUI (default)
xsql
Or explicitly:
xsql tui
Convert one file
xsql --from mysql --to postgres --input schema.sql --output schema.pg.sql
Convert a folder (recursive)
xsql --from postgres --to sqlite --input ./schemas --output ./out
Only files ending in .sql are converted; others are ignored.
Use the TUI
xsql tui
Tab/Shift+Tabmoves between fields↑/↓or←/→changes dialect when focused on From/Toiopens input picker,oopens output pickerxswaps from/to dialects,rruns conversionEnterruns conversion when focused on Run- If the output folder doesn't exist, the TUI will ask to create it (
y/n). Escquits
TUI keybindings
While the TUI is open, these keys are available:
- Navigation:
Up/Down(move selection) - Fast navigation:
PageUp/PageDown,Home/End - Parent directory:
LeftorBackspace - Open / enter directory:
RightorEnter - Select item:
s(select file or directory) - Start search/filter:
/(then type to filter results)- While searching: typing adds to the query,
Backspaceremoves a character,Escexits search
- While searching: typing adds to the query,
- Confirm directory selection: when prompted after selecting a directory press
ato select all files orfto pick individual files - Toggling:
dtoggles dry-run,xswapsfrom/todialects,rruns conversion - Quick pickers:
iopen input picker,oopen output picker
Hints are shown at the top of the picker when active.
TUI workflow is designed to be “no typing”:
- Pick input file or folder
- Pick output folder
- Press Enter to run
Examples
See the examples/ folder for small sample schemas (mysql.sql, postgres.sql, sqlite.sql).
Important limitations
This project currently focuses on a small subset of SQL needed for schema conversion:
- Only
CREATE TABLEis converted. - The intermediate representation is intentionally minimal (
xsql-ir). - Many dialect-specific features (indexes, constraints beyond primary keys, foreign keys, check constraints, extensions, etc.) are not yet mapped.
- Type mapping is best-effort (unknown types become
TEXT).
Roadmap (realistic)
- Expand IR to cover more schema features (constraints, indexes)
- Improve type mapping and defaults across dialects
- Add more dialects (e.g. MSSQL, BigQuery, Snowflake) as the IR grows
Contributing
See CONTRIBUTING.md.
License
MIT LICENSE.