Library / SDK
zeromq/pyzmq avatar
zeromq/pyzmq

PyZMQ: Python bindings for ZeroMQ, and what you get before writing a socket

PyZMQ: Python bindings for zeromq

4,177 stars664 forksPythonBSD-3-Clause

At a glance

What is it?
PyZMQ wraps libzmq for CPython and PyPy, shipping prebuilt wheels for macOS, Windows and Linux. The interesting part is not the binding layer but the boundary: what libzmq does for you, and what it deliberately leaves to your code.
Who is it for?
Adopt PyZMQ if you need ZeroMQ messaging from Python and want the binding to stay out of the way: the API tracks libzmq's stable 3.x and 4.x surface without translation layers. Do not adopt it expecting broker semantics, persistence, or delivery guarantees that libzmq does not provide, and do not pin an old pyzmq expecting the version number to match libzmq, since that stopped with 13.0.0.
Can I use it commercially?
Yes. BSD-3-Clause 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 last received commits 23 days ago.
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 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What PyZMQ actually is, and who ends up using it

PyZMQ is a binding, not a messaging system. The messaging implementation lives in libzmq, a C library; PyZMQ exposes it to Python. The README states that the package supports libzmq 3.2.2 and newer, including 4.x, and that it covers the stable (not DRAFT) 3.x and 4.x APIs. It runs on CPython 3.9 and newer and on PyPy.

The audience is narrower than "anyone who needs messaging". You are already the kind of developer who wants to choose a socket pattern (request-reply, publish-subscribe, push-pull, dealer-router) and wire it up yourself, rather than call a broker API and let the broker decide. If you want a server that stores messages and replays them, PyZMQ is the wrong layer. The README points readers at the ØMQ Guide for learning ZeroMQ itself, which is a fair signal that the binding assumes you bring the messaging knowledge.

One consequence of being a binding: almost everything you read about ZeroMQ behaviour applies unchanged. The README makes this explicit for the version story, saying there is "no code to change, no flags to pass" when moving to a newer libzmq. That property is the main reason the project has stayed useful across libzmq releases.

Where the Python layer stops and libzmq begins

The repository layout tells you most of the architecture. The Python package lives in zmq/, the compiled extension is built from Cython sources, and the build is driven by scikit-build-core with CMake, per pyproject.toml. On PyPy the build requires cffi instead of Cython, and the runtime dependency list in pyproject.toml is exactly that: cffi, and only when the implementation name is pypy.

So the data flow is: your Python code calls a zmq.Socket method, the compiled extension marshals frames into libzmq, and libzmq handles the transport, the queueing, and the socket state machine. Messages do not pass through a Python-level queue in the normal path. That is why throughput is dominated by libzmq and by how you structure your sends, not by the binding.

The build system is worth noting because it is unusual for a Python extension. scikit-build-core plus CMake means the project can build libzmq itself or link against one you already have, and pyproject.toml restricts the build to a single target and component named pyzmq. There is also an environment override: setting PYZMQ_LATEST_CYTHON pulls Cython from a GitHub archive rather than PyPI, which is a development convenience rather than something you want in a release pipeline.

Installing PyZMQ with pip and where the examples take over

The README recommends getting wheels from PyPI rather than building from the repository, and notes that wheels exist for macOS, Windows and Linux. The install is one command:

bash
pip install pyzmq

The README adds a caveat that matters in CI: make sure you are using the latest pip, or it may not find the right wheels. An old pip on a new Python version is the most common cause of an unexpected source build.

If the wheel does not work, or if you already have libzmq installed and configured the way you want, the README gives a way to force compilation:

bash
pip install --no-binary=pyzmq pyzmq

That path needs a compiler and the build dependencies from pyproject.toml, and it will link against the libzmq it finds. The repository also notes that building from the GitHub repository requires a recent Cython, so the source tarball from PyPI is the friendlier route if you want to compile.

For a first real use, do not write the socket code from memory. The repository ships an examples/ directory with subdirectories for the patterns you are most likely to need, including pubsub/, asyncio/, poll/, security/ and monitoring/, and the README points at the ØMQ Guide, which has a Python version of every example. Start by copying the closest example rather than inventing topology, because the socket pattern determines what the binding will and will not do for you.

The asyncio and event-loop story is where Python-specific work lives

Most of PyZMQ is a thin pass-through. The exception is integration with Python's concurrency models, and that is where the project has its own design surface. The examples directory contains asyncio/, eventloop/, gevent/ and poll/ subdirectories, which reflects that these are distinct integration paths rather than one general answer.

The practical constraint: a ZeroMQ socket is not thread-safe, and the binding does not make it so. If you use PyZMQ from multiple threads or from an event loop, you need the integration the project provides rather than calling recv() from arbitrary places. The asyncio examples exist precisely because a blocking receive inside a coroutine stalls the loop.

This is the part of PyZMQ I would read before writing code, not after. The README itself is short and defers to the Read the Docs site for API details and to the ØMQ Guide for messaging concepts, so the asyncio specifics are in the examples and the Sphinx docs rather than in the top-level README. If your application is already asyncio-based, budget time for that reading; it is not a drop-in.

What PyZMQ will not do for you

The binding is faithful to libzmq, which means it inherits libzmq's limits. There is no broker, no message persistence, and no built-in replay. If a subscriber connects after a publisher sends, the message is gone; that is the pub-sub pattern, not a bug in the binding. Anyone evaluating PyZMQ as a queue should stop here and look at a broker-based system instead.

There is also a version trap. The README is explicit that PyZMQ releases stopped matching libzmq versioning after 2.2.0, and that from 13.0.0 onward the project follows semantic versioning for PyZMQ itself. So a pyzmq version number tells you nothing about the libzmq it will link against. If your deployment depends on a specific libzmq feature, verify the linkage rather than inferring it from the pyzmq version.

The old-version guidance in the README is a good illustration of how far back the project carries compatibility notes, but it is also a warning: pinning pyzmq<16 to keep an old Python, or pyzmq<2.1 for libzmq 2.0.x, means you are on a branch of history that gets no attention. The README documents those pins without recommending them.

Finally, the README does not document rollback or downgrade procedures. If a new pyzmq release breaks your deployment, the recovery path is pip's ordinary version pinning plus the changelog, and you should confirm that yourself rather than assume the project ships a rollback mechanism.

PyZMQ against a broker-based Python client

The natural alternative is a client for a message broker, such as a RabbitMQ or Kafka client for Python. The difference is architectural, not cosmetic. With a broker, your process connects to a central server that owns routing, durability and consumer offsets. With PyZMQ, your processes connect to each other, and libzmq owns only the transport and the socket pattern.

That changes what you operate. A broker deployment adds a server to run, monitor and upgrade, and in exchange you get persistence and delivery semantics the broker defines. A PyZMQ deployment adds no server, but you now own reconnection logic, backpressure decisions, and what happens when a peer disappears mid-message. Neither is better in the abstract; they fail in different places.

There is a middle option worth knowing about: ZeroMQ itself has a broker pattern, and the project's examples/device/ directory exists for that. But a ZeroMQ device is a process you write and run, not a product you install. If you want a broker you do not maintain, PyZMQ is the wrong tool and the honest answer is to use a broker client.

Maintenance, licensing and upgrade cost

The repository is not archived and the last push was on 2026-09-07, so it is being worked on. The most recent release listed is v27.2.0 on 2026-08-20, following v27.1.0 on 2025-09-08 and v27.0.2 on 2025-08-21. That cadence suggests releases are not frequent, which for a binding is reasonable: the upstream API it tracks changes slowly.

Licensing is BSD-3-Clause, declared both in the repository and in pyproject.toml. That is permissive and compatible with commercial use. One detail worth checking if you redistribute: pyproject.toml lists wheel.license-files covering LICENSE* and licenses/LICENSE*, and the repository has a licenses/ directory plus a RELICENSE/ directory. Those exist because the project bundles or links code with its own terms. Whether that affects your distribution is a question for your legal review, not something to settle from a README.

Upgrade cost is mostly the wheel. If you install from PyPI on macOS, Windows or Linux, an upgrade is a pip version bump and a restart. The cost appears when you build from source: you inherit the CMake and scikit-build-core toolchain, and you are responsible for the libzmq your build links against. Teams that compile pyzmq should pin both the pyzmq version and the libzmq version, because the pyzmq version does not tell you the second one.

Editorial conclusion

Adopt PyZMQ if you need ZeroMQ messaging from Python and want the binding to stay out of the way: the API tracks libzmq's stable 3.x and 4.x surface without translation layers. Do not adopt it expecting broker semantics, persistence, or delivery guarantees that libzmq does not provide, and do not pin an old pyzmq expecting the version number to match libzmq, since that stopped with 13.0.0. Before committing, check whether a wheel exists for your platform and Python version, confirm which libzmq the wheel links against, and read the changelog for the release you are pinning.

Frequently asked questions

How do I install ZMQ in Python?

Install PyZMQ from PyPI with pip install pyzmq. The README notes that wheels are built for macOS, Windows and Linux, and warns that you should use the latest pip or it may not find the right wheel.

How do I install pyzmq?

Use pip install pyzmq. If the wheel does not work for your environment, or you want to compile against a libzmq you already configured, the README gives pip install --no-binary=pyzmq pyzmq.

What is pyzmq?

PyZMQ is the Python binding for ZeroMQ, exposing the libzmq 3.x and 4.x stable APIs to CPython 3.9 and newer and to PyPy. The messaging implementation itself lives in libzmq, not in the Python package.

What is the pyzmq package used for?

It lets Python code use ZeroMQ socket patterns such as request-reply and publish-subscribe over libzmq transports. The README directs readers to the ØMQ Guide for the messaging concepts, since the binding assumes you already know them.

What is the difference between zmq and pyzmq?

ZeroMQ is the C library, libzmq, that implements the messaging; PyZMQ is the Python binding to it. PyZMQ supports libzmq 3.2.2 and newer, and the README notes that pyzmq releases stopped matching libzmq version numbers after 2.2.0.

Official sources

  1. License: BSD-3-Clause
  2. Project website
  3. README
  4. Releases
  5. zeromq/pyzmq on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/zeromq-pyzmq.svg)](https://hysenlabs.com/projects/zeromq-pyzmq)