Editor’s note: This Bytewax review is based on my hands-on test of Bytewax 0.21.1 on a 10-core Apple Silicon Mac in late October 2026, using a Python 3.12 virtual environment. I weighed installation, the dataflow API, recovery, scaling, connectors, cost, and project health.
In this bytewax review, I’ll take a closer look at Bytewax’s pricing, features and project health, so you can see exactly whether it is safe to build on in 2026.
Bytewax is a free Apache-2.0 Python dataflow library on a Rust engine built on timely dataflow. It combines stateful operators with event-time windows and SQLite-backed recovery, without PyFlink’s JVM requirement.
Quick verdict: I recommend Bytewax for Python teams that want Flink-style stateful streaming without a JVM and can own maintenance. The company wound down in May 2025; two volunteer maintainers remain, the latest PyPI release is 0.21.1 from 2024-11-25, and the hosted docs domain no longer resolves.
Key Takeaways:
- Free Apache-2.0 library: My Python 3.12 installation needed only two dependencies; state and recovery require no paid tier.
- Recovery worked in my test: A crash at row 150,000 resumed to correct totals with 0 duplicates.
- Processes beat threads: Heavy Python work fell from 5.55 s to 2.84 s across four processes.
- No Python 3.13/3.14 PyPI wheels: Installation falls back to compiling Rust.
- No commercial support: Maintenance is volunteer-based, with docs now in the GitHub repository.
Pros and Cons
Pros
- Free Apache-2.0 library with two pip dependencies in my Python 3.12 installation.
- Eight windowing operators cover tumbling, sliding, and session windows with separate late-data output.
- SQLite recovery resumed my crashed payments job with 0 duplicates in FileSink output.
- Four processes reduced my heavy-work run from 5.55 s to 2.84 s using -i/-a.
- Built-in Kafka connectors include Avro and Schema Registry serialization support.
Cons
- No PyPI release since November 2024.
- No Python 3.13/3.14 wheels; source installation requires a Rust toolchain.
- bytewax.io and docs.bytewax.io no longer resolve.
- Two volunteer maintainers, with no paid support contract.
- Redis, DuckDB, and ClickHouse add-ons were last released in 2024, separate from the core package.
Bytewax Pricing: How Much Does It Cost?
Bytewax costs $0 under Apache-2.0, with packages on PyPI and conda-forge. There is no paid plan, managed Bytewax cloud, or commercial support contract in 2026.
- Bytewax open source (free): for engineers running their own infrastructure. The library includes stateful operators, SQLite recovery, the Kafka connector, and multi-process execution without a license upgrade.
- Bytewax Platform (discontinued): formerly offered Community, Startup, and Enterprise tiers as customized solutions without public prices. Its management API and dashboard belonged to the commercial offering, not a current subscription.
The discontinued Platform’s operational features included:
- Monitoring: Tracing and alerting around deployed dataflows.
- Access controls: OpenID Connect and role-based access control.
- Backup: Cloud backup for operational recovery.
- Premium connectors: Integrations beyond the free library’s core connector set.
I exclude those former Platform capabilities from a new Bytewax deployment budget. The free library does not replace a managed service such as RisingWave Cloud; you own the runtime and recovery storage.
What You Pay for With Bytewax vs Rivals
| Tool | License | Paid option | Starting price |
|---|---|---|---|
| Bytewax | Apache-2.0 | None | $0 |
| Quix Streams | Apache-2.0 | Hosted service: Quix Cloud | $0 for the self-hosted library |
| Pathway | BSL 1.1 | Scale/Enterprise | Free Community tier: 8 GB RAM and 4 cores; paid tiers quote-only |
| RisingWave | Apache-2.0 | RisingWave Cloud | From about $0.227 per RWU-hour |
| Apache Flink | Apache-2.0 | Managed services from cloud vendors | $0 self-hosted |
Is Bytewax Good Value for Money?
- No license-based core cap: Unlike Pathway’s free Community tier, Bytewax does not limit you to four cores. I favor its permissive license when infrastructure ownership is already part of the job.
- Infrastructure is your expense: Budget for VMs or Kubernetes and persistent recovery storage. The Helm repository was last pushed on 2024-05-24, so I include deployment-tool maintenance in that budget.
- Engineering replaces subscription spending: Interpreter support on main and open Kafka correctness fixes extend beyond the released package. Budget for version pinning and patch review; installing 0.21.1 does not deliver every current change.
- No vendor SLA: Volunteer maintenance offers no contractual response time. I recommend Quix Streams or RisingWave over Bytewax when commercial incident escalation is a purchasing requirement; each has a company behind it.
Reviewer’s Notes: I recommend pinning
bytewax==0.21.1on Python 3.12 for an initial production evaluation. If Python 3.13+ is mandatory, main requires a Rust-toolchain build and separate validation. Budget engineering time instead of a Bytewax subscription; the community-maintained conda-forge package does not add commercial support.
My Experience With Bytewax
Installing Bytewax
I ran the test on a 10-core Apple Silicon Mac running macOS 26, whose system Python was 3.14.
My first pip install bytewax on Python 3.14 failed. PyPI’s 0.21.1 wheels stop at CPython 3.12, so pip attempted a source build and stopped with: “Cargo, the Rust package manager, is not installed or is not on PATH. This package requires Rust and Cargo to compile extensions.”
On a Python 3.12 virtual environment, pip install bytewax==0.21.1 installed in seconds. Its two dependencies were prometheus_client and typing_extensions.
The wheel shipped only four built-in connector modules: files, stdio, kafka, and demo. The files module included FileSource, FileSink, DirSource, and CSVSource; no other connector modules shipped in the core package.
Running My First Dataflow
I ran the README quickstart: TestingSource supplied numbers 1 through 5, a filter kept even numbers, and a map multiplied them by 10. Unlike PyFlink, Bytewax needs no JVM for this Python dataflow.
from bytewax.dataflow import Dataflow
from bytewax.testing import TestingSource
import bytewax.operators as op
flow = Dataflow("quickstart")
nums = op.input("input", flow, TestingSource(range(1, 6)))
evens = op.filter("filter", nums, lambda x: x % 2 == 0)
tens = op.map("map", evens, lambda x: x * 10)
op.inspect("print_results", tens)
Running python -m bytewax.run quick:flow printed quickstart.print_results: 20 and 40; wall time was 0.135 s. The output prefixed the step id with the flow name, producing quickstart.print_results.
Windowing a Clickstream by Event Time
I used 9 synthetic click events for alice/bob with EventClock, a 1-minute TumblingWindower aligned to 12:00 UTC, and a SessionWindower gap of 45 s. I imported EventClock, TumblingWindower and SessionWindower from the windowing module in Bytewax 0.21.1.
My first attempt passed an already-keyed stream to count_window, which keys the stream itself. The run died with a Rust panic plus a Python traceback naming "win.count.sum.window.stateful_batch" and the key "alice". Passing the un-keyed stream fixed it.
With wait_for_system_duration=0, alice window 0 counted 3. An out-of-order event at 12:00:30, arriving after the 12:02:10 event, went to the separate late stream instead of disappearing. Alice’s sessions were [5,20,50,70] then [130].
With wait_for_system_duration=2 min, that event landed in window 0, raising the count to 4. The first session changed to [5,20,30,50,70]; the waiting allowance changed both the window count and session membership.
Crashing and Resuming a Stateful Job
Recovery initialization required an existing directory. Running python -m bytewax.recovery db 1 failed before I created db; FileSink then rejected my bare strings with a separate routing error:
recovery directory "db" does not exist; please create it with `mkdir`
step "rec.out" requires (key, value) 2-tuple from upstream for routing; got a str instead
After I created the directory, initialization created one partition, part-0.sqlite3. Emitting ("totals.csv", line) fixed FileSink routing by supplying the required key-value tuple.
My recovery flow processed a 300,000-row payments CSV, using stateful_map for running totals across 5 users and a snapshot interval of 1 s with -r db -s 1 -b 0. The first run raised a simulated crash at row 150,000, after 150,000 output lines.
I reran the same command, resumed from SQLite, and finished in 2.6 s. The result contained 300,000 output rows, 300,000 unique row ids, and 0 duplicates. Every user’s final total and count matched plain-Python ground truth, including user1 at 3,032,751 over 60,088 rows.
FileSink truncated back to the snapshot offset. Bytewax recovery remains at-least-once by design, with duplicates possible around resumption for sinks without resume logic.
Scaling Past One Core
For 1M items with light per-item work and stateful counts over 100 keys, adding threads made my run slower:
| Execution | Wall time |
|---|---|
-w 1 |
2.61 s |
-w 2 |
2.84 s |
-w 4 |
3.57 s |
| Plain Python loop | 1.74 s |
I also ran that light workload through separate processes using -i/-a on localhost. One process took 2.75 s, two took 2.27 s, and four took 2.85 s.
For 300k items with heavy per-item work, a sum of squares over range(500), separate processes performed better:
| Execution | Wall time |
|---|---|
| 1 process | 5.55 s |
| 2 processes | 3.12 s |
| 4 processes | 2.84 s |
-w 4 in one process |
5.79 s |
Processes printed "error connecting to worker N: Connection refused; retrying" while peers started, then proceeded.
Reviewer’s Notes: I recommend processes through
-i/-a, not additional-wthreads, for Python-heavy steps. Workers within one process share the GIL. My single-partition TestingSource also limited input parallelism; production scaling needs a partitioned source, such as Kafka partitions.
Operators, Windowing and State
Bytewax’s Python dataflow API is its strongest feature: source-agnostic operators support transformations and keyed state without requiring Kafka. Quix Streams is Kafka-only, making Bytewax the more flexible fit when file inputs and custom sources belong in the same application.
- Stateless transformations:
map,filter,flat_map, andfilter_maptransform records;branch,merge, andredistributecontrol routing. - Keyed and stateful processing:
key_on,stateful_map,stateful_flat_map, andstateful_batchsupport per-key logic.joincombines streams, whileenrich_cachedsupports cached enrichment. - Final aggregations:
count_final,fold_final,reduce_final,max_final, andmin_finalsupport end-of-input results. I recommend windowed equivalents when an unbounded stream needs recurring output.
For the payments flow, stateful_map kept running totals per user rather than requiring a separate database update for each input. Recovery snapshots preserve that per-key state in SQLite partitions, alongside progress needed for resumption.
The windowing module includes eight operators:
windowprovides the base windowing operation.collect_window,count_window, andfold_windowcollect or aggregate records.join_windowcombines streams within windows.reduce_window,max_window, andmin_windowprovide reduction and extrema.
| Windowing choice | Behavior | My recommendation |
|---|---|---|
| TumblingWindower | Fixed, nonoverlapping time windows | Periodic totals |
| SlidingWindower | Overlapping time windows | Rolling measurements |
| SessionWindower | Groups activity by inactivity gap | Sessions or bursts |
| EventClock | Uses event timestamps and lateness allowance | Delayed event streams |
| SystemClock | Uses system time | Processing-time windows |
EventClock advances its watermark from the largest timestamp seen minus the waiting allowance. All timestamps and watermarks use UTC. Late records have a separate output stream, which let my clickstream test distinguish rejected late arrivals from accepted events.
Open limitations affect more specialized pipelines:
- Non-time windows: Issue #284 has requested them since 2023-08-18.
- Huge iterable expansion: Issue #543 concerns
stateful_flat_maphandling very large iterables. - Graceful abort: Issue #318 remains open for aborting on exceptions without panicking.
For inspection, python -m bytewax.visualize rec:flow printed a Mermaid flowchart of my dataflow. The testing module also exposes run_main and cluster_main for pytest-style tests. I favor this local development model over PyFlink when Python callbacks and inspectable per-key logic matter more than cluster-level operations.
Connectors, Recovery and Deployment
Bytewax’s built-in connector set is narrow compared with Flink’s. I recommend budgeting custom integration work for a pipeline spanning several databases or cloud services.
- Kafka:
KafkaSourceandKafkaSink, with Avro and Schema Registry serialization support. - Files:
FileSource,DirSource,CSVSource,FileSink, andDirSink. - Local development:
StdOutSink,RandomMetricSource, andTestingSource/TestingSink. - Custom integrations: Input and output base classes for implementing your own connectors.
Separate add-ons remain on 2024 releases:
| Package | Latest version | Release |
|---|---|---|
| bytewax-redis | 0.1 | 2024-10-02 |
| bytewax-duckdb | 0.1.22 | 2024-11-19 |
| bytewax-clickhouse | 0.0.1 | 2024-08-08 |
| bytewax-azure-ai-search | 0.1.2 | 2024-09-12 |
PR #538 proposes folding 12 add-ons into core, but remains open. I treat those packages as code requiring compatibility work, not a maintained connector catalog.
Recovery uses a fixed partition count at initialization. Set it to the maximum worker count you expect to use; changing that count later requires manual SQLite work. Resume with the same recovery directory; the new run can use a different worker count.
Recovery requires both -s and -b, alongside -r for the directory. My payments test used -s 1 -b 0.
Recovery is at-least-once, with duplicates possible around resumption for sinks without resume logic. My FileSink run had 0 duplicates because it truncated to the snapshot offset, not because every sink inherits duplicate-free delivery.
Pending correctness work includes:
- KafkaSink #593: Messages dropped when Kafka has not accepted them.
- KafkaSource #606: Data skipped when retention removes the saved resume offset.
- Recovery #631: Recovery-store garbage collection with sub-millisecond epochs.
These PRs are open and unreleased; their proposed fixes are not protections supplied by 0.21.1 or main.
Deployment uses python -m bytewax.run, with -w for worker threads or -i/-a for separate processes. Each run flag has a BYTEWAX_* environment-variable counterpart.
The waxctl deployment CLI is unmaintained, and the Helm repository was last pushed on 2024-05-24. Issue #546 records a waxctl null-pointer failure. I prefer Flink’s exactly-once checkpointing and broader connector ecosystem when recovery requirements outweigh Bytewax’s smaller Python setup.
Project Health: Who Maintains Bytewax in 2026?
Bytewax has two listed volunteer maintainers, but its latest PyPI release remains 0.21.1 from November 2024. I consider that release gap a bigger adoption risk than the local API problems I encountered.
- 2025-05-22: Founder Zander Matheson stated that the company was not commercially viable and the original core team would no longer maintain the open-source project.
- 2025-10-15: Issue #560, “State of the project?”, opened. It received no maintainer response until 2026-05-06, about 6.5 months later.
- May 2026: A community-maintained README banner and
MAINTAINERS.mdestablished lazy-consensus governance. On 2026-05-19, Matheson wrote that he “can’t dedicate full time”. - October 2026: Merged PR #591 added @cheeeee as the second maintainer, alongside @awmatheson.
- 2026-10-20: The maintenance update recorded 24 merged PRs since early May, including 14 from @cheeeee.
- 2026-10-25: Repository activity continued, but no v0.22.0 tag, release, or milestone existed.
Main includes unreleased Python 3.13/3.14 support through PyO3 0.25, excluding free-threaded builds. Other main-branch changes include:
- Linux packaging: manylinux2014 wheels.
- Kafka startup: A startup timeout and an OAUTHBEARER hang fix.
- Windows execution: A path fix in
bytewax.run.
The bytewax.io domain no longer resolves, and neither does docs.bytewax.io. Docs now live as Markdown under the repository’s docs/ folder. Issue #645 tracks access; open PR #587 proposes repointing links to the GitHub sources.
A community fork, bytewax-fork, published 0.22.0rc9 on 2026-03-04, requiring Python >=3.10. I treat that as a separate release-candidate dependency, not an interchangeable official upgrade.
The 2026-10-31 snapshot recorded 19,256 PyPI downloads last month. GitHub showed:
- About 2,068 stars.
- 29 open issues.
- 47 open pull requests.
With 14 of 24 recent merged PRs coming from one contributor, I see concentrated maintenance risk despite two named maintainers. The faust-streaming fork shows that a Python streaming project can continue after its original team steps away; I still recommend Bytewax only for teams that can carry their own fixes.
How Does Bytewax Compare to Competitors?
For a new Kafka-centric Python pipeline, I choose Quix Streams before Bytewax unless Bytewax’s source-agnostic API solves a specific requirement. Quix Streams released 3.28.1 in October 2026; Bytewax’s official package remains from November 2024.
- Quix Streams: The Apache-2.0, pure-Python library released 3.28.1 on 2026-10-15 and requires Python >=3.11. It wins for Kafka-centric teams wanting a maintained Python library, but its Kafka-only design excludes independent file-based dataflows.
- Pathway: Version 0.33.0 arrived on 2026-09-18, combining Python APIs with a Rust engine and an LLM/RAG toolkit. I recommend it for real-time RAG when its BSL 1.1 license and free Community limit of 8 GB RAM and 4 cores fit.
- Apache Flink / PyFlink: Version 2.3.0 offers exactly-once checkpointing and a broad connector ecosystem. I choose it for mission-critical distributed pipelines, accepting the JVM and greater cluster operations burden. Its Python package requires Python >=3.9.
- Faust (faust-streaming): Version 0.15.4 arrived on 2026-10-28 under BSD-3-Clause, requiring Python >=3.10. Its asyncio agents and tables suit asynchronous Kafka applications, but community maintenance does not remove volunteer-project risk.
- Arroyo: This Apache-2.0 Rust streaming SQL engine remains open source and self-hostable after Cloudflare’s 2025-04-10 acquisition. I shortlist it for SQL-first pipelines rather than Python callbacks, accepting a roadmap tied to Cloudflare.
- RisingWave: SQL materialized views replace application-level dataflow code. I choose it for managed SQL processing; Cloud starts from about $0.227 per RWU-hour. An RWU is the maximum of vCPU or memory in GB divided by four.
- Kafka Streams / Spark Structured Streaming: Kafka Streams provides Java/Scala processing with RocksDB state stores and no separate processing cluster. Spark supplies PySpark on a JVM cluster, with micro-batching as the default model.
Bytewax remains my pick when Apache-2.0 licensing and source-agnostic Python stateful logic matter more than a vendor relationship. I reject Bytewax as a shortcut around Flink setup when the pipeline’s recovery requirements favor Flink. For an existing asynchronous Kafka application, faust-streaming is a closer API fit than switching to Bytewax’s dataflow model.
| Tool | Language/API | License | Latest release | Best for |
|---|---|---|---|---|
| Bytewax | Python; Rust engine | Apache-2.0 | 0.21.1, 2024-11-25 | Self-owned Python dataflows |
| Quix Streams | Python; Kafka-centric | Apache-2.0 | 3.28.1, 2026-10-15 | Maintained Python Kafka processing |
| Pathway | Python/SQL; Rust engine | BSL 1.1 | 0.33.0, 2026-09-18 | Real-time RAG |
| PyFlink | Python API; JVM engine | Apache-2.0 | 2.3.0, 2026-06-21 | Mission-critical distributed streaming |
| Faust | Python asyncio | BSD-3-Clause | 0.15.4, 2026-10-28 | Kafka agents and tables |
| RisingWave | SQL streaming database | Apache-2.0 | v3.1.0, 2026-09-21 | Managed SQL materialized views |
How I Reviewed Bytewax
I tested Bytewax 0.21.1 on a 10-core Apple Silicon Mac, running macOS 26, on 2026-10-31. Installation failed under system Python 3.14 and worked in a Python 3.12 virtual environment.
My hands-on coverage included:
- Quickstart: Filtering and mapping a small
TestingSource. - Event-time processing: Tumbling and session windows with out-of-order events.
- Recovery: A 300,000-row payments file with a simulated crash and SQLite-backed resumption.
- Scaling: Worker-thread and separate-process runs for light and heavy Python work.
- Visualization: A Mermaid rendering of the recovery dataflow.
I read Bytewax’s source, CHANGELOG, MAINTAINERS.md, and open issues and PRs on GitHub. I compared the licenses, releases, and pricing of six rivals.
I did not test Kafka against a live broker, waxctl, Kubernetes/Helm, Docker, or the Prometheus metrics endpoint. I also did not build main under Python 3.13/3.14.
Prices current as of October 2026.
Should You Build on Bytewax in 2026?
Yes, if your team can own maintenance and wants Python-native stateful pipelines without a JVM. My FileSink recovery test resumed a 300,000-row job with 0 duplicates, and heavy Python work improved from 5.55 s to 2.84 s using four processes.
I recommend starting with 0.21.1 on Python 3.12, not assuming the latest interpreter will install cleanly. Building main can address interpreter compatibility, but adds build-and-validation responsibility and does not incorporate the open Kafka correctness fixes.
Skip Bytewax if you need a vendor SLA, official Python 3.13+ wheels today, or a stronger foundation for strict Kafka recovery requirements. I choose Quix Streams for maintained Python Kafka workflows, Flink for exactly-once checkpointing, or RisingWave for managed SQL processing.
Bytewax’s source-agnostic Python API is a stronger reason to adopt it than the absence of a license fee. I reject it for a team that expects volunteer maintainers to provide the operational safety net of a commercial platform.
Install bytewax==0.21.1 in a Python 3.12 environment, run a crash-and-resume test against your actual sink, and follow issue #560 in the Bytewax repository for maintenance and release decisions.
FAQ
Is Bytewax still maintained?
Yes, Bytewax is community-maintained by two listed volunteers, with repository activity continuing into October 2026. Its latest official PyPI release remains 0.21.1 from 2024-11-25. Recent commits and merged pull requests do not constitute a newer published package. See “Project Health: Who Maintains Bytewax in 2026?” above for the dated timeline.
Is Bytewax free?
Yes, Bytewax is free under the Apache-2.0 license, including stateful operators and SQLite-backed recovery. No paid Bytewax tier or commercial support contract remains available. The former Bytewax Platform was discontinued. You still pay for infrastructure and the engineering work required to deploy, maintain, and patch your pipelines.
Does Bytewax work with Python 3.13 or 3.14?
Bytewax supports Python 3.13/3.14 on main, but official PyPI wheels stop at Python 3.12 for release 0.21.1. Newer interpreters trigger a source-build attempt rather than a wheel installation. Building main requires a Rust toolchain; bytewax-fork is a separate release-candidate option, not an official Bytewax upgrade.
Where is the Bytewax documentation now?
Bytewax docs live as Markdown in the repository’s docs/ folder. The bytewax.io and docs.bytewax.io domains no longer resolve. The repository includes recovery and windowing concept guides alongside deployment material. Use the branch matching your installed version because main includes changes absent from the released 0.21.1 package.
Is Bytewax better than Flink?
Bytewax is better for a smaller, Python-native setup without a JVM; Flink wins for mission-critical distributed streaming in my recommendation. Flink offers exactly-once checkpointing and a larger connector ecosystem. Bytewax recovery is at-least-once by design, even though my FileSink test produced 0 duplicates. See “How Does Bytewax Compare to Competitors?” above.








