# Building emitix: a zero-dependency event bus for Python
> Why I built a tiny, fully-typed event bus for Python - and how the sync + async, wildcard, and priority pieces fit together.
Author: Rahul Bhatt
Published: 2026-10-02
Tags: python, architecture, open-source
Canonical: https://bhattrahul.in/blog/building-emitix
---Most of my projects reach a point where one part of the code needs to tell
another part "this just happened" - without the two knowing about each other.
That's the job of an event bus. I wanted one that was tiny, typed, and didn't
drag in dependencies. So I built [emitix](/work/emitix).

## The smallest useful thing

The entire API starts with one decorator and one call:

```python title="quickstart.py"
import emitix

@emitix.on("user.created")
def send_welcome_email(user):
    print(f"Welcome, {user}!")

emitix.emit("user.created", "Ada")
```

Arguments to `emit` flow straight through to every handler. No envelope, no
schema ceremony - just call it like a function.

## Going async

Handlers can be coroutines. Emit them with `emit_async`:

```python title="async.py" {4}
@emitix.on("order.placed")
async def charge_card(order):
    await payments.charge(order)

await emitix.emit_async("order.placed", order)
```

## Wildcards and priority

Two features that turned out to matter in real code - subscribing to a family of
events, and controlling the order handlers run in:

```python title="wildcards.py" ins="priority=10"
@emitix.on("order.*")          # any order.* event
def audit(event, *args):
    log.info("audit", event, args)

@emitix.on("order.placed", priority=10)   # runs before lower priorities
def reserve_stock(order):
    inventory.reserve(order)
```

## What I left out (on purpose)

- No broker, no network - it's in-process by design.
- No required message classes - strings and args are enough for most apps.

If you want the full feature list - `once()`, `off()`, thread-safety - it's in
the [project write-up](/work/emitix) and on
[PyPI](https://pypi.org/project/emitix/).

{/* TODO(rahul): add benchmarks or a before/after from a real refactor. */}