Everything you need for structured event delivery in Elixir
Collect events during a request or transaction and commit them atomically. No events leak on failure.
Built-in Phoenix Channels adapter for real-time WebSocket delivery, plus a simple behaviour for custom adapters.
Fan-out to multiple adapters with independent backpressure per consumer. Built on GenStage.
Subscribe to events with supervised task execution and cascading support for internal workflows.
Compile-time event-to-topic mapping with multi-tenant scoping. Isolate WebSocket topics per tenant with a single config option.
Built-in telemetry events for monitoring, plus test helpers for capturing and asserting on emitted events.
Get up and running in minutes
# config/config.exs
config :emissions,
adapters: [
{Emissions.Phoenix.PubSubAdapter,
pubsub: MyApp.PubSub,
scope: :org_id}, # multi-tenant topic scoping
{MyApp.KafkaAdapter, topic: "my-events"}
],
handlers: [
MyApp.SearchIndexHandler,
MyApp.NotificationHandler
]
# router.ex — auto-manages buffer lifecycle per request
pipeline :api do
plug :accepts, ["json"]
plug Emissions.Plug
end
The plug starts a buffer for mutating requests, commits on 2xx responses, and terminates on errors. Just emit events in your controllers — no manual start/commit needed.
def create_order(conn, params) do
case Orders.insert(params) do
{:ok, order} ->
Emissions.emit(:order_created, order, %{source: "api"})
json(conn, %{id: order.id})
{:error, changeset} ->
conn
|> put_status(:unprocessable_entity)
|> json(%{errors: format_errors(changeset)})
end
end
defmodule MyApp.Topics do
use Emissions.TopicRouter,
mappings: %{
orders: [:order_created, :order_updated, :order_shipped],
inventory: [:item_received, :item_adjusted, :item_moved],
users: [:user_created, :user_updated]
}
end
MyApp.Topics.topic_for_event(:order_created)
#=> :orders
A GenStage pipeline with fan-out to multiple adapters
emit() / commit()
GenServer, per-request
GenStage + BroadcastDispatcher
Events flow through a per-request buffer, get committed to a GenStage producer, and fan out to all registered adapter consumers. Each consumer manages its own backpressure independently. The Handler Dispatcher is a special adapter that routes events to your internal handler modules, executing each in a supervised task.
Transactional event buffering with clean semantics
Dive deeper with our comprehensive guides
Build custom adapters to deliver events to any destination.
Real-time event delivery over WebSockets with built-in PubSub adapter and multi-tenant topic scoping.
Pluggable event serialization for maps, Avro, Protobuf, and custom formats.
Subscribe to events and handle them in supervised tasks.
Per-request event buffering with transactional semantics.
GenStage producer with BroadcastDispatcher for fan-out delivery.
Compile-time event-to-topic mapping with zero runtime overhead.
Automatic buffer lifecycle management for Phoenix and Plug apps.
Test helpers for capturing and asserting on emitted events.
Comprehensive instrumentation for monitoring and observability.