Pure-Java reader/writer for the Vortex columnar file format.
100% Java, no JNI, no sun.misc.Unsafe. Uses the FFM API (MemorySegment/Arena, Java 25+)
for zero-copy memory-mapped reads — good performance out of the box, without native dependencies.
Checked against the Rust reference in both directions (Rust writes, Java reads and vice versa), and against 172 real-world Raincloud datasets, each matching its Parquet copy value for value.
- JVM analytics engines and OLAP systems
- Anyone who wants mmap-backed, zero-copy columnar reads without native-library management
- Anyone who wants to query
.vortexfiles with SQL from IntelliJ, DBeaver or another JDBC tool - Small footprint. The Rust reference's JNI bindings (
vortex-jni) are a 75 MB jar (native binaries for four platforms) that pulls in Arrow, Netty, Guava and RoaringBitmap. vortex-java's reader is ~800 KB of plain Java (vortex-reader+vortex-core+vortex-fsst) with no other required dependencies, and runs on any platform with a JDK. CI builds the full reactor on Linux + macOS + Windows × JDK 25 + 27.
<dependency>
<groupId>io.github.dfa1.vortex</groupId>
<artifactId>vortex-reader</artifactId>
<version>0.18.0</version>
</dependency>try (VortexReader vf = VortexReader.open(Path.of("data/example.vortex"));
var iter = vf.scan(ScanOptions.all())) {
while (iter.hasNext()) {
try (Chunk chunk = iter.next()) {
LongArray ts = chunk.column(ColumnName.of("timestamp"));
for (long i = 0; i < ts.length(); i++) {
System.out.println(ts.getLong(i));
}
}
}
}Lifecycle.
ScanIteratorimplementsIterator<Chunk>andChunkimplementsAutoCloseable. Each chunk owns a confinedArena; closing it releases the decoded buffers. Callingiter.next()while a prior chunk is still open throwsIllegalStateException. Use try-with-resources, oriter.forEachRemaining(c -> ...)which closes each chunk for you. See docs/explanation.md#memory-model.
<dependency>
<groupId>io.github.dfa1.vortex</groupId>
<artifactId>vortex-writer</artifactId>
<version>0.18.0</version>
</dependency>DType.Struct schema = DType.structBuilder()
.field(ColumnName.of("timestamp"), DType.I64)
.field(ColumnName.of("symbol"), DType.UTF8)
.field(ColumnName.of("price"), DType.F64)
.field(ColumnName.of("volume"), DType.I64.asNullable()) // boxed Long[] → nullable
.build();
try (var ch = FileChannel.open(Path.of("data/example.vortex"),
StandardOpenOption.CREATE, StandardOpenOption.WRITE);
var writer = VortexWriter.create(ch, schema, WriteOptions.cascading(3))) {
writer.writeChunk(c -> c
.put(ColumnName.of("timestamp"), new long[] {1_700_000_000_000L, 1_700_000_001_000L})
.put(ColumnName.of("symbol"), new String[] {"AAPL", "AAPL"})
.put(ColumnName.of("price"), new double[] {189.95, 190.10})
.put(ColumnName.of("volume"), new Long[] {100L, null})); // null in nullable col
}Each
.putis validated at the call site: unknown column names, mismatched array types, and boxed arrays for non-nullable columns throwIllegalArgumentExceptionimmediately. Missing columns surface asIllegalStateExceptionwhen the lambda returns.
vortex-jdbc-driver is a read-only JDBC driver in one self-contained jar, so SQL tools can browse and
query .vortex files with no code. Download vortex-jdbc-driver-0.18.0-all.jar from
Maven Central, add
it as a driver with class io.github.dfa1.vortex.jdbc.driver.VortexDriver, and connect to a directory:
jdbc:vortex:/data/vortex
Every *.vortex file in it is a table of schema vtx, named after the file:
select symbol, count(*), max(high) from vtx.ohlc group by symbol order by 2 desc;The tool must run on JDK 25 or later. Setup steps for IntelliJ and DBeaver, URL options and troubleshooting are in the how-to.
For more examples — projection, filtering, custom encodings, and the CLI — see the tutorial.
Docs follow the Diátaxis framework.
| Document | Mode | Contents |
|---|---|---|
| docs/tutorial.md | Tutorial | Step-by-step: write and read your first Vortex file |
| docs/how-to.md | How-to | Recipes: count rows, convert Parquet, filter, project, custom encodings |
| docs/reference.md | Reference | API surface, CLI subcommands, operator tables, file-format trailer |
| docs/compatibility.md | Reference | Encoding support table, S3 fixture status |
| docs/explanation.md | Explanation | Design rationale, memory model, benchmarks |
| docs/testing.md | Explanation | Test strategy: layers, counts per module, what each layer verifies |
Requirements: Java 25+. Build: ./mvnw verify.
Forks welcome. See CONTRIBUTING.md for full build reference, coding conventions, and how to add a new encoding.
This project uses Claude Code for implementation work. Architecture, API design, and all decisions are human-driven.
- vortex.dev — the Vortex project's website
- Vortex: A Columnar File Format for GPU Streaming — InfoQ presentation
- Vortex: One Format for Any Shape — SpiralDB blog post
- BtrBlocks: The Compressor Behind Vortex — the cascading, cost-based encoding selection this project's own cascading compressor is modeled on
- A Tour of the Vortex Columnar Format with vortex-java — walkthrough of the format on a real dataset
| Project | Language | Notes |
|---|---|---|
| vortex-data/vortex | Rust | Reference implementation + JNI bindings |
| LaurieRhodes/vortex-go | Go | Pure-language port |
| Evariops/Vorticity | C# | Pure .NET, dependency-free |
YourKit supports open source projects with innovative and intelligent tools for monitoring and profiling Java and .NET applications. YourKit is the creator of YourKit Java Profiler, YourKit .NET Profiler, and YourKit YouMonitor.
