Skip to main content

deltalite

Streaming, partition-level upsert for Delta Lake tables that replaces delta-rs's SQL MERGE with a bounded-memory merge engine. Memory is bounded by the size of the incoming batch and a few concurrency knobs — never by the size of the target table.

delta-rs stays the storage and protocol layer (transaction log, checkpoints, Parquet encoding, S3 conditional-put commits, conflict resolution). deltalite replaces only the merge execution, and writes output files through a streaming writer that produces the same files and Add-action statistics as delta-rs's RecordBatchWriter without holding a second copy of each file.

import deltalite

table = deltalite.DeltaLiteTable.open("s3://bucket/my_table")
stats = table.upsert(record_batch, primary_keys=["id"], partition_key="day")
print(f"v{stats.version}: +{stats.rows_inserted} / ~{stats.rows_updated}")

Why

delta-rs MERGE executes a DataFusion hash join whose memory scales with the scanned target, and it can deadlock under a bounded memory pool (delta-io/delta-rs#4614). For a large, slowly-changing table merged against a comparatively small batch — the typical incremental-sync shape — that means either OOM risk or a hang.

deltalite takes a different route:

  1. Build a primary-key hash set over the (small) source batch.
  2. Stream the (large) target one Parquet row group at a time, dropping rows whose key is in the source set.
  3. Write survivors plus the source rows into new files.
  4. Commit every touched partition in one atomic Delta commit.

Peak memory is bounded by the source batch and the concurrency knobs, not by the table. In validation, resident memory stayed flat from 62k- to 1M-row partitions (~4× below MERGE) at matching write volume, via exact content-based file selection.

Installation

pip install deltalite
# or
uv add deltalite

Prebuilt cp312-abi3 wheels are published for manylinux (2_28) and musllinux on x86_64/aarch64, and macOS on arm64/x86_64. A single wheel works on any CPython 3.12 or newer. No Rust toolchain is needed to install.

Usage

upsert accepts anything with the pyarrow C-stream interface — a pyarrow.Table, a RecordBatch, or a RecordBatchReader:

import pyarrow as pa
import deltalite

table = deltalite.DeltaLiteTable.open(
    "s3://bucket/events",
    storage_options={
        "AWS_REGION": "us-east-1",
        "AWS_ACCESS_KEY_ID": "...",
        "AWS_SECRET_ACCESS_KEY": "...",
    },
)

batch = pa.table({
    "id":  [1, 2, 3],
    "day": ["2026-01-01", "2026-01-01", "2026-01-02"],
    "val": ["a", "b", "c"],
})

stats = table.upsert(
    batch,
    primary_keys=["id"],
    partition_key="day",          # omit for an unpartitioned table
    commit_metadata={"source": "my-sync"},
)

print(stats)
# UpsertStats(version=42, partitions_touched=2, files_added=2, files_removed=1, ...)

Rows in the batch whose primary key already exists are replaced; new keys are inserted. Deletes are not expressed through upsert — it is an insert-or-replace by key. Duplicate primary keys within a single batch are rejected (raising DeltaLiteError) rather than silently double-inserted.

API

DeltaLiteTable

Method Description
DeltaLiteTable.open(uri, storage_options=None) Open an existing Delta table. storage_options is the usual object-store dict (S3/GCS/Azure/local).
DeltaLiteTable.is_deltatable(uri, storage_options=None) True if a Delta table exists at uri.
.upsert(data, primary_keys, partition_key=None, **opts) Insert-or-replace data by key. Returns UpsertStats. See knobs below.
.compact(**opts) Small-file compaction, the replacement for DeltaTable.optimize.compact. Returns a stats dict. See "Compaction" below.
.version() Current table version (int).
.reload() Bring the table state up to date with the log (incremental; falls back to a full re-open).
.table_id() The table id from the metadata action (str).
.configuration() Table configuration, delta.* properties and custom keys (dict[str, str]).
.schema_arrow() Table schema as a pyarrow Schema.
.schema_json() Table schema as the Delta JSON document (str), as DeltaTable.schema().to_json() returns it.
.partition_columns() Partition column names (list[str]).
.num_files() Number of active data files (int).
.files() Active data files as dicts: path (relative to the table root), size, modification_time (epoch ms), partition_values (dict[str, str | None]).
.file_uris() URIs of the table's active data files.
.history(limit) Recent commit history entries.

version, table_id, configuration, schema_*, partition_columns, num_files, files and file_uris read the loaded snapshot in memory and do no I/O; call reload() first when the table may have moved. history reads the log.

UpsertStats

Returned by upsert. Counts: version, partitions_touched, files_added, files_removed, files_carried_over, files_probed, rows_updated, rows_inserted, rows_copied, source_rows, null_pk_rows. Per-phase wall-clock timings (milliseconds): ingest_ms (importing the pyarrow source), initial_open_ms (the full snapshot load in DeltaLiteTable.open, reported on the first upsert through a handle and 0 afterwards, so a sum over a handle's upserts counts it once), open_ms (snapshot refreshes around the upsert), relax_ms (nullability-relax check), plan_ms (listing + pruning files), rewrite_ms (reading + rewriting the touched partitions), commit_ms (committing to the Delta log), maintenance_ms (checkpoint/log cleanup, non-zero only on checkpoint-boundary commits). columns_relaxed counts non-nullable columns flipped to nullable before the write.

Compaction

compact plans bins exactly as delta-rs's optimize.compact does, from the loaded log with no storage reads, and commits them the same way (ZSTD level 4, one OPTIMIZE commit, dataChange=false). Each bin is streamed one file and one byte-bounded batch at a time through the upsert's fetch and decode budgets, so memory follows the knobs, not the bin. Output files and row groups are also capped by decoded size, so a bin that decodes past a cap writes more than one file where delta-rs writes one.

Knob Default Meaning
target_file_size table's delta.targetFileSize Bin size and output file size (compressed bytes).
max_parallel_bins 2 Bins rewritten at once.
slot_budget_bytes none Memory for the whole call: caps the decode and fetch budgets at a quarter each and lowers max_parallel_bins so the output files fit the rest.
max_decoded_file_bytes 1 GiB An output file closes when its decoded bytes reach this (keeps files under the 2 GiB Arrow offset limit).
max_row_group_decoded_bytes 128 MiB An output row group closes at this many decoded bytes.
partitions all Only these partition values.
min_partition_removable_files 1 Rewrite a partition only when its bins remove at least this many more files than they write. 1 is delta-rs's behavior.
max_bins_per_commit one commit Commit every N bins instead.
max_replan_rounds 1 Times the partitions of bins dropped on a conflict are planned and rewritten again.
commit_max_retries 15 Commit attempts after another writer committed first.
dry_run False Plan only; report what would be rewritten.

Conflicts: when another writer commits first, compaction keeps each bin whose input files are all still live and drops the others (deleting their output), so it never resurrects rows a merge replaced. A concurrent schema, partitioning or protocol change raises DeltaLiteCommitConflictError. Tables the upsert refuses are refused here too (DeltaLiteUnsupportedTableError). The result dict carries deltalite's counters plus delta-rs's numFilesAdded, numFilesRemoved, partitionsOptimized, numBatches, totalConsideredFiles and totalFilesSkipped.

Exceptions

All inherit from DeltaLiteError, so you can catch the base or branch on kind:

Exception Raised when
DeltaLiteError Base class / generic failure.
DeltaLiteCommitConflictError Concurrent commit won the conditional-put race (retry-exhausted).
DeltaLiteSchemaMismatchError Batch schema is incompatible with the table.
DeltaLiteTableNotFoundError No Delta table at the URI.
DeltaLiteUnsupportedTableError Table uses a feature deltalite can't handle (e.g. deletion vectors, column mapping).
DeltaLiteSourceTooLargeError Batch exceeds max_source_bytes (see below).

Operational knobs

Per-call — keyword arguments to upsert (defaults in parentheses):

Argument Default Purpose
max_parallel_partitions 2 Partitions merged concurrently.
max_parallel_files 4 Files read concurrently within a partition.
max_buffered_bytes 64 MiB Decoded rows in flight between the file readers and the writer.
max_fetch_bytes 128 MiB Compressed row-group bytes the file readers hold before decoding. A reader reserves its file's largest row group before fetching; a row group larger than the cap still runs, alone.
prune_strategy "probe" "probe" skips files that can't contain a source key; "none" scans all.
skip_unmatched_files True Convenience toggle: False ≡ prune_strategy="none".
probe_concurrency 8 Concurrent statistics/probe reads.
read_batch_size 8192 Row-group read batch size.
target_file_size table setting, else 100 MiB Output file size target.
max_source_bytes 2 GiB Oversized-batch guard (0 disables).
multipart_threshold / multipart_part_size 64 MiB / 16 MiB Multipart upload thresholds (0 threshold disables).
commit_max_retries 15 Conditional-put commit retry budget.
commit_metadata None Extra key/values recorded in the Delta commit.

Process-global — environment variables, enforced on top of the per-call knobs so that many concurrent upsert threads in one process cannot multiply the budgets:

DELTALITE_PROCESS_MAX_PARALLEL_PARTITIONS (8), DELTALITE_PROCESS_MAX_PARALLEL_FILES (16), DELTALITE_PROCESS_MAX_BUFFERED_BYTES (256 MiB), DELTALITE_PROCESS_MAX_FETCH_BYTES (256 MiB), DELTALITE_MAX_SOURCE_BYTES, DELTALITE_MULTIPART_THRESHOLD_BYTES, DELTALITE_MULTIPART_PART_SIZE_BYTES.

Checkpoint prefetch. Opening or reloading a table reads its latest checkpoint Parquet file whole in one GET and serves the Parquet reader's many small range reads from memory, instead of one round trip per footer, metadata block and column chunk. DELTALITE_CHECKPOINT_PREFETCH_MAX_BYTES (128 MiB) bounds the total checkpoint bytes cached by one table load; larger files or multipart checkpoints that exhaust the budget fall back to range reads, and 0 disables the prefetch. Cached bytes also reserve space from DELTALITE_PROCESS_MAX_BUFFERED_BYTES, so concurrent table opens share the process-wide budget. The bytes are released as soon as the load finishes.

Commit snapshot adoption. After a successful upsert the handle keeps the table state delta-rs derived for the commit it just wrote (the same state every delta-rs operation returns) instead of listing the log and reading that commit back. The next upsert still refreshes before it plans, so commits from other writers are observed exactly as before, and a checkpoint the upsert's own maintenance wrote is adopted on that refresh. DELTALITE_ADOPT_COMMIT_SNAPSHOT=0 restores the post-commit refresh.

Data-file reads. Every Parquet data file is opened with a 64 KiB footer size hint, so a footer that fits arrives in one GET instead of two, and a file the probe found a match in hands its parsed footer to the rewrite, so the file is not opened a second time.

Metrics

deltalite emits via the Rust metrics facade (static labels only): deltalite_upserts_total (outcome, prune_strategy, error_kind), deltalite_upsert_duration_seconds, deltalite_files_{added,removed,carried_over,probed}_total, deltalite_rows_{updated,inserted,copied}_total, and deltalite_checkpoint_prefetch_total (outcome).

Compatibility & status

  • Built against deltalake (delta-rs) 0.32.x as the storage/protocol layer. Correctness is guaranteed by a differential parity suite that runs the same batch sequences through real delta-rs MERGE and through deltalite.upsert and asserts identical logical content — not by version equality.
  • Not supported: tables with deletion vectors or column mapping (detected and raised as DeltaLiteUnsupportedTableError), and SCD2 merges.
  • deltalite rejects duplicate source primary keys that MERGE silently double-inserts — check pre-existing data if you migrate an existing pipeline.

This package is developed in the PostHog monorepo under rust/deltalite/. Issues and source live there.

Metadata

Release files for deltalite 0.1.10

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for deltalite 0.1.10
File Size Uploaded
deltalite-0.1.10.tar.gz 274.8 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for deltalite 0.1.10
File
deltalite-0.1.10-cp312-abi3-musllinux_1_2_x86_64.whl CPython 3.12 abi3 Linux musl 1.2+ x86-64 Details
deltalite-0.1.10-cp312-abi3-musllinux_1_2_aarch64.whl CPython 3.12 abi3 Linux musl 1.2+ ARM64 Details
deltalite-0.1.10-cp312-abi3-manylinux_2_28_x86_64.whl CPython 3.12 abi3 Linux glibc 2.28+ x86-64 Details
deltalite-0.1.10-cp312-abi3-manylinux_2_28_aarch64.whl CPython 3.12 abi3 Linux glibc 2.28+ ARM64 Details
deltalite-0.1.10-cp312-abi3-macosx_11_0_arm64.whl CPython 3.12 abi3 macOS 11.0+ ARM64 Details
deltalite-0.1.10-cp312-abi3-macosx_10_12_x86_64.whl CPython 3.12 abi3 macOS 10.12+ x86-64 Details

Total release size: 298.1 MB

Release files / deltalite-0.1.10.tar.gz

Download URL deltalite-0.1.10.tar.gz
Size 274.8 kB
Tags Source
SHA-256 checksum
How to use checksums
8d950a88a308a4046d7b1b588df4e686345b2057a16eecbece67075bd8404295
BLAKE2b-256 checksum
How to use checksums
dd7a7357bbecc633d84249821601f6fc539712d75d0cb0bd169ead6106ea6f43
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 5, 2026.

Transparency log

Release files / deltalite-0.1.10-cp312-abi3-musllinux_1_2_x86_64.whl

Download URL deltalite-0.1.10-cp312-abi3-musllinux_1_2_x86_64.whl
Size 65.5 MB
Tags CPython 3.12 Linux musl 1.2+ x86-64 abi3
SHA-256 checksum
How to use checksums
3544f35e30e9fa4eac5f47b0528312d0e1894a4638eaf622551d45f70737f434
BLAKE2b-256 checksum
How to use checksums
3d97fb1fbbcb8cec378dab5cc76ff059d28b8075b38c8b68642752e66174b967
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 5, 2026.

Transparency log

Release files / deltalite-0.1.10-cp312-abi3-musllinux_1_2_aarch64.whl

Download URL deltalite-0.1.10-cp312-abi3-musllinux_1_2_aarch64.whl
Size 64.5 MB
Tags CPython 3.12 Linux musl 1.2+ ARM64 abi3
SHA-256 checksum
How to use checksums
59f0a2d80673bd5ccddc61de67c4ffb4ef40d08a85c35161560f0690fa57a1b3
BLAKE2b-256 checksum
How to use checksums
c95874b2f64751f9d2bc9a2513134edebf0894ae7b7e9677bad235961e80a39b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 5, 2026.

Transparency log

Release files / deltalite-0.1.10-cp312-abi3-manylinux_2_28_x86_64.whl

Download URL deltalite-0.1.10-cp312-abi3-manylinux_2_28_x86_64.whl
Size 67.2 MB
Tags CPython 3.12 Linux glibc 2.28+ x86-64 abi3
SHA-256 checksum
How to use checksums
b68a86c2a7e9f0c4ebdacd17043753062b90cf87a0b0c019c9da6f8cba4b3ade
BLAKE2b-256 checksum
How to use checksums
6a74216d8603431be70d37094d3dfeca5ef4a2727d195e759061178d338dc0ff
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 5, 2026.

Transparency log

Release files / deltalite-0.1.10-cp312-abi3-manylinux_2_28_aarch64.whl

Download URL deltalite-0.1.10-cp312-abi3-manylinux_2_28_aarch64.whl
Size 64.3 MB
Tags CPython 3.12 Linux glibc 2.28+ ARM64 abi3
SHA-256 checksum
How to use checksums
2ddd0956229413a41f15ad6f411777f031d91a394b9d23f5fdc7b7b41f94d179
BLAKE2b-256 checksum
How to use checksums
17aa5fee721b265ca13f98fee403ab67603980ffb063e1e73e7de0fe16937b65
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 5, 2026.

Transparency log

Release files / deltalite-0.1.10-cp312-abi3-macosx_11_0_arm64.whl

Download URL deltalite-0.1.10-cp312-abi3-macosx_11_0_arm64.whl
Size 17.9 MB
Tags CPython 3.12 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
492f3df6c3d1fba68dd24f853f2a6238ad251e6e3b82ae597a029832a9b0155d
BLAKE2b-256 checksum
How to use checksums
04ccdc25222c7fe0dbbaefdb5af1ace83f68c6997a52510726a156e929530dca
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 5, 2026.

Transparency log

Release files / deltalite-0.1.10-cp312-abi3-macosx_10_12_x86_64.whl

Download URL deltalite-0.1.10-cp312-abi3-macosx_10_12_x86_64.whl
Size 18.4 MB
Tags CPython 3.12 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
35c6e9c35eb480b49e9ea02d41fdd94eeef4c8c21f7079b6031518f29f5757ab
BLAKE2b-256 checksum
How to use checksums
0fa1983adbc7d0b85d3cee19a07c5ee5c41ae7971e5ed077cbe8924b78cdcf66
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 5, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.10 This release

7 release files

0.1.9

7 release files

0.1.8

7 release files

0.1.7

7 release files

0.1.6

7 release files

0.1.5

7 release files

0.1.4

7 release files

0.1.3

7 release files

0.1.2

7 release files

0.1.1

7 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page