Name: Towards AI Legal Name: Towards AI, Inc. Description: Towards AI is the world's leading artificial intelligence (AI) and technology publication. Read by thought-leaders and decision-makers around the world. Phone Number: +1-650-246-9381 Email: pub@towardsai.net
228 Park Avenue South New York, NY 10003 United States
Website: Publisher: https://towardsai.net/#publisher Diversity Policy: https://towardsai.net/about Ethics Policy: https://towardsai.net/about Masthead: https://towardsai.net/about
Name: Towards AI Legal Name: Towards AI, Inc. Description: Towards AI is the world's leading artificial intelligence (AI) and technology publication. Founders: Roberto Iriondo, , Job Title: Co-founder and Advisor Works for: Towards AI, Inc. Follow Roberto: X, LinkedIn, GitHub, Google Scholar, Towards AI Profile, Medium, ML@CMU, FreeCodeCamp, Crunchbase, Bloomberg, Roberto Iriondo, Generative AI Lab, Generative AI Lab VeloxTrend Ultrarix Capital Partners Denis Piffaretti, Job Title: Co-founder Works for: Towards AI, Inc. Louie Peters, Job Title: Co-founder Works for: Towards AI, Inc. Louis-François Bouchard, Job Title: Co-founder Works for: Towards AI, Inc. Cover:
Towards AI Cover
Logo:
Towards AI Logo
Areas Served: Worldwide Alternate Name: Towards AI, Inc. Alternate Name: Towards AI Co. Alternate Name: towards ai Alternate Name: towardsai Alternate Name: towards.ai Alternate Name: tai Alternate Name: toward ai Alternate Name: toward.ai Alternate Name: Towards AI, Inc. Alternate Name: towardsai.net Alternate Name: pub.towardsai.net
5 stars – based on 497 reviews

Frequently Used, Contextual References

TODO: Remember to copy unique IDs whenever it needs used. i.e., URL: 304b2e42315e

Resources

Free: 6-day Agentic AI Engineering Email Guide.
Learnings from Towards AI's hands-on work with real clients.
Why WebSockets don’t scale easily — and how AWS changes the game
Latest   Machine Learning

Why WebSockets don’t scale easily — and how AWS changes the game

Last Updated on July 6, 2026 by Editorial Team

Author(s): Leapfrog Technology

Originally published on Towards AI.

Why WebSockets don’t scale easily — and how AWS changes the game

WebSockets are deceptively simple. Every connected user maintains a persistent connection to the server, and each connection continuously occupies server resources such as memory, CPU cycles, network buffers, and application state. Unlike traditional HTTP requests, WebSocket connections are long-lived and stateful, meaning resource consumption grows almost linearly with the number of users. You can, however, derive a simple mathematical model to introduce the problem.

The fundamental problem

Every active WebSocket connection consumes server resources. For each connection, a Node.js process maintains:

  • A TCP socket
  • Read/write buffers
  • Event listeners
  • User session metadata
  • Heartbeat/ping state

So:
Total Memory=N×Mc
where

  • N = number of concurrent users
  • Mc​ = memory consumed per connection

Resource usage assumptions for 1000 concurrent users establishing WebSocket connections

The following estimates assume:

  • 1,000 simultaneously connected clients
  • Clients are mostly idle (heartbeat/ping messages only)
  • Small text messages (less than 1 KB)
  • No large binary payloads
  • One Node.js process
  • Linux server
  • TLS termination handled separately (or already accounted for)
  • Figures represent application memory only, not total system memory

(These are realistic ballpark figures (actual values vary by implementation).

Resource Usage for Raw WebSocket (ws node.js package) implementation

The ws library is a lightweight implementation that exposes the WebSocket protocol with minimal abstraction.

Typical per-connection memory consumption:

Memory:

1000 × 30KB = 30,0000KB
29 MB

Resource Usage for Socket.IO package implementation

Socket.IO builds on top of WebSockets (via Engine.IO) and adds higher-level functionality such as

  • Engine.IO layer
  • Rooms
  • Acknowledgements
  • Automatic reconnection
  • Packet encoding
  • Additional metadata

Typical per-connection memory consumption:

Memory:

1000 × 600KB = 60,000KB
58 MB

Visual comparison

This is approximately linear growth:

Memory Number of Connections

But memory isn’t the real problem

Memory is only one dimension. Suppose an EC2 instance has:

  • 2 GB RAM
  • 1 vCPU

If your application itself consumes:

  • 500 MB for Node.js application code
  • 200 MB for caches
  • 300 MB OS overhead

Available for WebSockets:

2GB − 1GB = 1GB

Using raw WebSockets:

1000MB ÷ 30KB ≈ 34,000 theoretical connections

Using Socket.IO:

1000MB ÷ 60KB ≈ 17,000 theoretical connections

In reality, CPU, network bandwidth, and event-loop latency become bottlenecks much earlier (often around 5k — 20k connections per Node process depending on message frequency).

The scalability challenge

The issue isn’t serving 1,000 users. The issue is serving 100,000 users.

If one server holds 10,000 persistent connections:

100,000 ÷ 10,000 = 10 servers

Now you must manage:

  • Load balancing
  • Sticky sessions
  • Cross-instance pub/sub
  • Connection failover
  • Redis adapters
  • Auto scaling

At that point, WebSockets become a distributed systems problem rather than a networking problem.

Scaling WebSockets with Node.js, Nginx, and Redis Pub/Sub

To move beyond a single-server bottleneck, WebSocket connections are typically distributed across multiple Node.js instances running in a cluster behind a reverse proxy like Nginx.

Figure: High-Level Architecture supporting scalable WebSocket with Redis Backplane.

At a high level, the architecture looks like this:

  • Nginx handles incoming WebSocket upgrades and load balances connections across Node.js upstream servers.
  • Each Node.js instance manages only a subset of active connections.
  • A Redis Pub/Sub layer synchronizes messages across all instances.

This solves a key limitation: WebSocket connections are stateful, so without coordination, one server cannot notify clients connected to another server.

We can model the scaling behavior as:

N = n_1 + n_2 + n_3 + … + n_k

Where:

  • N = total concurrent connections
  • n_k = connections handled by each Node.js instance

If each instance supports ~10,000 connections:

100,000 users ≈ 10 Node instances

However, connection distribution alone is not enough. Message propagation requires cross-instance communication:

Client A → Node A → Redis Pub/Sub → Node B, Node C → Clients

So Redis acts as the “event backbone”, ensuring messages reach all subscribed instances regardless of which server holds the original socket.

In practice, the system scales in two dimensions:

  • Vertical (per node): limited by memory per connection
  • Horizontal (cluster): limited by coordination overhead (Redis + network hops)

This architecture allows WebSockets to scale from thousands to hundreds of thousands of concurrent connections, but introduces a new tradeoff: distributed complexity replaces single-server simplicity.

The operational cost of self-managed WebSocket scaling

Once WebSockets are distributed across multiple Node.js instances with a load balancer and a Redis Pub/Sub backbone, the system becomes functionally scalable but operationally heavy.

At this stage, scaling is no longer just about handling connections; it requires continuous management of infrastructure behavior in real time.

Engineers must now monitor and tune:

  • Connection distribution across nodes (to avoid uneven load)
  • Memory per instance (to prevent socket exhaustion)
  • Redis Pub/Sub throughput and latency
  • Message fan-out patterns across services
  • Network hops introduced by inter-node communication
  • Failure recovery and reconnection storms during outages

In essence, the system shifts from a simple connection model to a continuously evolving distributed system where every component becomes a potential bottleneck.

The AWS approach: Offloading the complexity

Managed AWS WebSocket solutions, such as API Gateway WebSockets, fundamentally change this model by removing the need to manage persistent connection infrastructure directly.

Write on Medium

Instead of maintaining Node.js servers for connection handling, AWS takes responsibility for:

  • Maintaining persistent WebSocket connections at scale
  • Handling connection lifecycle (establish, reconnect, disconnect)
  • Scaling underlying infrastructure automatically
  • Routing messages to connected clients via managed APIs
  • Integrating with backend services through AWS Lambda, SQS, or EventBridge

In this model, engineers no longer manage sockets as infrastructure primitives. Instead, they work with higher-level events:

Client Event →AWS API Gateway → Compute Layer (Lambda / Service) → Event Routing Back to Clients

What this removes from engineering ownership

Moving to AWS-managed WebSockets shifts responsibility away from engineers in several critical areas:

  • No server provisioning or horizontal scaling for WebSocket nodes
  • No load balancer tuning or sticky session management
  • No Redis Pub/Sub coordination layer
  • No manual connection tracking or socket state distribution
  • No handling of connection spikes or reconnection storms
  • No direct memory management per connection

Simple 1-to-1 Chat using AWS API Gateway WebSockets

This is a minimal architecture for building a real-time 1-to-1 chat system using AWS-managed WebSockets. The goal is to avoid managing servers, connection state, or scaling logic manually.

Create a WebSocket API in API Gateway

In AWS API Gateway, create a WebSocket API. You will be asked to define a Route Selection Expression, typically: request.body.action

This means every incoming message is routed based on the action field in the JSON payload.

Figure: Create a WebSocket API (websocket-1–1-chat) in API Gateway with a route selection expression

Figure: Define custom route key (sendMessage) for integration

Once created, API Gateway provides:

  • WebSocket Endpoint
wss://{api-id}.execute-api.{region}.amazonaws.com/{stage}
  • Connection URL (HTTP POST)
https://h7axxxxxxx.execute-api.us-west-2.amazonaws.com/production/@connections

Figure: WebSocket Endpoint and @connection URL endpoint of websocket-1–1-chat API

What they mean:

  • WebSocket Endpoint → used by clients to connect and stay connected in real time
  • Management / POST endpoint → used by backend (Lambda) to send messages to a specific connected client

Understanding Route Keys

API Gateway uses route keys to decide how messages are handled:

Built-in routes:

  • $connect
    Triggered when a client first connects
    → Used for authentication and initialization
  • $disconnect
    Triggered when a client disconnects
    → Used for cleanup
  • $default
    Triggered when no matching route is found
    → Catch-all for messages

Custom route example

If a client sends:

{ "action": "sendMessage", "toUserId": "user_2", "message": "Hello"}

Then API Gateway routes it to:

sendMessage

You must explicitly create this route in API Gateway.

Wire Routes to Lambda Functions

Each route is connected to a Lambda:

This is done in API Gateway → Routes → Attach Integration.

Figure: Attach integrations for $connect, $disconnect, $default and sendMessage route keys

Store Connection IDs in DynamoDB

Every connected client gets a unique: connectionId

During $connect, store this in DynamoDB:

Table: Connections

userIDconnectionsuser_1abc123user_2xyz789

This allows you to map:

userId → connectionId

Without this, you cannot target specific users.

Sending a Message (1-to-1 Flow)

Figure: Flow diagram for API Gateway and Lambda interactions based on route keys

When user_1 sends a message to user_2:

Step 1: User 1 sends a message

{ "action": "sendMessage", "toUserId": "user_2", "message": "Hey!"}

Step 2: Lambda receives the request

The messageHandler Lambda:

  • Reads sender (user_1)
  • Reads recipient (user_2)
  • Looks up user_2 in DynamoDB
  • Retrieves connectionId

Step 3: Forward message using API Gateway Management API

Lambda calls:

POST /@connections/{connectionId}

Payload:

{ "from": "user_1", "message": "Hey!"}

This sends the message directly to user_2’s active WebSocket connection.

$Disconnect Cleanup

When a user disconnects:

  • $disconnect route triggers
  • Remove their connectionId from DynamoDB

This prevents stale connections and ensures accurate routing.

Final architecture flow

User 1 → WebSocket API Gateway → Lambda (sendMessage) → DynamoDB lookup (user_2 connectionId) → API Gateway Management API → User 2 receives message

Figure: Rough sequence diagram representing user_1 sending a message to user_2 involving API Gateway and Lambda Integrations

AWS advantage with a tradeoff

With AWS API Gateway WebSockets, there are:

  • No servers to manage
  • No Redis Pub/Sub required
  • No connection scaling logic
  • No load balancers or sticky sessions

You only define:

  • Routes ($connect, $disconnect, custom actions)
  • Lambda logic
  • Connection storage (DynamoDB)

AWS handles persistent connections, scaling, and delivery infrastructure automatically, allowing you to focus purely on application logic rather than socket management.

The tradeoff

While self-managed architectures offer full control and lower per-request cost at scale, they require deep operational expertise in distributed systems.

AWS-managed WebSockets reduce this burden by abstracting connection management entirely, but in exchange, they introduce constraints in protocol control, cost predictability at extreme scale, and platform dependency.

In practice, the decision is not about capability, but about where you want complexity to live:

  • Self-managed WebSockets: maximum control, maximum operational responsibility
  • AWS-managed WebSockets: reduced control, significantly reduced infrastructure burden

Join thousands of data leaders on the AI newsletter. Join over 80,000 subscribers and keep up to date with the latest developments in AI. From research to projects and ideas. If you are building an AI startup, an AI-related product, or a service, we invite you to consider becoming a sponsor.

Published via Towards AI


Towards AI Academy

We Build Enterprise-Grade AI. We'll Teach You to Master It Too.

15 engineers. 100,000+ students. Towards AI Academy teaches what actually survives production.

Start free — no commitment:

6-Day Agentic AI Engineering Email Guide — one practical lesson per day

Agents Architecture Cheatsheet — 3 years of architecture decisions in 6 pages

Our courses:

AI Engineering Certification — 90+ lessons from project selection to deployed product. The most comprehensive practical LLM course out there.

Agent Engineering Course — Hands on with production agent architectures, memory, routing, and eval frameworks — built from real enterprise engagements.

AI for Work — Understand, evaluate, and apply AI for complex work tasks.

Note: Article content contains the views of the contributing authors and not Towards AI.