Aix enables efficient storage and querying of large chess game collections. Read more on my blog post and the documentation.
Get started by:
- Installing the
aixchessextension for DuckDB:INSTALL aixchess FROM community; LOAD aixchess;. - Download one of the Aix-compatible Lichess database files or convert your own PGN file using pgn-to-aix.
With the aixchess extension loaded, you can execute SQL queries over a chess game collection. For example, this query generates a heatmap of king move destinations:
with king_destinations as (
select
move_details(movedata)
.list_filter(lambda m: m.role = 'k')
.apply(lambda m: m.to)
as destinations
from 'aix_lichess_2025-12_low.parquet'
),
unnested as (
select unnest(destinations) as destination from king_destinations
),
aggregated as (
select destination, count() from unnested group by 1 order by 2 desc
)
from aggregated;Which results in:
┌─────────────┬──────────────┐
│ destination │ count_star() │
│ varchar │ int64 │
├─────────────┼──────────────┤
│ g1 │ 74020594 │
│ g8 │ 71579360 │
│ g7 │ 23388424 │
...
To directly decode an Aix-encoded game with Rust, use the aix-chess-compression crate.
Make sure that CMake, Ninja, ccache, and Cargo are installed. Build the extension using:
GEN=ninja make
A DuckDB binary with the extension loaded is then available in ./build/release/duckdb. Running unit tests is possible with make test.