ArrayRecord Source Quick Reference

September 11, 2026 ยท View on GitHub

MetadataValue
LevelIntermediate
Runtime~15 min
PrerequisitesSimple Pipeline
FormatPython + Jupyter

Overview

Learn to use ArrayRecordSourceModule for loading data from Google's ArrayRecord format. ArrayRecord is a high-performance file format used by Google for ML datasets, similar to TFRecord but with better random access.

Learning Goals

By the end of this quick reference, you will be able to:

  1. Configure ArrayRecordSourceConfig for ArrayRecord files
  2. Create an ArrayRecordSourceModule from file paths
  3. Integrate ArrayRecord sources into Datarax pipelines
  4. Understand checkpointing and state management

Coming from Google Grain?

GrainDatarax
grain.ArrayRecordDataSource(paths)ArrayRecordSourceModule(config, paths)
grain.DataLoader(source)Pipeline(source=source, stages=[], batch_size=32, rngs=nnx.Rngs(0))
Manual iterationAutomatic stateful iteration
Manual checkpointingBuilt-in get_state() / set_state()

Key Differences:

  1. Stateful Iteration: Datarax tracks position automatically via NNX Variables
  2. Checkpointing: Built-in state serialization for resume
  3. Pipeline Integration: Direct integration with DAG-based pipelines
  4. Shuffling: Internal shuffle handling per epoch

Files

Quick Start

Installation

ArrayRecord requires the array_record package:

uv pip install "datarax[data]" array-record

!!! note "Platform Support" ArrayRecord is primarily available on Linux. Check compatibility for your platform.

Run the Python Script

python examples/integration/arrayrecord/01_arrayrecord_quickref.py

Key Concepts

ArrayRecordSourceConfig

Configuration for ArrayRecord data sources:

ParameterTypeDefaultDescription
seedint42Random seed for shuffling
num_epochsint-1Epoch budget for direct source iteration (-1 for unbounded)
shuffle_filesboolFalseShuffle record order within each epoch
from datarax.sources import ArrayRecordSourceConfig

config = ArrayRecordSourceConfig(
    seed=42,
    num_epochs=10,       # Run for 10 epochs
    shuffle_files=True,  # Reshuffle record order each epoch
)

Creating an ArrayRecord Source

import numpy as np
from datarax.sources import ArrayRecordSourceModule, ArrayRecordSourceConfig
from flax import nnx


def decode(record: bytes) -> dict[str, np.ndarray]:
    # ArrayRecord records are bytes; turn one into a dict of arrays.
    return {"data": np.frombuffer(record, dtype=np.float32)}


# Single file
source = ArrayRecordSourceModule(
    ArrayRecordSourceConfig(seed=42),
    paths="/path/to/data.riegeli",
    decode=decode,
    rngs=nnx.Rngs(0),
)

# Multiple files with glob pattern
source = ArrayRecordSourceModule(
    ArrayRecordSourceConfig(seed=42, shuffle_files=True),
    paths="/path/to/data-*.riegeli",
    decode=decode,
    rngs=nnx.Rngs(0),
)

# List of specific files
source = ArrayRecordSourceModule(
    ArrayRecordSourceConfig(num_epochs=10),
    paths=[
        "/path/to/train-00000.riegeli",
        "/path/to/train-00001.riegeli",
    ],
    decode=decode,
    rngs=nnx.Rngs(0),
)

Pipeline Integration

from datarax.pipeline import Pipeline

# Create pipeline from ArrayRecord source; each pass covers one epoch
pipeline = Pipeline(source=source, stages=[], batch_size=32, rngs=nnx.Rngs(0))

# Add transformations
# Pipeline stages are set at construction; rebuild with normalize_op in stages.
pipeline = Pipeline(
    source=pipeline.source,
    stages=[normalize_op],
    batch_size=pipeline.batch_size,
    rngs=nnx.Rngs(0),
)

# Iterate
for batch in pipeline:
    # Process batch
    print(f"Batch shape: {batch['data'].shape}")

Checkpointing

ArrayRecordSourceModule supports full state serialization:

# Save checkpoint
state = source.get_state()
# state = {"current_index": 1234, "current_epoch": 5, ...}

# Later: restore from checkpoint
source.set_state(state)
# Resumes from exact position

State Contents:

State KeyDescription
current_indexCurrent position in dataset
current_epochCurrent epoch number
shuffled_indicesShuffle order (if enabled)
prefetch_cachePrefetched records cache

Epoch Control

Finite Epochs:

Reuse a single pipeline across epochs. Each iter(pipeline) session covers one pass over the source, so re-entering the for batch in pipeline loop starts a new epoch.

# Run for exactly 10 epochs
config = ArrayRecordSourceConfig(num_epochs=10)
source = ArrayRecordSourceModule(config, paths=paths, decode=decode, rngs=nnx.Rngs(0))

pipeline = Pipeline(source=source, stages=[], batch_size=32, rngs=nnx.Rngs(0))
for epoch in range(10):
    for batch in pipeline:
        train_step(batch)
# Each iter(pipeline) session covers one pass over the source.

Step-Based Training:

Re-enter the pipeline per epoch until a step budget is reached.

# Run until a step budget is reached, re-entering the pipeline per epoch
pipeline = Pipeline(source=source, stages=[], batch_size=32, rngs=nnx.Rngs(0))

step = 0
while step < max_steps:
    for batch in pipeline:
        train_step(batch)
        step += 1
        if step >= max_steps:
            break

Setting num_epochs=-1 makes the source iterate unboundedly when consumed directly (iterating the source itself, not the pipeline).

Shuffling Behavior

When shuffle_files=True:

  1. At initialization, indices are shuffled using seed
  2. At each epoch boundary, indices are reshuffled using seed + epoch
  3. This ensures reproducible but varied order across epochs
config = ArrayRecordSourceConfig(
    seed=42,
    shuffle_files=True,
)
# Epoch 0: shuffled with seed=42
# Epoch 1: reshuffled with seed=43
# Epoch 2: reshuffled with seed=44

Results

Running the quick reference produces:

============================================================
ArrayRecord Source Quick Reference
============================================================

This quick reference demonstrates the ArrayRecordSourceModule API.
Actual usage requires ArrayRecord files (*.riegeli format).

Key API Summary:

  1. Configuration:
     config = ArrayRecordSourceConfig(
         seed=42,
         num_epochs=-1,
         shuffle_files=True,
     )

  2. Source Creation:
     source = ArrayRecordSourceModule(
         config,
         paths="/path/to/*.riegeli",
         decode=decode,
         rngs=nnx.Rngs(0),
     )

  3. Pipeline Integration:
     pipeline = Pipeline(source=source, stages=[], batch_size=32, rngs=nnx.Rngs(0))

  4. Checkpointing:
     state = source.get_state()
     source.set_state(state)

============================================================
Quick reference completed!
============================================================

Feature Summary

FeatureDescription
StatefulTracks position via NNX Variables
CheckpointingFull get_state() / set_state()
ShufflingPer-epoch reshuffling with seed control
Epoch ControlPer-session passes; loop iter(pipeline) for epochs
Decodingdecode turns each bytes record into arrays for batches
Grain CompatibleWraps Grain's ArrayRecordDataSource

When to Use ArrayRecord

  • Large datasets (>10GB)
  • Need random access to records
  • Working with Google's ML infrastructure
  • Migrating from TFRecord to a modern format

Next Steps

API Reference