One command to run queries against a variety of SQL engines.
runsql duckdb "select 1 as x"
runsql trino "select 1 as x"
runsql tsql "select @@version"
runsql redshift "select current_user"
# No query: open the REPL
runsql duckdbIt currently supports 20 engines:
| Kind | Dialects |
|---|---|
| Docker | clickhouse drill hive materialize mysql oracle postgres presto risingwave spark starrocks trino tsql |
| Native | duckdb sqlite |
| Cloud | athena bigquery databricks redshift snowflake |
- Docker engines need a daemon and
./containers.sh duckdbandsqliteare single binaries that stay native so they start instantly and can read files in your working directory- Cloud engines need the vendor CLI plus credentials
Setup for each is below.
Requires zsh for runsql itself.
Some engines shell out to helpers to format results: athena, databricks, drill and redshift need python3; athena, databricks and drill also need column; drill needs curl. On macOS curl and column ship with the base system, and python3 comes with the Xcode Command Line Tools (xcode-select --install).
mkdir -p ~/.zsh && cp sql.zsh ~/.zsh/sql.zsh
echo 'source ~/.zsh/sql.zsh' >> ~/.zshrc
exec zshDialects are independent, so install the pieces below only for the engines you want. Sourcing defines exactly one name, runsql, so nothing on your PATH gets shadowed.
Install any docker daemon, such as Docker Desktop.
Then create the containers:
./containers.shThat pulls the engine images and creates thirteen containers (~35GB for all of them). It's safe to re-run; existing containers are left alone. runsql runs docker start <name> before each query, so containers you've stopped come back automatically.
The postgres image also provides the psql client used for materialize, risingwave and redshift, so those need nothing installed either.
Two engines need a note on Apple Silicon: drill is amd64-only and mssql has no arm64 build, so both run emulated.
Local engines keep running once started. To hand the memory back:
docker stop clickhouse drill hive materialize mssql mysql oracle postgres presto risingwave spark starrocks trinoA query issued immediately after a cold start can fail with a connection error while the engine is still booting.
Only two, both single binaries — they stay native because container startup would dominate their runtime, and because a container can't see files in your working directory:
brew install duckdb # sqlite3 already ships with macOSNothing is hardcoded: each cloud engine reads its settings from RUNSQL_* variables, and an unset one fails by name instead of guessing. Export them from your shell profile. Each engine re-triggers its own login when the session expires, so you authenticate once and forget about it.
| Variable | Used by | Default |
|---|---|---|
RUNSQL_AWS_PROFILE |
athena, redshift | required |
RUNSQL_AWS_SSO_SESSION |
athena, redshift | required |
RUNSQL_AWS_REGION |
athena, redshift | us-east-1 |
RUNSQL_AWS_ACCOUNT_ID |
redshift | required |
RUNSQL_ATHENA_OUTPUT |
athena | required |
RUNSQL_ATHENA_WORKGROUP |
athena | primary |
RUNSQL_REDSHIFT_WORKGROUP |
redshift | required |
RUNSQL_REDSHIFT_DATABASE |
redshift | dev |
RUNSQL_DBX_HOST |
databricks | required |
RUNSQL_DBX_WAREHOUSE_ID |
databricks | required |
RUNSQL_DBX_PROFILE |
databricks | required |
RUNSQL_MSSQL_PASSWORD |
tsql | 1StrongPwd@@ |
brew install awscli
export RUNSQL_AWS_PROFILE=my-profile
export RUNSQL_AWS_SSO_SESSION=my-sso-session
export RUNSQL_AWS_ACCOUNT_ID=123456789012
export RUNSQL_ATHENA_OUTPUT="s3://my-bucket/me/athena-results/"
export RUNSQL_REDSHIFT_WORKGROUP=my-workgroupThe profile and SSO session must exist in your ~/.aws/config:
[sso-session my-sso-session]
sso_start_url = https://<your-org>.awsapps.com/start
sso_region = us-east-1
[profile my-profile]
sso_session = my-sso-session
sso_account_id = 123456789012
sso_role_name = <role>
region = us-east-1Redshift needs no client installed, as psql comes from the postgres image, so docker is required for it too. runsql redshift "<query>" runs one query; runsql redshift opens a psql REPL.
brew tap databricks/tap && brew install databricks
export RUNSQL_DBX_HOST=https://<workspace>.cloud.databricks.com
export RUNSQL_DBX_WAREHOUSE_ID=<warehouse-id>
export RUNSQL_DBX_PROFILE=<profile>
databricks auth login --host "$RUNSQL_DBX_HOST" --profile "$RUNSQL_DBX_PROFILE"brew install snowflake-cli
snow connection add # writes ~/.snowflake/config.tomlrunsql just calls snow sql -q, so it uses whatever connection the CLI is configured with: a config file, environment variables, or a wrapper of your own. If you keep credentials in a secret manager, wrap the call so the settings are only in the environment of that one command, e.g., <your-secret-tool> -- runsql snowflake "select 1".
Install the SDK from the official instructions, or unpack the tarball directly (swap darwin-arm for darwin-x86_64 or linux-x86_64 as needed):
curl -sL https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-cli-darwin-arm.tar.gz | tar xz -C ~/.local/opt
~/.local/opt/google-cloud-sdk/install.sh # puts gcloud and bq on your PATH
gcloud auth loginbq ships inside the SDK, so there's nothing else to install. runsql bigquery wraps bq query, so it takes bq flags, e.g., runsql bigquery --nouse_legacy_sql "select 1".
Call a dialect with no query to get its REPL instead:
runsql trino
runsql duckdb
runsql redshiftAvailable for every engine that has one. The cloud batch APIs (athena, bigquery, databricks, snowflake) don't, and say so.