0
0
NestJSframework~15 mins

Subscriptions in NestJS - Deep Dive

Choose your learning style9 modes available
Overview - Subscriptions
What is it?
Subscriptions in NestJS allow your application to send real-time updates to clients. They are often used with GraphQL to push data changes instantly instead of waiting for clients to ask repeatedly. This means clients can listen for events like new messages or data changes and get notified immediately. Subscriptions keep the connection open so updates flow continuously.
Why it matters
Without subscriptions, apps rely on clients asking for updates again and again, which wastes time and resources and feels slow. Subscriptions solve this by pushing updates instantly, making apps feel alive and responsive. This is crucial for chat apps, live dashboards, or any feature needing real-time data. Without it, user experience suffers and servers get overloaded.
Where it fits
Before learning subscriptions, you should understand basic NestJS controllers and services, and how GraphQL queries and mutations work. After mastering subscriptions, you can explore advanced real-time patterns, WebSocket integrations, and scaling real-time features across multiple servers.
Mental Model
Core Idea
Subscriptions keep a live connection open so the server can send updates to clients instantly when data changes.
Think of it like...
Subscriptions are like a newspaper subscription: instead of going to the store daily to check for new papers, the newspaper is delivered to your door as soon as it’s printed.
Client ──► (opens connection) ──► Server
  ▲                             │
  │                             ▼
  ◄───────── Updates pushed ────
Build-Up - 7 Steps
1
FoundationUnderstanding real-time communication basics
🤔
Concept: Learn what real-time communication means and why it differs from regular request-response.
Normally, clients ask servers for data and wait for answers. Real-time means the server can send data anytime without waiting. This requires keeping a connection open, like a phone call instead of letters.
Result
You understand why normal requests can feel slow and why real-time updates improve user experience.
Understanding the difference between asking for data and receiving data automatically is key to grasping subscriptions.
2
FoundationBasics of GraphQL subscriptions in NestJS
🤔
Concept: Introduce how NestJS supports GraphQL subscriptions using WebSockets.
NestJS uses Apollo Server under the hood, which supports subscriptions over WebSocket. You define a subscription resolver method that returns an AsyncIterator, which streams data to clients.
Result
You can write a simple subscription resolver that sends data updates to clients.
Knowing that subscriptions use AsyncIterators helps understand how data streams continuously instead of one-time responses.
3
IntermediateImplementing a subscription resolver
🤔Before reading on: do you think a subscription resolver returns data directly or a stream of data? Commit to your answer.
Concept: Learn to create a subscription resolver method that returns an AsyncIterator to push updates.
In NestJS, you create a method decorated with @Subscription() that returns an AsyncIterator from a PubSub instance. PubSub is a simple event system that lets you publish events and subscribe to them.
Result
Your subscription resolver can push updates to clients whenever you publish an event.
Understanding that subscriptions rely on event streams clarifies how updates flow from server to client.
4
IntermediateUsing PubSub for event management
🤔Before reading on: do you think PubSub stores data or just manages event notifications? Commit to your answer.
Concept: Learn how PubSub acts as a simple event bus to manage subscription events.
PubSub does not store data; it only notifies subscribers when an event happens. You publish events with a name and payload, and subscribers listening to that name receive the payload.
Result
You can trigger subscription updates by publishing events from anywhere in your app.
Knowing PubSub only manages notifications prevents confusion about data storage responsibilities.
5
IntermediateFiltering subscription events by criteria
🤔Before reading on: do you think all subscribers get every event or can events be filtered? Commit to your answer.
Concept: Learn to send updates only to clients interested in specific data using filters.
You can add filter functions to subscription resolvers that check event payloads and decide if a client should receive the update. This avoids sending irrelevant data to clients.
Result
Clients receive only the updates they care about, improving efficiency and user experience.
Filtering events is essential for scalable real-time apps with many clients and diverse data interests.
6
AdvancedScaling subscriptions with Redis PubSub
🤔Before reading on: do you think the default PubSub works across multiple servers? Commit to your answer.
Concept: Learn how to use Redis PubSub to share subscription events across multiple server instances.
The default PubSub in NestJS is in-memory and works only within one server. For multiple servers, use Redis PubSub which broadcasts events through Redis, so all servers can notify their clients.
Result
Your real-time updates work correctly even when your app runs on many servers behind a load balancer.
Understanding the limits of in-memory PubSub helps avoid bugs in distributed systems.
7
ExpertHandling subscription lifecycle and cleanup
🤔Before reading on: do you think subscriptions automatically clean up resources when clients disconnect? Commit to your answer.
Concept: Learn how to manage subscription connections and clean resources to prevent memory leaks.
Subscriptions keep connections open, so you must handle client disconnects and unsubscribe events properly. NestJS allows you to implement lifecycle hooks to clean up AsyncIterators and free memory.
Result
Your app remains stable and efficient even with many clients connecting and disconnecting frequently.
Knowing how to manage subscription lifecycles prevents common production issues like memory leaks and server crashes.
Under the Hood
Subscriptions use WebSocket connections to keep a channel open between client and server. The server uses AsyncIterators to push data streams asynchronously. Internally, a PubSub system manages events by storing subscriber callbacks and invoking them when events are published. This avoids repeated client polling and reduces latency.
Why designed this way?
This design balances efficiency and simplicity. WebSockets provide a persistent connection ideal for real-time data. AsyncIterators fit naturally with JavaScript's async model. PubSub decouples event producers and consumers, making the system modular. Alternatives like HTTP polling were too slow and resource-heavy.
┌─────────┐       WebSocket       ┌─────────┐
│ Client  │──────────────────────▶│ Server  │
└─────────┘                       └─────────┘
     ▲                                │
     │                                ▼
  Receives                      AsyncIterator
  pushed data                      stream
     │                                │
     │                                ▼
  Listens to                   PubSub event
  subscription                 publishes events
Myth Busters - 4 Common Misconceptions
Quick: Do subscriptions send data only once or continuously? Commit to your answer.
Common Belief:Subscriptions send data only once like queries.
Tap to reveal reality
Reality:Subscriptions keep sending data continuously as events happen until the client disconnects.
Why it matters:Thinking subscriptions send data once leads to wrong implementations and missed real-time updates.
Quick: Does the default NestJS PubSub work across multiple servers? Commit to your answer.
Common Belief:The default PubSub works fine in multi-server setups.
Tap to reveal reality
Reality:The default PubSub is in-memory and only works within a single server instance.
Why it matters:Using default PubSub in distributed apps causes missed updates and inconsistent data across clients.
Quick: Do subscriptions automatically clean up when clients disconnect? Commit to your answer.
Common Belief:Subscriptions clean up resources automatically on disconnect.
Tap to reveal reality
Reality:You must explicitly handle cleanup to avoid memory leaks and dangling connections.
Why it matters:Ignoring cleanup causes server memory to grow and eventually crash under load.
Quick: Can subscriptions replace all API calls? Commit to your answer.
Common Belief:Subscriptions can replace queries and mutations entirely.
Tap to reveal reality
Reality:Subscriptions are for real-time updates only; queries and mutations are still needed for initial data and changes.
Why it matters:Misusing subscriptions leads to inefficient and complex APIs that confuse clients.
Expert Zone
1
Subscription resolvers can use context to authenticate and authorize clients before sending updates.
2
Combining filters with dynamic topics allows fine-grained control over who receives which events.
3
Handling backpressure and slow clients is critical to avoid blocking the event stream and degrading performance.
When NOT to use
Avoid subscriptions for simple or rarely changing data where polling is sufficient. For very high-scale systems, consider specialized real-time platforms like Kafka or MQTT instead of WebSocket-based subscriptions.
Production Patterns
Use Redis or other distributed PubSub systems to scale subscriptions. Implement authentication in subscription context. Use filters to minimize data sent. Monitor connection counts and memory usage to detect leaks. Gracefully handle client disconnects and errors.
Connections
Event-driven architecture
Subscriptions build on the event-driven pattern by pushing events to clients.
Understanding event-driven systems helps grasp how subscriptions decouple data producers and consumers for real-time updates.
WebSocket protocol
Subscriptions use WebSocket to maintain persistent connections for data streaming.
Knowing WebSocket basics clarifies how subscriptions keep communication open unlike HTTP requests.
Publish-subscribe pattern in distributed systems
Subscriptions implement the pub-sub pattern to broadcast events to multiple clients.
Recognizing pub-sub as a core messaging pattern explains how subscriptions scale and manage event delivery.
Common Pitfalls
#1Not cleaning up subscription resources on client disconnect.
Wrong approach:asyncIterator.return() is never called; subscriptions stay open indefinitely.
Correct approach:Implement onDisconnect lifecycle hook to call asyncIterator.return() and free resources.
Root cause:Misunderstanding that subscriptions keep connections open and require manual cleanup.
#2Using default in-memory PubSub in a multi-server environment.
Wrong approach:const pubSub = new PubSub(); // used in all servers without shared backend
Correct approach:Use RedisPubSub or similar distributed PubSub to share events across servers.
Root cause:Assuming single-server PubSub works for distributed deployments.
#3Sending all events to all clients without filtering.
Wrong approach:Subscription resolver returns pubSub.asyncIterator('EVENT') without filters.
Correct approach:Add filter function to send events only to interested clients based on payload or context.
Root cause:Not considering client-specific data needs leads to inefficient and noisy updates.
Key Takeaways
Subscriptions keep a live connection open to push real-time updates from server to client.
They rely on WebSocket and AsyncIterators to stream data continuously.
PubSub manages event notifications but requires distributed backends like Redis for multi-server setups.
Proper filtering and lifecycle management are essential for scalable, efficient subscriptions.
Subscriptions complement, not replace, queries and mutations in GraphQL APIs.