# Quix Streams: the only Python example ends mid-statement

> Quix Streams is a Kafka stream processing library with a declarative StreamingDataFrame, shipped on PyPI and conda-forge under Apache-2.0, with its last push dated 2026-10-01. The framework README example is four lines long and stops inside a function call, and the Makefile declares no target that runs the tests.

**quixio/quix-streams** — Python Streaming DataFrames for Kafka

- Repository: https://github.com/quixio/quix-streams
- Website: https://docs.quix.io
- Stars: 1,577 · Forks: 114
- Language: Python
- License: Apache-2.0
- Published: 2026-09-10 · Updated: 2026-09-10 · Language: en
- Canonical page: https://hysenlabs.com/projects/quixio-quix-streams

## The one Python example on the front page stops inside a function call

The README presents a single application as its example of processing data from a Kafka topic, converting Celsius temperature readings into Fahrenheit and producing alerts to another topic. That application is four statements long and the fourth one is unfinished:

```python
from quixstreams import Application

# A minimal application reading temperature data in Celsius from the Kafka topic,
# converting it to Fahrenheit and producing alerts to another topic.

# Define an application that will connect to Kafka
app = Application(
    broker_address="localhost:9092",  # Kafka broker address
)

# Define the Kafka topics
temperature_topic = app.topic("temperature-celsius", value_deserializer="json")
alerts_topic = app.topic("temperature-alerts", value_serializer="json")

# Create a Streaming DataFrame connected to the input Kafka topic
sdf = app.dataframe(to
```

So the broker, the input topic, the output topic and both serializer names are all shown, and the operation the example was introduced to demonstrate is not. The prose points elsewhere for anything runnable, naming a Quickstart and four tutorials: Word Count, Anomaly Detection, Purchase Filtering and Solar Farm Telemetry Enrichment. The key concepts it introduces instead are declarative, so the missing fourth line is where the transformation would have been declared.

## Two distributions, and the conda one is published under a namespace

Installation is offered through two channels with different coordinates:

```shell
# PyPI
python -m pip install quixstreams

# or conda
conda install -c conda-forge quixio::quixstreams
```

The package is `quixstreams` on PyPI and `quixio::quixstreams` on conda-forge, where the `quixio::` prefix is a channel user rather than a channel. A `conda/` directory sits at the repository root, so the conda recipe is built from this tree rather than mirrored from the wheel. Two independent build paths means two independent version streams to reconcile when they disagree.

The version floor is stated twice and agrees. The stated requirement is Python 3.11+ with Apache Kafka 0.10+, and the packaging metadata writes it as `requires-python = ">=3.11, <4"`, so Python 3.10 users are outside the supported range by an explicit upper-bound expression rather than by a lower bound alone. What is not in that file is the version itself. pyproject.toml marks version and dependencies as dynamic, so neither number appears in the file most people would open to pin them, and a `requirements.txt` sits at the root carrying the runtime set instead.

## Pure Python here means no JVM, not no native code

The first key feature claim is pure Python, meaning no wrappers around Java and no cross-language debugging. That claim is about the JVM, and the dependency list explains what is left. The Kafka client is `confluent-kafka[avro,json,protobuf,schemaregistry]` in the range from 2.8.2 up to but not including 2.13, which is a binding to the native librdkafka client rather than a pure-Python protocol implementation. Stateful operation rides on `rocksdict` in the 0.3 series, a Rust-backed local store. The remaining support cast is `orjson`, `pydantic`, `jsonschema`, `jsonlines`, `rich`, `jsonpath_ng` and `httpx`, with `typing_extensions` and `pydantic-settings` for configuration and typing.

Two things follow from that list which the feature list does not say out loud. Transport and state are both native extensions, so a platform without a wheel for confluent-kafka or rocksdict needs a toolchain before it needs Python code. And `pydantic-settings` makes environment variables a supported configuration path, while the README names no environment variable at all and shows configuration only through the `Application` constructor.

## The all extra is twenty-two packages and the narrow extras are four

The optional dependency named `all` is not a convenience bundle, it is the entire connector surface. It spans Google Cloud BigQuery, PyIceberg with pyarrow and glue, InfluxDB 3 with pandas and InfluxDB 1, Google Cloud Pub/Sub, Postgres through psycopg2, MySQL through pymysql, MongoDB through pymongo, Neo4j, Amazon S3 through boto3, Azure blob storage, Redis with hiredis, Elasticsearch, Paho MQTT, and pandas with python-dateutil for the frame-shaped work. Against that, the file names a small number of narrow extras so you can take one codec at a time, with `avro`, `parquet`, `protobuf` and `influxdb1` among them.

The version expressions inside `all` are where the caution lives. `mysql-replication` is written as greater than or equal to 1.0.17 and less than 1.0.18, a single patch line, which is a change-data-capture connector held deliberately still. `azure-storage-blob` stops at 12.31, `google-cloud-bigquery` stops at 3.46 and `redis` stops at 9. Install the bundle and you accept all of those ceilings at once, whether or not you touch the affected sink.

## State is a local store and the transaction boundary belongs to Application

Exactly-once processing is offered via Kafka transactions, and the object that arranges it is `Application`, not your pipeline code. Under the hood it is described as consuming and deserializing messages, processing them with the `StreamingDataFrame`, producing to the output topic, automatically checkpointing processed messages and state for resiliency, and scaling through Kafka's built-in consumer groups mechanism. `StreamingDataFrame` itself is a predefined declarative pipeline, so the commit and transaction boundaries are set by the framework around a dataframe the user never sees the internals of.

That structure is what makes the guarantee portable and also what bounds it. Because the transaction is a Kafka transaction, the behavior is a property of the broker underneath, which is why the floor is stated as Apache Kafka 0.10+ and why the project describes itself as scaling on Kafka's low-level scalability, resiliency and durability instead of maintaining its own. Around that sit the operators: windowing, branching, group by, fault-tolerant stateful operations and streaming joins. What is not written down anywhere here is what exactly-once means when a sink is one of the non-Kafka targets in that extra, since the transaction can only cover what the broker participates in.

## The Makefile documents itself by grepping its own comment markers

`make` with no arguments runs `help`, and the help target is generated by grepping the Makefile for target names followed by a `##` comment, then piping the matches through awk to print each name indented and colored in a fourteen character field. The targets it finds are `format`, `lint`, `format-check` and `typecheck`, with `check` declared as an alias for `lint`.

`PYTHON` is discovered by probing, in the order activated virtual environment, `./.venv`, `python3`, then `python`, and a comment above it explains why: a venv symlink may exist but be broken or platform-mismatched, and invoking tools as `python -m ruff` and `python -m mypy` also avoids picking up a console binary from the wrong platform. The probe is overridable with `make lint PYTHON=...`. `MYPY_PATHS` is set to `quixstreams` alone, with a pointer to the pre-commit config for the rest. And while a `tests/` directory and a `requirements-dev.txt` both sit at the repository root, none of these targets runs them. The six phony targets cover style and types, and the test invocation is not in the visible build tooling.

## The library ships no cluster, and the DevOps story belongs to the product

The pitch is a lightweight library without server-side clusters to manage, and pipelines that run anywhere Python is installed. Deployment is then offered as a choice between your own infrastructure and Quix Cloud, which is described as running on AWS, Azure, GCP or on-premise, handing over self-service DevOps, CI/CD and monitoring, with the claim that it is built with engineering practices learned from Formula 1 Racing. None of that arrives in the Apache-2.0 repository. There is no operator, no container definition and no deployment manifest in the tree, so the operational layer is the commercial platform and not the library.

Metadata drift around that boundary is small but real. The homepage recorded with the project points at the documentation site, while the packaging metadata names the GitHub repository as its homepage, so two files disagree about where the project starts. The declared author is Quix Analytics Ltd, the license is set by reference to the LICENSE file, and a `LICENSES/` directory sits beside it for per-license texts. The classifier claims Production/Stable, which is a packaging claim about release discipline and says nothing about the example that stops mid-call.

## Conclusion

Quix Streams is a reasonable pick when your pipeline is pure Python, your state fits a local key-value store, and you can accept that exactly-once is a property of your broker's transaction support rather than of the framework itself. Install with `python -m pip install quixstreams` for the wheel the build produces, or with the conda-forge channel when your environment is already conda, and note that pyproject.toml declares version and dependencies as dynamic so neither value appears in the file you would normally pin. Take the `all` extra only when you need one of its twenty-two packages, and check the `mysql-replication` floor of 1.0.17 with a ceiling of 1.0.18 before you rely on that connector. Do not plan on the README to hand you a working pipeline, because its example ends at `sdf = app.dataframe(to` and the transformation it promises lives in the docs. And if you build from source, know that the Makefile gives you format, lint and mypy and nothing that runs the tests directory, so the test command is something you have to go find.

## FAQ

### What does Quix Streams need in order to run?

Python 3.11 or newer and Apache Kafka 0.10 or newer. The packaging metadata writes the Python floor as >=3.11, <4, and the runtime dependency file lists eleven packages led by confluent-kafka.

### Which data stores does the Quix Streams all extra cover?

Twenty-two packages: Google BigQuery and Pub/Sub, PyIceberg with glue, InfluxDB 1 and 3, Postgres, MySQL with mysql-replication, MongoDB, Neo4j, S3, Azure blob storage, Redis, Elasticsearch, Paho MQTT, pandas, python-dateutil, fastavro and protobuf.

### How does Quix Streams provide exactly-once processing?

Through Kafka transactions. The Application object consumes and deserializes, runs the StreamingDataFrame, produces to the output topic, checkpoints processed messages and state automatically, and scales using Kafka's built-in consumer groups.

### How do you run the Quix Streams tests from the repository?

The Makefile does not say. It declares help, format, format-check, typecheck, lint and an alias check for lint, while a tests/ directory and a requirements-dev.txt file sit at the repository root with no target referencing either.

## Sources

- [License: Apache-2.0](https://github.com/quixio/quix-streams/blob/main/LICENSE)
- [Project website](https://docs.quix.io)
- [quixio/quix-streams on GitHub](https://github.com/quixio/quix-streams)
- [README](https://github.com/quixio/quix-streams/blob/main/README.md)
- [Releases](https://github.com/quixio/quix-streams/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/quixio-quix-streams
