ExArrow v0.8.0 Release Notes
Date: 2026-08-21
Highlights
ExArrow v0.8.0 makes Parquet a first-class citizen for larger-than-memory
workloads. Read pushdown, write compression options, footer metadata, and
multi-file directory streams let you scan only the data you need — peak memory
scales with the selected row groups, not the whole file.
- Read pushdown:
:columns(projection),:row_groups(selection), and
:filters(a predicate AST with row-group statistics pruning). - Write options:
:compression,:row_group_size,:dictionary. ExArrow.Parquet.Metadata: footer-only metadata without decoding rows
(path, compression, encodings, min/max, key-value metadata).- Multi-file streams:
from_parquet_files/2,from_parquet_dir/2, plus
Stream.close/1when abandoning early. ExArrow.IPC.File.write/3andExArrow.RecordBatch.concat/1.
Added
ExArrow.Stream.from_parquet/2andParquet.Reader.from_file/2/
from_binary/2accept:columns,:row_groups, and:filters. Supported
filter ops::eq,:ne,:gt,:gte,:lt,:lteover integers, floats,
UTF-8 strings, and booleans, composable via{:and, [...]}/{:or, [...]}.
Row-group min/max statistics prune whole groups (Int32/Int64, Float32/Float64,
Utf8, Boolean);:neis never pruned from min/max alone. Remaining rows are
filtered during decode via parquet-rsRowFilter. Statistics pruning resolves
columns against Parquet leaf indices (safe for nested Struct/List schemas).- Filter values are validated in Elixir and range-checked in the NIF before use
(e.g. out-of-range Int32 / non-representable Float32 return{:error, _}
instead of silent wrap/truncation). Parquet.Reader.read_stats/1reports%{row_groups_total, row_groups_selected, row_groups_skipped}for a Parquet-backed stream.- Parquet write options on
Writer.to_file/4andto_binary/3:
:compression(:none/ alias:uncompressed,:snappy,:zstd,
{:zstd, level}with level1..22,:lz4,:gzip),:row_group_size
(positive integer),:dictionary(boolean). ExArrow.Parquet.Metadatawithfrom_file/1andfrom_binary/1— returns
row groups, per-column statistics (path, compression, encodings, num_values,
min, max), and key-value metadata.ExArrow.Stream.from_parquet_files/2andfrom_parquet_dir/2— lazy
per-file open in lexicographic order with schema field-name checking. Early
Enum.take/2does not open later files. Paths must be binaries (no silent
to_string/1coercion). Repeatnext/1after EOF returnsnil.ExArrow.Stream.close/1— stops the backing Agent for:parquet_multi
streams (no-op for other backends). Use after partial consumption in
long-lived processes.ExArrow.IPC.File.write/3— public IPC file-format writer.ExArrow.RecordBatch.concat/1— public batch concatenation.ExArrow.Parquet.Opts(internal) — validates read/write options in Elixir
before reaching the NIF, returning clear{:error, message}tuples.livebook/05_parquet.livemd— Parquet pushdown, compressed write, multi-file
directory, and IPC file writer, with a PyArrow side-by-side cell (Pythonx
shares Elixir path bindings asbytes; decode beforepq.read_table).bench/parquet_pushdown_bench.exs— pushdown filter vs full read + project
(no public scalar-predicate kernel yet for an equivalent post-filter).- DuckDB-generated
test/fixtures/parquet_zstd.parquetand nested-struct
pruning fixture for third-party / nested-schema regression coverage
(thanks @mindreframer —
#243). - Optional
arrow_testingIPC conformance suite
(script/fetch_arrow_testing.sh+mix test --include arrow_testing) —
local/opt-in by default; optionalworkflow_dispatchCI job does not gate
PRs. - CI: Mix.install optional-dep smoke (
script/mix_install_smoke.sh), Livebook
Hex-pin check (script/check_livebooks.sh), andlivebook/00_quickstart.exs
smoke on the test matrix.
Changed
- Native crate enabled Parquet compression codecs (
snap,zstd,lz4,
gzip/flate2-zlib-rs) and addedarrow-arithso write options and
filter evaluation work end-to-end. Parquet.Reader.from_file/1/from_binary/1are now arity-2 with an
optional keyword list (from_file(path, opts \\ [])). Calls without options
continue to work via the default.Parquet.Writer.to_file/3/to_binary/2are now arity-4 / arity-3 with an
optional keyword list (to_file(path, schema, batches, opts \\ [])).Stream.from_parquet/1/from_parquet_binary/1are now arity-2 with
optionalopts; the[:ex_arrow, :parquet, :read]telemetry event now
includes:opts,:row_groups_skipped, and:row_groups_selected.
Multi-file batch telemetry uses the currently open path (not the full list).mix.exs: version bumped to0.8.0;ExArrow.Parquet.Metadataadded to
theParquetmodule group.- README, Parquet guide, overview, CHANGELOG, and livebooks updated to
~> 0.8.0.
Upgrade notes
-
Recommended dependency:
{:ex_arrow, "~> 0.8"}
-
The Parquet reader/writer arities changed by adding an optional
opts
keyword list at the end. Existing calls without options continue to work
unchanged (default argument). -
ExArrow.Streamgained a:parquet_multibackend for multi-file streams.
Theresourcefield may now hold anAgentpid for that backend; code that
pattern-matched onresourcebeing a plain reference should use the public
StreamAPI instead. CallStream.close/1when abandoning a multi-file
stream early from a long-lived process. -
:uncompressedis accepted as an alias for:noneon write compression.
Zstd levels must be in1..22.
Verification performed
mix compile --warnings-as-errors,mix format --check-formatted,
mix credo --strict,mix sobelow --exit --skip,script/check_version,
script/check_livebooks.sh,mix dialyzer,mix test,
mix docs --warnings-as-errors, and CI matrix (Elixir 1.18–1.20 / OTP 27–29,
Mix.install smoke, ADBC integration) — green on merge of
#244.
Full Changelog: v0.7.2...v0.8.0