google/grain: a declarative data pipeline for JAX training loops
Library for reading and processing ML training data.
At a glance
- What is it?
- Grain reads and processes training data for JAX models through chainable MapDataset and IterDataset transformations. It is a small, opinionated API surface, and the README leaves several operational questions open.
- Who is it for?
- Adopt Grain if you are building a JAX training loop and want the input pipeline expressed as a chain of transformations rather than as a bespoke iterator class, and if your training hosts run Linux on x86_64 or aarch64. Do not adopt it if you need GPU-side preprocessing, if you train on a Mac with an Intel chip, or if you require an API stability guarantee that the 0.2.x version line does not offer.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository received new commits within the last day.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The gap Grain fills between a file on disk and a JAX training step
A JAX training step consumes arrays. Getting from a directory of records to those arrays is not something JAX itself handles, and the result is usually a hand-written Python generator with shuffling, batching and prefetching logic folded into it. Grain replaces that generator with a declarative chain. The README's opening example builds a pipeline from a Python list: a MapDataset.source call, then shuffle with a seed, then map, then batch. Each method returns a new dataset object, and iterating over the final object yields batches. The intended audience is anyone training or evaluating JAX models who wants the input path to be readable and reproducible rather than buried in loop control flow. The README is explicit that JAX is not a hard dependency, so the library can feed other frameworks, but the naming, the documentation and the listed users all point at JAX as the primary target.
MapDataset, IterDataset and the determinism claim
The README names two dataset abstractions, MapDataset and IterDataset, and the quickstart links to a tutorial titled Basic Dataset. MapDataset is the one demonstrated: it supports random access in principle, which is what allows shuffle to permute elements globally rather than within a fixed-size buffer. That distinction matters. A buffer-based shuffle, the kind common in streaming loaders, only ever mixes elements that happen to be near each other in the source order, so the randomness depends on how the source is ordered. A global shuffle does not have that dependency. The seed argument makes the permutation reproducible, which is the source of the determinism claim in the description. IterDataset is the streaming counterpart, and the README does not show it in the excerpt, so anything beyond its existence is unconfirmed here. The architecture implied by the example is a chain of transformations evaluated lazily when iteration begins, with the shuffle stage needing to materialise or index the full source to permute it.
Installing Grain and the platform table you should read first
Installation is a single command: pip install grain, from PyPI. The README publishes a platform support table, and it is worth reading before anything else. Linux is supported on both x86_64 and aarch64. macOS is supported on aarch64 only, so Apple Silicon works and Intel Macs do not. Windows is supported on x86_64, with aarch64 marked not applicable. The README also states plainly that Grain does not directly use GPU or TPU in its transformations and that processing within Grain is done on the CPU by default. That is a design statement, not a bug report. It means the transformations run on the host processor while the accelerator waits, so the throughput question for any deployment is whether CPU preprocessing can keep pace with the training step. Beyond the install command and the dataset chain, the excerpt does not show configuration keys or environment variables, so there is nothing further to document on that front.
Where the CPU-only design becomes the wrong tool
The CPU default is the sharpest limitation in the supplied material. If your preprocessing includes image decode, augmentation, or tokenisation heavy enough to saturate a core, and your accelerator step is short, the input pipeline becomes the bottleneck and no amount of pipeline restructuring inside Grain changes that, because Grain's transformations are not running on the accelerator. A second constraint is the platform table: an Intel Mac is simply not a supported target, which rules out local development on that hardware without a container or a different machine. A third is version maturity. The recent releases are v0.2.16, v0.2.17 and v0.2.18, all on a 0.2 line, and the citation block in the README pins version 0.2.12 while the release list shows 0.2.18. That gap between the cited version and the current one tells you the API is still moving and that a pinned citation can lag the code. For a project that will be maintained across a multi-year training run, an unstable interface is a real cost.
Grain against a PyTorch-style loader
The obvious comparison is torch.utils.data, the DataLoader and Dataset pair that most PyTorch users already know. The difference is where the pipeline lives. In the PyTorch model, you subclass Dataset to implement __getitem__ and __len__, then hand that object to a DataLoader configured with batch_size, shuffle, num_workers and a sampler, and the shuffling and batching behaviour is a property of the loader rather than of the dataset. In Grain, those steps are methods on the dataset object itself, so the pipeline is a single expression that reads top to bottom and the seed travels with the shuffle call. Grain's approach makes the transformation order explicit in the code, which is easier to audit when you are trying to reproduce a training run. The PyTorch approach has the advantage of a much larger ecosystem of existing Dataset implementations and of multi-process loading through num_workers, which the Grain excerpt does not describe. Neither is strictly better; they put the configuration in different places.
Who is already running it, and what that does and does not tell you
The README lists MaxText, Gemma, kauldron, maxdiffusion and unnamed internal Google projects as existing users. That list is useful for one purpose: it shows the library is exercised in large-scale JAX training code, not only in examples. It is not evidence about API stability, performance, or how well Grain will fit your particular data format, and the README offers nothing on any of those points. The citation block names eleven authors, which suggests a project with real ongoing investment rather than a single-maintainer experiment. The last push date on the repository is 2026-09-10, and the most recent release in the list is v0.2.18 from 2026-06-17, so the project is active on both the commit and release axes. What the material does not contain is any statement about backward-compatibility policy, deprecation windows, or a target date for a 1.0.
Licence, maintenance and what to check before you depend on it
Grain is Apache-2.0, which permits commercial and internal use and includes an explicit patent grant. That is the standard permissive choice for a Google-originated library and it carries no copyleft obligation on your own code. This is a description of the licence terms, not legal advice; if your organisation has a policy on third-party dependencies, run it through that process. On maintenance cost, the practical risks are the 0.2.x version line and the CPU-only transformation model. Upgrading within 0.2.x means reading the changelog before each bump, since the cited version in the README already trails the published releases. The thing to verify first is the shape of your own pipeline: confirm that the transformations you need map onto the MapDataset chain shown in the README, and confirm that your preprocessing fits on the CPU beside the accelerator, because that is where Grain will run it.
Editorial conclusion
Adopt Grain if you are building a JAX training loop and want the input pipeline expressed as a chain of transformations rather than as a bespoke iterator class, and if your training hosts run Linux on x86_64 or aarch64. Do not adopt it if you need GPU-side preprocessing, if you train on a Mac with an Intel chip, or if you require an API stability guarantee that the 0.2.x version line does not offer. Before committing, verify two things against your own workload: that the transformation chain you need can be expressed without dropping into IterDataset, and that the CPU cost of your preprocessing fits alongside your accelerator work, since the README states that processing within Grain runs on the CPU by default.
Community notes