Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
2a6e8f2
Add D1 Cloudflare adapter, change python dependency install flow, ada…
Maxteabag Dec 16, 2025
4bc908f
Improve driver installation flow
Maxteabag Dec 16, 2025
2fa6988
Improve driver installation ux
Maxteabag Dec 16, 2025
0547cd7
Improve driver installation even more
Maxteabag Dec 16, 2025
8154b8b
Remove pre commit
Maxteabag Dec 16, 2025
644b211
Lazy load adapters
Maxteabag Dec 16, 2025
3fc90b2
Minor tweaks
Maxteabag Dec 17, 2025
d4e5b8e
Use Keyring as default credentials storage
Maxteabag Dec 17, 2025
dde111d
Improve startup performance and profiling
Maxteabag Dec 17, 2025
7537874
Add debug launch timing status bar
Maxteabag Dec 17, 2025
a55e5ab
Add debug launch timing status bar
Maxteabag Dec 17, 2025
24a445e
UI polishing
Maxteabag Dec 17, 2025
ce7c94d
Optimzations
Maxteabag Dec 17, 2025
e429ae1
Merge branch 'optimization'
Maxteabag Dec 17, 2025
e2a10ea
Upgrade CLI
Maxteabag Dec 17, 2025
bed0188
Make design more lazygit
Maxteabag Dec 17, 2025
fc27a98
Theme and ux improvements
Maxteabag Dec 17, 2025
c5cff2c
Minor design changes
Maxteabag Dec 17, 2025
d9f5a9f
Sqlit theme to be default
Maxteabag Dec 17, 2025
f3cfafa
Improve yank animations
Maxteabag Dec 17, 2025
ac7885a
Adapt tests to new CLI API
Maxteabag Dec 17, 2025
d33738c
Fix CLI PWD edge case - fix all tests
Maxteabag Dec 17, 2025
3b8cca5
Add support for unknown installer
Maxteabag Dec 17, 2025
eb8a5a6
QoF changes - Add VIM bindings
Maxteabag Dec 17, 2025
a4e800d
Update cell functioality, save cursor between queries
Maxteabag Dec 17, 2025
e3ca997
UX polish - add x to clear results
Maxteabag Dec 18, 2025
37d4af0
Fix incosnsitent spacing on pane header
Maxteabag Dec 18, 2025
de0ac34
Remove dead code
Maxteabag Dec 18, 2025
556fa52
Improve leader menu and help menu
Maxteabag Dec 18, 2025
512d88b
Update demos
Maxteabag Dec 18, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,17 @@ jobs:

- name: Run unit tests
run: |
pytest tests/test_validation.py tests/ui/ -v --timeout=60
pytest tests/ -v --timeout=60 \
--ignore=tests/test_sqlite.py \
--ignore=tests/test_mssql.py \
--ignore=tests/test_postgresql.py \
--ignore=tests/test_mysql.py \
--ignore=tests/test_oracle.py \
--ignore=tests/test_mariadb.py \
--ignore=tests/test_duckdb.py \
--ignore=tests/test_cockroachdb.py \
--ignore=tests/test_turso.py \
--ignore=tests/test_ssh.py

test-sqlite:
runs-on: ubuntu-latest
Expand Down
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ venv/
*.swp
*.swo

# Local caches
.cache/
.ruff_cache/
.sqlit/

# OS
.DS_Store

Expand All @@ -34,3 +39,6 @@ aur/src/
aur/pkg/
aur/*.pkg.tar.*
sqlit-notifications/

# Integration test artifacts
tests/integration/python_packages/artifacts/
10 changes: 10 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-toml
- id: check-added-large-files
- id: check-merge-conflict
2 changes: 1 addition & 1 deletion .sqlit-config/settings.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"theme": "tokyo-night",
"expanded_nodes": []
}
}
114 changes: 85 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ A lightweight TUI for people who just want to run some queries fast.


## Motivation
I usually do my work in the terminal, but I found myself either having to boot up massively bloated GUI's like SSMS or Vscode for the simple task of merely browsing my databases and doing some queries toward them. For the vast majority of my use cases, I never used any of the advanced features for inspection and debugging that SSMS and other feature-rich clients provide.
I usually do my work in the terminal, but I found myself either having to boot up massively bloated GUI's like SSMS or Vscode for the simple task of merely browsing my databases and doing some queries toward them. For the vast majority of my use cases, I never used any of the advanced features for inspection and debugging that SSMS and other feature-rich clients provide.

I had the unfortunate situation where doing queries became a pain-point due to the massive operation it is to open SSMS and it's lack of intuitive keyboard only navigation.

Expand All @@ -45,11 +45,56 @@ sqlit is a lightweight database TUI that is easy to use and beautiful to look at

## Installation

### Method 1: `pipx` (Recommended)

This is the recommended method. It installs `sqlit-tui` in an isolated environment, so optional drivers are easy to add later.

1. **Install pipx:** If you don't have pipx, you can install it with:
```bash
python3 -m pip install --user pipx
python3 -m pipx ensurepath
```
*(You may need to restart your terminal after this step)*

2. **Install sqlit-tui:**
```bash
pipx install sqlit-tui
```

3. **Optional drivers (only if you need them):** `sqlit` will tell you what to install when a driver is missing, but you can also pre-install them. For example:
```bash
# PostgreSQL / Supabase / CockroachDB
pipx inject sqlit-tui psycopg2-binary

# MySQL
pipx inject sqlit-tui mysql-connector-python
```

### Method 2: `uv` (Alternative)

`uv` is a fast, modern installer. This also keeps things isolated and makes optional drivers easy.

```bash
pip install sqlit-tui
uv tool install sqlit-tui
```

If you are missing Python packages for your database provider, sqlit will help you install them when you attempt to connect. If you want to pre-install requirements, see [Adapter Requirements](#adapter-requirements).
### Method 3: `pip` (Alternative)

*(Note: To avoid dependency conflicts, installing in a virtual environment is recommended.)*

You can install `sqlit-tui` and drivers directly with `pip` using "extras". The application will guide you if a driver is missing.
If you installed Python via a system package manager (Homebrew, apt, pacman, etc.), `pip install` may be restricted; in that case, use `pipx`, `uv`, or a virtual environment.

```bash
# To install with PostgreSQL and MySQL support
pip install "sqlit-tui[postgres,mysql]"

# To add a driver to an existing installation
pip install "sqlit-tui[mariadb]"

# To install all drivers
pip install "sqlit-tui[all]"
```

## Usage

Expand Down Expand Up @@ -78,20 +123,29 @@ sqlit query -c "MyConnection" -q "SELECT * FROM Users" --format csv
sqlit query -c "MyConnection" -f "script.sql" --format json

# Create connections for different databases
sqlit connection create --name "MySqlServer" --db-type mssql --server "localhost" --auth-type sql
sqlit connection create --name "MyPostgres" --db-type postgresql --server "localhost" --username "user" --password "pass"
sqlit connection create --name "MyMySQL" --db-type mysql --server "localhost" --username "user" --password "pass"
sqlit connection create --name "MyCockroach" --db-type cockroachdb --server "localhost" --port "26257" --database "defaultdb" --username "root"
sqlit connection create --name "MyLocalDB" --db-type sqlite --file-path "/path/to/database.db"
sqlit connection create --name "MyTurso" --db-type turso --server "libsql://your-db.turso.io" --password "your-auth-token"
sqlit connections add mssql --name "MySqlServer" --server "localhost" --auth-type sql
sqlit connections add postgresql --name "MyPostgres" --server "localhost" --username "user" --password "pass"
sqlit connections add mysql --name "MyMySQL" --server "localhost" --username "user" --password "pass"
sqlit connections add cockroachdb --name "MyCockroach" --server "localhost" --port "26257" --database "defaultdb" --username "root"
sqlit connections add sqlite --name "MyLocalDB" --file-path "/path/to/database.db"
sqlit connections add turso --name "MyTurso" --server "libsql://your-db.turso.io" --password "your-auth-token"

# Connect via SSH tunnel
sqlit connection create --name "RemoteDB" --db-type postgresql --server "db-host" --username "dbuser" --password "dbpass" \
sqlit connections add postgresql --name "RemoteDB" --server "db-host" --username "dbuser" --password "dbpass" \
--ssh-enabled --ssh-host "ssh.example.com" --ssh-username "sshuser" --ssh-auth-type password --ssh-password "sshpass"

# Temporary (not saved) connection
sqlit connect sqlite --file-path "/path/to/database.db"

# Provider-specific CLI help
sqlit connect -h
sqlit connect supabase -h
sqlit connections add -h
sqlit connections add supabase -h

# Manage connections
sqlit connection list
sqlit connection delete "MyConnection"
sqlit connections list
sqlit connections delete "MyConnection"
```

## Keybindings
Expand All @@ -105,6 +159,7 @@ sqlit connection delete "MyConnection"
| `h` | Query history |
| `d` | Clear query |
| `n` | New query (clear all) |
| `y` | Copy query (when query editor is focused) |
| `v` / `y` / `Y` / `a` | View cell / Copy cell / Copy row / Copy all |
| `Ctrl+Q` | Quit |
| `?` | Help |
Expand Down Expand Up @@ -134,14 +189,16 @@ Connections and settings are stored in `~/.sqlit/`.

### How are sensitive credentials stored?

Credentials are stored in plain text in a protected directory (`~/.sqlit/`) with restricted file permissions (700/600).
Connection details are stored in `~/.sqlit/connections.json`, but passwords are stored in your OS keyring when available (macOS Keychain, Windows Credential Locker, Linux Secret Service).

If a keyring backend isn't available, `sqlit` will ask whether to store passwords as plaintext in `~/.sqlit/` (protected permissions). If you decline, you’ll be prompted when needed.

### How does sqlit compare to Harlequin, Lazysql, etc.?

sqlit is inspired by [lazygit](https://github.com/jesseduffield/lazygit) - you can just jump in and there's no need for external documentation. The keybindings are shown at the bottom of the screen and the UI is designed to be intuitive without memorizing shortcuts.

Key differences:
- **No need for external documentation** - Sqlit embrace the "lazy" approach in that a user should be able to jump in and use it right away intuitively. There should be no setup instructions. If python packages are required for certain adapters, sqlit will help you install them as you need them.
- **No need for external documentation** - Sqlit embrace the "lazy" approach in that a user should be able to jump in and use it right away intuitively. There should be no setup instructions. If python packages are required for certain adapters, sqlit will help you install them as you need them.
- **No CLI config required** - Just run `sqlit` and pick a connection from the UI
- **Lightweight** - While Lazysql or Harlequin offer more features, I experienced that for the vast majority of cases, all I needed was a simple and fast way to connect and run queries. Sqlit is focused on doing a limited amount of things really well.

Expand All @@ -155,24 +212,23 @@ sqlit is built with [Textual](https://github.com/Textualize/textual) and inspire

See `CONTRIBUTING.md` for development setup, testing, CI, and CockroachDB quickstart steps.

## Adapter Requirements
### Driver Reference

Each database provider requires specific Python packages. sqlit will prompt you to install these when needed, but you can also pre-install them:
Most of the time you can just run `sqlit` and connect. If a Python driver is missing, `sqlit` will show (and often run) the right install command for your environment.

| Database | Package | Install Command |
|----------|---------|-----------------|
| SQLite | *(built-in)* | No installation needed |
| SQL Server | `pyodbc` | `pip install pyodbc` |
| PostgreSQL | `psycopg2-binary` | `pip install psycopg2-binary` |
| MySQL | `mysql-connector-python` | `pip install mysql-connector-python` |
| MariaDB | `mariadb` | `pip install mariadb` |
| Oracle | `oracledb` | `pip install oracledb` |
| DuckDB | `duckdb` | `pip install duckdb` |
| CockroachDB | `psycopg2-binary` | `pip install psycopg2-binary` |
| Supabase | `psycopg2-binary` | `pip install psycopg2-binary` |
| Turso | `libsql-client` | `pip install libsql-client` |
| Database | Driver package | `pipx` | `pip` / venv |
| :--- | :--- | :--- | :--- |
| SQLite | *(built-in)* | *(built-in)* | *(built-in)* |
| PostgreSQL / CockroachDB / Supabase | `psycopg2-binary` | `pipx inject sqlit-tui psycopg2-binary` | `python -m pip install psycopg2-binary` |
| SQL Server | `pyodbc` | `pipx inject sqlit-tui pyodbc` | `python -m pip install pyodbc` |
| MySQL | `mysql-connector-python` | `pipx inject sqlit-tui mysql-connector-python` | `python -m pip install mysql-connector-python` |
| MariaDB | `mariadb` | `pipx inject sqlit-tui mariadb` | `python -m pip install mariadb` |
| Oracle | `oracledb` | `pipx inject sqlit-tui oracledb` | `python -m pip install oracledb` |
| DuckDB | `duckdb` | `pipx inject sqlit-tui duckdb` | `python -m pip install duckdb` |
| Turso | `libsql-client` | `pipx inject sqlit-tui libsql-client` | `python -m pip install libsql-client` |
| Cloudflare D1 | `requests` | `pipx inject sqlit-tui requests` | `python -m pip install requests` |

**Note:** SQL Server also requires the ODBC driver. On first connection attempt, sqlit will detect if it's missing and help you install it.
**Note:** SQL Server also requires the platform-specific ODBC driver. On your first connection attempt, `sqlit` can help you install it if it's missing.

## License

Expand Down
1 change: 1 addition & 0 deletions aur/PKGBUILD
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ depends=(
'python-pyperclip'
'python-sshtunnel'
'python-paramiko'
'python-keyring'
)
optdepends=(
'python-psycopg2: PostgreSQL and CockroachDB support'
Expand Down
Binary file removed demo-connect.gif
Binary file not shown.
Binary file removed demo-history.gif
Binary file not shown.
Binary file removed demo-providers.gif
Binary file not shown.
Binary file removed demo-query.gif
Binary file not shown.
Binary file removed demo-sqlite.gif
Binary file not shown.
Binary file added demos/demo-connect.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added demos/demo-history.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added demos/demo-providers.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added demos/demo-query.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added demos/demo-sqlite.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes.
18 changes: 18 additions & 0 deletions docker-compose.test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -156,3 +156,21 @@ services:
start_period: 10s
tmpfs:
- /var/lib/postgresql/data

miniflare:
build:
context: ./tests/fixtures/d1
container_name: sqlit-test-miniflare
command: ["wrangler", "dev", "--local", "--ip", "0.0.0.0", "--port", "8787"]
ports:
- "8787:8787"
volumes:
- ./tests/fixtures/d1/wrangler.toml:/app/wrangler.toml
- ./tests/fixtures/d1/index.js:/app/index.js
working_dir: /app
healthcheck:
test: ["CMD", "node", "-e", "fetch('http://localhost:8787/').then(r=>{if(!r.ok)process.exit(1)}).catch(()=>process.exit(1))"]
interval: 5s
timeout: 5s
retries: 10
start_period: 10s
Loading
Loading