WebSockets on Render

Send and receive data in real time.

The WebSocket protocol enables real-time, bi-directional data streaming between a client and server. It's commonly used for app features like text chat, financial dashboards, and AI voice assistants:

Diagram showing WebSocket messages between a client and a server

Render web services can accept inbound WebSocket connections from the public internet. Additionally, service types besides static sites can initiate outbound WebSocket connections over both the public internet and your private network.

Web service setup

In your web service code, you usually extend your existing HTTP server framework with WebSocket support. For example, in Node.js it's common to use the ws module with the Express framework to enable WebSocket connections.

See basic examples for some popular frameworks below, and consult your framework's documentation for additional details.

This example uses Express along with the ws module:

This example uses FastAPI's built-in WebSocket support:

This example uses the Django Channels framework. Note that you'll need to run your Django app with an ASGI-compatible server like Daphne or Uvicorn.

This example uses the Rails Action Cable framework:

Action Cable serves WebSocket connections at /cable by default.

Connecting from clients

After you deploy WebSocket capabilities to your web service, you can start initiating connections from client code.

To test quickly, you can install the websocat command-line tool to connect directly from your terminal:

Always use the wss protocol for WebSocket connections over the public internet.

If you use ws, most WebSocket clients fail when Render responds to their "handshake" request with a 301 code (attempting to redirect to TLS).

For local server testing and connections over your private network, use ws.

Here's a simple Node.js client that connects to a Render-hosted WebSocket server:

Regardless of your language or framework, all you need to do is specify your web service's public URL (custom domains work great), including the path for your WebSocket server.

Maintaining connections

Render does not enforce a maximum duration for WebSocket connections. However, a variety of factors can cause a connection to be interrupted (instance shutdowns, network issues, platform maintenance, and so on).

To maintain active connections and detect stale ones, your web service and its connected clients should periodically send each other keepalive messages. The WebSocket protocol defines special ping and pong control frames specifically for this purpose. When one side sends a ping, the other side should respond with a pong:

Diagram showing WebSocket ping and pong messages

Many WebSocket libraries automatically handle pong responses, so you usually only need to implement ping logic on each side.

Server-side pings

On the server side, periodic pings help you detect stale connections as early as possible. This helps you free up resources to maintain performance.

The example below extends the earlier Express example to add a basic "heartbeat" using ping. The same concepts apply to other languages and frameworks.

Adapted with appreciation from the ws README

Client-side reconnects

Your clients should include logic to reconnect to your service in the event of an interruption. This logic should account for both "graceful" disconnects (such as your service closing the connection due to an instance shutdown) and unexpected errors (such as the connection becoming stale due to a network issue).

Reconnection logic should use exponential backoff to avoid overwhelming the server if it's in a degraded state.

Clients are not guaranteed to reconnect to the same instance after a disruption.

Render's load balancer assigns each incoming WebSocket connection to a random instance of your service, regardless of past connection history.

The longer example below demonstrates client-side reconnection logic with exponential backoff in Node.js. The same concepts apply to other languages and frameworks.

Handling instance shutdown

Render periodically swaps out your web service's running instances. This occurs most commonly when you deploy a new version of your service, and it also happens as part of standard platform maintenance.

As part of shutting down an instance, Render sends it a SIGTERM signal and gives it a 30-second window to shut down gracefully. You can extend this window to a maximum of 300 seconds by setting a shutdown delay.

Does your use case require a shutdown delay longer than 300 seconds?

Please reach out to our support team in the Render Dashboard.

During the shutdown window, you can gracefully close any open WebSocket connections and optionally send clients a message specific to this scenario. You can also save any relevant session state.

Saving session state

If a WebSocket connection is interrupted and your service instance has been storing state relevant to that client, you can save that state to a Render Key Value instance or other shared storage:

This way, if the client reconnects, whichever instance it connects to can fetch the saved state and resume the session.

If you use this pattern, you can set a TTL for saved session state to automatically invalidate it after it's no longer needed.

FAQ

Can I receive WebSocket connections on a different port from other HTTP requests?

Not over the public internet. All public internet traffic to your web service is routed to a single port (the default port is 10000). This includes WebSocket connections, which start as HTTP requests that are then upgraded.

You can receive WebSocket connections on a different port over your private network. However, this is limited to connections from your other Render services in the same region.

How long can a WebSocket connection stay open?

Until the connected instance shuts down. Render doesn’t impose a fixed timeout for WebSocket connections, but they close automatically when the instance is replaced (for example, during a deploy).

For details, see Maintaining connections.

Do WebSocket messages count as outbound bandwidth usage?

Some of them do. Outbound WebSocket messages from your services over the public internet count as outbound bandwidth usage.

Inbound messages and private network connections do not count as outbound bandwidth usage.

Is there a limit on the number of open WebSocket connections a service can have?

No. However, a large number of connections can strain your instance's compute resources, resulting in degraded performance.

To handle more connections, you can upgrade to a larger instance type or scale to multiple instances:

  • Larger instance types have more RAM and CPU, which enables each instance to handle more connections.
  • Scaling your service horizontally enables you to distribute connections across multiple instances, reducing the load on each.
    • When a client initiates a WebSocket connection, Render's load balancer assigns it to one of your service's instances at random.