A Smooth API Developer Experience with WunderGraph Cosmo


Vincent Vermersch
GraphQL and CQRS align naturally, with queries as reads and mutations as commands. Federation enables contract-driven collaboration, and Event-Driven Federated Subscriptions (EDFS) enrich lightweight events (e.g., from NATS) into full GraphQL responses. Cosmo supports this architecture with efficient scaling, and persisted operations that—when enforcement is enabled—secure the API by allowing only trusted queries.
CQRS (Command Query Responsibility Segregation) represents a powerful architectural approach that separates read and write operations in an application. This separation allows each side to be optimized according to its specific needs: commands (writes) can prioritize consistency and complex business rule validation, while queries (reads) can optimize performance with denormalized data models or dedicated caches.
Additionally, CQRS facilitates Event Sourcing , providing a complete history of changes and enabling state reconstruction at any point in time.
GraphQL naturally aligns with CQRS principles with its clear distinction between queries and mutations. GraphQL queries align perfectly with the "Query" side of CQRS, allowing clients to specify precisely the data they need, thus reducing the issues of over-fetching and under-fetching typical of REST APIs.
Mutations, on the other hand, represent the "Command" side, offering an explicit interface for modification operations with typed and predictable returns. GraphQL’s strongly typed nature also facilitates the definition of clear contracts between read and write models, while allowing these models to evolve independently.
GraphQL resolvers can query different data sources optimized for reading. At the same time, mutations can trigger commands in an event system, thus creating an elegant and maintainable CQRS architecture where complexity is encapsulated behind a unified and intuitive interface for frontend developers. With Cosmo , the CQRS pattern maps cleanly in practice. The Cosmo Router and schema composition help read and write models evolve independently while staying connected through federation contracts.
GraphQL Federation empowers distributed teams to work autonomously while maintaining a cohesive API, allowing each team to own and develop its portion of the graph independently.
Through the concept of subgraphs, teams can define their domain-specific schemas, entities, and resolvers without needing to coordinate every change with other teams.
This approach works just as well for collaboration within one team, connecting frontend and backend.
This architectural pattern establishes clear boundaries of ownership, where each team becomes responsible for its service's schema definition, including the types it exposes and the fields it contributes to shared entities.
The federation specification provides a standardized way to express these relationships through directives like @key
, @extends
, and @external
, creating an explicit contract that defines how services interconnect. This contract-driven approach means teams can iterate on their internal implementations freely as long as they maintain their published schema interface, reducing cross-team dependencies and enabling parallel development workflows.
The composition process in GraphQL Federation acts as a critical enforcement mechanism that validates inter-team contracts at build time, not at runtime.
When subgraphs are composed into a supergraph, the composition engine performs comprehensive validation to ensure that all type definitions are compatible, required fields are provided by the appropriate services, and entity references can be properly resolved across service boundaries. This automated validation catches contract violations early in the development cycle, making the implicit dependencies between teams explicit and verifiable.
By treating schema composition as a CI/CD step, organizations can enforce governance policies, require schema reviews before deployment, and maintain a versioned history of their API evolution. This systematic approach transforms what could be a complex coordination challenge into a well-defined process where contract adherence is automatically verified, enabling teams to move fast while maintaining system integrity.
When an event broker publishes a minimal event containing only essential identifiers, the backend developer is happy because they only need to publish minimal data with no overhead. But that might not be enough for the frontend — they may want the ticket price, purchase date, or other details.
For example:
With EDFS , they can leverage the power of GraphQL federation to automatically resolve additional fields from various subgraphs.
The Router receives the anemic event—a lightweight message containing only essential identifiers—recognizes it as an Entity through the @key
directive, and then seamlessly fetches additional fields like ticket price, department information, or recent activities from their respective subgraphs. This transforms a simple notification into a rich, contextualized update tailored to each client’s subscription query.
This approach maintains the efficiency of event-driven architectures, where producers can publish lightweight events without needing to know about every possible consumer requirement. The GraphQL layer then acts as an intelligent orchestrator, enriching these events with relevant data from across the federated graph.
This architecture fundamentally changes the economics and complexity of implementing subscriptions in federated systems.
Traditional GraphQL subscriptions would require the event producer to include all possible data, creating tight coupling and large payloads. Alternatively, the subscribing subgraph would need to maintain stateful connections and orchestrate the enrichment itself, consuming significant CPU and memory resources.
With EDFS, subgraphs remain completely stateless – they simply publish minimal events to NATS or another broker and continue processing.
With EDFS, frontend developers gain simplicity in consuming real-time events without needing a single line of backend subscription code.
By defining an Event-Driven Graph (EDG) with the @edfs__natsSubscribe
directive, developers can directly map NATS subjects to GraphQL subscriptions.
For example, defining a subscription creates a direct bridge between the NATS event stream and the GraphQL API:
When a frontend client executes this subscription, the Cosmo Router subscribes to the NATS subject user.123.updated
and maintains the connection. It then begins listening for incoming events and handles updates as they arrive.
For example, when a minimal event like this is published on NATS:
The Router receives the request, enriches it by fetching additional User fields from the appropriate subgraphs based on the client's selection set, and streams the complete response back to the frontend over the configured transport (such as WebSockets, SSE, or HTTP multipart).
The frontend developer can simply use standard GraphQL subscription syntax without needing to know or care about NATS or event broker specifics.
Backend teams no longer need to implement WebSocket servers, manage connection pools, handle reconnection logic, or coordinate subscription state across services – they simply publish lightweight events to NATS and remain completely stateless.
Under the hood, the Router uses epoll/kqueue to handle thousands of WebSocket connections. In practice, 10,000 concurrent subscriptions can run at ~40 goroutines, ~150–200 MB of memory, and ~0% CPU at idle. The Router also deduplicates subscriptions so identical subscriptions share the same trigger, and it orchestrates cross-subgraph data fetching to enrich anemic events. Developers don’t need to tune connection pools or kernel-level concurrency. The Router scales cleanly to thousands of clients out of the box.
Operations are pre-registered in CI/CD with wgc operations push
; when enforcement is enabled, the Cosmo Router only accepts these trusted queries instead of arbitrary ones from clients.
This approach significantly reduces your API's attack surface by preventing expensive or malicious queries from being executed. This can effectively hide the schema from most clients when you enforce persisted operations (and typically disable introspection), because clients send only SHA-256 identifiers.
The progressive migration path moves from logging unknown operations to allowing only safelisted operations and finally to blocking all unknown operations. This staged rollout lets teams gradually identify and register all legitimate client operations before fully locking down production environments.
Each client application can maintain its own set of operations (identified by the graphql-client-name
header), allowing fine-grained control over what different clients can execute.
For instance, your mobile app might have a different set of allowed operations than your web application. Updating either client's allowed operations is now as simple as running wgc operations push
with the new operation manifest.
This separation between operation registration and Cosmo Router deployment enables rapid client iteration while maintaining strict security controls. Frontend teams can add new queries to their applications and register them independently without coordinating Cosmo Router deployments with the platform team.
Frequently Asked Questions (FAQ)
GraphQL aligns with CQRS by separating queries and mutations. Queries map to the read side, allowing precise data fetching, while mutations map to the write side, providing typed, predictable commands.
WunderGraph Cosmo helps support CQRS workflows by allowing read and write models to evolve independently while staying connected through federation contracts and schema composition.
EDFS is a pattern where lightweight events are published to a broker like NATS and enriched through GraphQL Federation. The Cosmo Router resolves additional fields across subgraphs, turning minimal events into rich, contextual updates.
Cosmo uses NATS to handle event streams. The Router manages subscriptions to NATS subjects, enriches events with data from subgraphs, and streams complete GraphQL subscription responses to clients.
Persisted operations are pre-registered GraphQL queries. When enforcement is enabled, the Cosmo Router only accepts these trusted operations, reducing the attack surface and preventing unknown operations from running.

Vincent Vermersch
CTO at NéMo
Vincent Vermersch is the CTO at NéMo, the mobility app for everything except cars. He has been building SaaS products since 2002, focusing on data-driven solutions in the marketing and e-commerce industries. Vincent is a practitioner of Event Sourcing, Event Modeling, and Wardley Mapping.