CosmoStreams

GraphQL Subscriptions
Without the Hurdle

Cosmo Streams moves subscription infrastructure into the Router, so your services only publish events and respond to HTTP requests. No connection management required.

The Problem

Subscriptions force connection state into every service.

Without Cosmo Streams, each service that supports subscriptions manages its own connection state, WebSocket servers, and subscriber tracking. Scaling and infrastructure choices become constrained by persistent connections.

See capabilities
01

Connection state in every service

Each subgraph that serves subscriptions holds long-lived connections from the Router, one per distinct set of forwarded auth headers (so often one per user), plus subscriber tracking and state.

02

Scaling tied to subscribers

Subscriber count influences how services scale. As connections grow, every participating service must account for the persistent load.

03

Infrastructure limits

Persistent connections limit infrastructure choices. Many compute platforms aren't designed to maintain long-lived connections.

How It Works

The Router runs the subscription server. Your services stay HTTP-only.

01

Service publishes an event

A service publishes an event when data changes. No WebSocket server required.

02

Router receives the event

The Router receives the event from Kafka, NATS, or Redis.

03

Router resolves fields

Events carry the entity type and key; the Router resolves the remaining fields from your subgraphs.

04

Deliver to subscribers

The Router delivers the result to matching subscribers.

Capabilities

Subscriptions without connection management in your services

Move connection state to the Router. Keep services HTTP-based and stateless.

No WebSocket servers in subgraphs

HTTP-only services

Subgraphs handle HTTP requests and publish events. They do not manage persistent client connections. Cosmo Streams moves connection management to the Router.

HTTP onlyPublish eventsNo connection state

Compatible with serverless

Request-based scaling

Services remain request-based, so they can run on Lambda, Cloud Run, and other short-lived compute platforms. The Router maintains client connections.

LambdaCloud RunServerless

Works with your existing broker

Kafka, NATS, or Redis

The Router connects to Kafka, NATS (including JetStream), or Redis. No additional messaging layer required. Your services publish events with the entity __typename and key; Cosmo Streams exposes them as GraphQL subscriptions and resolves the other fields from your subgraphs.

Apache KafkaNATS / JetStreamRedis

Subscription logic centralized

Router-level filtering and hooks

Filter events in the schema with @openfed__subscriptionFilter, or write a Router custom module for per-subscriber decisions. The Router does not check whether a client may subscribe to a topic. Add that check in a SubscriptionOnStart handler.

Subscription filterCustom modulesSubscriptionOnStart

Brokers

Kafka, NATS, and Redis

Each provider is configured under events.providers in the Router config and referenced by ID from the schema directives.

NATS and JetStream

  • Subscribe to one or more subjects, and publish from mutations.
  • Request/Reply: @edfs__natsRequest sends a request to a subject and waits for the response.
  • JetStream: configure a stream and consumer, so messages sent while a subscription is inactive can be consumed when it restarts. The consumer is deleted after 30 seconds of inactivity by default; consumerInactiveThreshold changes that.
  • Authenticate with a token or a username and password. TLS, including mTLS, is configurable.
NATS and JetStream docs

Apache Kafka

  • Subscribe to one or more topics, and publish from mutations.
  • TLS, plus SASL/PLAIN or SASL/SCRAM authentication, in the provider config.
  • The Router does not create topics. Topics, including ones rendered from templates, must already exist.
  • The Kafka client connects lazily, so by default the Router starts even if a broker is unreachable.
Apache Kafka docs

Redis

  • Subscribe to one or more channels, and publish from mutations.
  • Set cluster_enabled to use the Redis Cluster client. The URLs become cluster seeds.
  • Connection and pool settings go in the URL query string.
  • Valkey works as a drop-in replacement, standalone or in cluster mode.
Redis docs

From the docs

What the Router does with subscriptions

~150-200MB

Memory for 10,000 idle clients on one Router, with 0% CPU while no messages are published.

1 trigger

Subscriptions on the same topic share one trigger. It shuts down when the last of them unsubscribes.

0

WebSocket servers in your subgraphs. The Router fetches fields from subgraphs over plain HTTP.

5

Client subscription protocols: graphql-ws, Server-Sent Events, multipart HTTP, and the legacy subscriptions-transport-ws and absinthe.

The Router uses epoll and kqueue where the OS supports them. Read how in Scaling GraphQL Subscriptions in Go, and how the Router handles subscriptions in Native Subscriptions with Cosmo Router.

Filtering and authorization

One directive and five handlers

Handlers are Router custom modules written in Go. SubscriptionOnStart, OnReceiveEvents, and OnPublishEvents need Router 0.266.0 or later, SubscriptionOnCreate needs 0.327.0, and BeforeEventsDispatch needs 0.336.0. The Router does not authorize subscribers against topics on its own.

@openfed__subscriptionFilter

Declarative filter in the schema. Supports IN, combined with AND, OR, and NOT.

SubscriptionOnStart

Runs once when a client subscribes. Use it to check permissions, rate-limit, or send an initial event.

OnReceiveEvents

Runs when events arrive from the broker. Use it for per-subscriber decisions.

BeforeEventsDispatch

Runs once per batch of events, before dispatch to any subscriber.

OnPublishEvents

Runs before the Router sends events to the broker.

SubscriptionOnCreate

Runs before a subscription is registered and can change its event configuration. Experimental.

When to Use Cosmo Streams

Where Cosmo Streams fits

Serverless, event-driven backends, or per-user subscription filtering. Cosmo Streams centralizes connection management in the Router.

Serverless

Subscriptions without persistent connections

Your services run on Lambda, Cloud Run, or similar. Cosmo Streams lets services remain request-based while the Router maintains connections to clients.

Event-driven

Backend already publishes events

Services publish to Kafka, NATS, or Redis. Cosmo Streams exposes events that carry the entity type and key as GraphQL subscriptions, without adding subscription infrastructure to each service.

Per-user data

Different results per subscriber

The same subscription should return different results by user. Cosmo Streams filters events per subscriber in the Router, and a custom module can authorize each subscription when it starts.

FAQ

How Cosmo Streams works

More in the Cosmo Streams docs. Subscriptions run on the Cosmo federation router.

Get started

Publish events. Deliver subscriptions.
No connection management in your services.

Cosmo Streams moves subscription infrastructure into the Router. Your services stay HTTP-only.