Open Sourcing babylon-table

By Gary Kennedy
July 8, 2026

Babylon has open sourced babylon-table, a dependency-free Java library for ingesting and reshaping tabular data. Published under the Apache 2.0 license and available on Maven Central, the module grew out of Babylon’s practical financial data work. Its most distinctive feature is a small domain specific language (DSL) for describing table transformations in a business-readable form.

In the previous article AI-Powered Refactoring: Modularising Code with Codex 5.4, we described how Codex helped us restructure the Babylon codebase into a set of smaller, clearer modules.

One of those modules was babylon-table.

At first, it was simply an internal library. It existed because we needed a practical way to ingest, reshape, clean, and transform tabular data inside our financial application. Over time, it became clear that the module was useful enough, and self-contained enough, to stand on its own.

We have now open sourced babylon-table under the Apache 2.0 license. The module includes dependency-free table structures, immutable columns, byte-level CSV parsing, streaming CSV import, and a small DSL for reshaping data.

This post explains why the module exists, what problems it is trying to solve, and why its design is slightly different from many general-purpose data libraries.

Why another table library?

There are already many excellent libraries for working with tabular data.

But our use case is quite specific.

We are not primarily using tables for classic machine learning workflows. We are not usually building large numeric matrices where every column is a double. In our financial application, a column of BigDecimal values is far more common than a column of primitive doubles.

We are usually dealing with data such as:

  • broker transaction records
  • contract notes
  • CSV exports
  • reference data
  • account statements
  • tax-related records
  • intermediate data extracted from PDFs or emails

The problem is not statistical modelling. The problem is ingestion, normalisation, reconciliation, and transformation.

We need to take data from different sources, often with different shapes, naming conventions, formats, currencies, identifiers, and levels of quality, and turn it into something the application can use reliably.

That is the space babylon-table is designed for.

No third-party dependencies

One of the clearest design goals was that babylon-table should have no third-party runtime dependencies.

This matters for a few reasons.

First, it keeps the module easy to use. Adding it to a project should not bring in a large dependency tree, introduce version conflicts, or force unrelated architectural decisions.

Second, it makes the library easier to reason about. A small dependency-free module has fewer hidden behaviours and fewer moving parts.

Third, it makes the module more suitable for long-lived financial software. Financial records often need to remain reproducible and understandable for many years. Reducing dependency churn is part of that discipline.

The goal is not to reject dependencies as a general principle. Dependencies are often useful and necessary. But for this particular module, the core problem is small enough that keeping it dependency-free feels like the right trade-off.

Immutable columns

Another important design choice is that columns are immutable.

A table transformation should not quietly mutate the original data. Instead, operations produce new columns or new tables.

That makes transformation pipelines easier to understand. It also reduces the risk of accidental side effects, especially when the same source data is used in more than one stage of processing.

This is particularly important in financial applications. When a value changes, we want that change to be deliberate and visible. If a source column is parsed, renamed, filtered, mapped, or combined with another column, those steps should be explicit.

Immutable columns also make it easier to test transformations. A test can start with known input, apply a transformation, and compare the result without worrying that an earlier reference has been modified behind the scenes.

Parsing bytes before strings

CSV ingestion is one of the main use cases for the module.

A common approach is to read text into strings early, split it into fields, and then parse those strings into typed values. That works, but it can create unnecessary allocations and premature conversions.

Where possible, babylon-table applies the CSV state machine directly to bytes and delays conversion to strings until it is actually needed.

This is partly about efficiency, but it is also about correctness and control.

CSV parsing has rules. Quoted fields, escaped quotes, delimiters, line endings, and empty fields all need to be handled carefully. Treating CSV as “just split on commas” is not good enough.

By applying the parser at the byte level, the module can identify the structure of the data before turning every field into a Java String. The aim is to do the minimum necessary work at each stage, and only convert values once the structure is known.

For small files, this may not matter much. For repeated ingestion, server-side processing, and financial workflows where reliability matters, it is a useful discipline.

Streaming CSV import

babylon-table also includes a streaming API for CSV import.

This was not driven by our main financial application use case. In practice, the files we ingest are usually modest in size: broker reports, statements, contract notes, reference files, and other operational data. We have not needed to stream enormous CSV files in production.

We learnt about The One Billion Row Challenge, so we thought we would try it “for the craic”. Very quickly, that forced us to add a streaming API.

That experiment was useful.

It forced us to think more carefully about where allocation happens, when bytes become strings, how rows should be exposed, and which parts of the design assumed that all data had already been materialised.

Even though the streaming API is not central to our financial use case, the exercise improved the overall design. It made the boundaries clearer between parsing, row handling, column construction, and full table materialisation.

Sometimes a stress test is valuable even when the stress case is not the business case.

A small DSL for reshaping data

The fourth major motivation is the DSL.

In many applications, transforming tabular data quickly becomes repetitive. Rename this column. Drop that column. Parse this value. Add a derived value. Reorder the output. Convert this field to a BigDecimal. Combine two fields. Filter some rows.

All of this can be done in Java code, but writing custom code for every input format becomes tedious and hard to maintain.

babylon-table includes a small domain-specific language for describing table transformations.

The idea is not to create a general programming language. The idea is simplicity: to describe common table reshaping operations compactly, consistently, and in a form that remains accessible to business users.

That matters because many data ingestion problems are not really code problems. They are mapping problems.

A source file has one shape. The application needs another shape. The DSL gives us a way to describe that transformation without writing a new Java class each time.

This is especially useful when dealing with external data sources. Broker exports, platform reports, and statement formats can vary. A small declarative transformation layer makes it easier to adapt those formats into a stable internal model.

Not a machine learning table

It is worth being explicit about what babylon-table is not.

It is not trying to be a dataframe library for machine learning. It is not optimised around dense numeric arrays. It is not designed around the assumption that the most important column type is double.

Our use case is different.

In financial software, values often need to preserve exact decimal semantics. A monetary amount should not casually become a binary floating-point value. A security identifier is not just a string; it may be an ISIN, SEDOL, ticker, internal ID, or broker-specific description. Dates, currencies, quantities, prices, fees, and tax fields all carry meaning.

For that reason, ColumnObject<BigDecimal> is much more representative of our use case than a primitive double column.

The library is designed around practical data transformation, not statistical computation.

Built for ingestion and transformation

The broader purpose of babylon-table is to help get external data into a reliable internal form.

That includes reading data, preserving structure, applying transformations, and producing output that can be consumed by the rest of the application.

In a financial system, the difficult part is often not storing data once it is clean. The difficult part is getting from messy external records to clean internal records in a way that is repeatable, testable, and explainable.

That is where babylon-table fits.

It gives us a small foundation for working with tabular data before that data becomes part of the application’s permanent record.

Why open source it?

The idea of a columnar representation of data is not new. It is well understood, widely used, and not something we regard as proprietary. There is little reason for this kind of module to remain private if it can be made publicly available and reusable.

We also use open-source libraries ourselves. We understand the benefit of well-built, well-maintained public libraries, so it feels reasonable to contribute something back to the community.

babylon-table is a small contribution, but it is a useful one. The module is self-contained, dependency-free, and focused on a common problem: transforming tabular data safely and predictably.

Open sourcing also improves the discipline of the design. A private module can rely on informal knowledge, hidden assumptions, and the convenience of changing APIs whenever the surrounding application changes. A public library has to be more careful. Its purpose needs to be clear, its API needs to be deliberate, and its behaviour needs to be documented and stable.

The same is true of testing. When a library is public, the test suite is public as well. Code coverage is no longer just an internal metric; it becomes part of the visible quality of the project. That creates useful pressure to keep behaviour well tested, especially around parsing, edge cases, and transformation logic.

That discipline tends to improve quality. Even if the main user of the library remains our own application, treating the module as a public API forces better decisions about naming, boundaries, compatibility, documentation, and tests.

The source code is available on GitHub at github.com/gary-babylon-app/babylon-table, and the core library is published on Maven Central as app.babylon:babylon-table.

A small piece of a larger system

babylon-table is not the whole Babylon platform. It is a small building block.

But small building blocks matter.

Financial applications depend on data quality. Data quality depends on ingestion. Ingestion depends on reliable parsing and transformation. If that layer is vague, ad hoc, or hidden inside application code, errors become harder to find and harder to explain.

By separating this logic into its own module, we make the system easier to reason about.

That was the original motivation for modularising the codebase. Open sourcing babylon-table is a continuation of the same idea.

Clear boundaries. Small modules.