Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Getting started

Download the binary for Linux x86-64 from the latest release, or build it from source with Zig 0.15.2 (see the README):

$ curl -fsSL -o basalt https://github.com/leonardomb1/basalt/releases/latest/download/basalt-x86_64-linux
$ chmod +x basalt

A first query

Save this as orders.csv:

id,region,amount,placed_at
1,north,120.50,2026-03-01
2,south,80.00,2026-03-01
3,north,42.25,2026-03-02
4,east,310.00,2026-03-02
5,south,15.75,2026-03-03

A SELECT on its own prints its rows. -c runs a script given on the command line:

$ basalt run -c "SELECT * FROM 'orders.csv' LIMIT 3;"
id  region  amount  placed_at
--  ------  ------  ----------
1   north   120.5   2026-03-01
2   south   80      2026-03-01
3   north   42.25   2026-03-02
(3 rows)

The file’s extension picks the reader, and the column types are read from the data: amount is a number and placed_at a date. Queries are SQL:

$ basalt run -c "SELECT region, COUNT(*) AS orders, SUM(amount) AS revenue
                 FROM 'orders.csv' GROUP BY region ORDER BY revenue DESC;"
region  orders  revenue
------  ------  -------
east    1       310
north   2       162.75
south   2       95.75
(3 rows)

A first load

A script in a file can take parameters and write its result instead of printing it. Save this as daily.sql:

PARAM since DATE DEFAULT '2026-03-02';

LOAD INTO 'daily.parquet' AS
SELECT placed_at AS day, region, SUM(amount) AS revenue
FROM 'orders.csv'
WHERE placed_at >= $since
GROUP BY placed_at, region
ORDER BY day, region;

check validates a script without running it — every name, type and parameter — and run executes it. -p binds a parameter:

$ basalt check daily.sql
ok: daily.sql checks out
$ basalt run daily.sql
Read 5 rows, loaded 3 into daily.parquet in 86ms (58 rows/s, 12 lanes)
$ basalt run daily.sql -p since=2026-03-01
Loaded 5 rows into daily.parquet in 90ms (55 rows/s, 12 lanes)

A mistake is reported where it is, before anything runs:

$ basalt check -c "SELECT regoin FROM 'orders.csv';"
<command>:1:8: error: unknown field `regoin`

Seeing the plan

EXPLAIN prints how a query will run without running it:

$ basalt run -c "EXPLAIN SELECT region, SUM(amount) AS revenue FROM 'orders.csv'
                 WHERE amount > 50 GROUP BY region;"
plan
  write  stdout  (default)
    aggregate  1 agg(s), 1 group(s)
      schema: region:string?  revenue:float?
      filter
        schema: id:int?  region:string?  amount:float?  placed_at:date?
        scan  csv  orders.csv
          schema: id:int?  region:string?  amount:float?  placed_at:date?
  physical: morsel-parallel candidate (per-lane partials, combined)

Next

  • Scripts describes what a script may hold.
  • Connections reaches databases, APIs and file servers.
  • Sources and LOAD INTO list what can be read and written.
  • REPL is the interactive way to explore data.