Talk to an Engineer
Back to Writing
•12 min read•
Vercel WebSocketsrealtime SaaS architectureNext.js WebSocketsconnection recoveryproduction readiness

Vercel WebSockets Are GA: A Realtime SaaS Architecture Guide

A dark realtime SaaS architecture showing clients connecting through a socket layer to durable shared state

Realtime features are deceptively easy to demo.

A browser opens a socket, the server echoes a message, and two tabs update at once. The difficult work begins when a customer changes networks, a deployment replaces the server, two messages arrive out of order, or one user tries to subscribe to another tenant's room.

On October 20, 2026, Vercel made WebSocket support in Vercel Functions generally available. The official announcement says the connections follow normal Function limits and pricing, with CPU billed only while code processes messages.

That removes an important hosting constraint for Next.js and other SaaS teams on Vercel. It does not remove the distributed-systems decisions behind a reliable realtime product.

The useful question is not, “Can this app use WebSockets now?” It is:

Does this customer workflow need a bidirectional live connection, and can the product recover when that connection disappears?

What Vercel WebSockets Actually Change

Vercel Functions can now accept a WebSocket upgrade and keep a two-way connection open between the client and server. Vercel's WebSockets documentation says support is available on all plans and requires Fluid compute.

Each accepted connection remains pinned to the Function instance that accepted it. Multiple connections can share an instance, but a reconnect is not guaranteed to reach the same one. A connection also closes when that Function reaches its maximum duration.

Those properties define the architecture:

  • the socket instance is a temporary delivery endpoint, not the database;
  • a client must reconnect, resubscribe, and restore state;
  • durable rooms, presence, counters, and pub/sub coordination need an external store;
  • a deployment can leave old and new application versions serving connections at the same time.

General availability means the platform capability is ready for production use. It does not make in-memory state durable or turn an uninterrupted connection into a product guarantee.

That distinction is familiar from background work. A queue transports a job but does not define the business outcome. A WebSocket transports live messages but should not become the only record of what happened. The SaaS background jobs guide applies the same principle: delivery mechanisms and authoritative state need separate contracts.

Choose the Smallest Transport That Fits the Workflow

Do not start with a protocol. Start with the direction, frequency, and consequence of the product interaction.

Use ordinary HTTP when the user asks and the server answers

Form submissions, settings changes, search requests, and most dashboard actions remain easier to authorize, retry, cache, observe, and test as request-response operations.

Polling can also be enough when a few seconds of delay is acceptable. A billing export that finishes in the background rarely needs a live socket. Polling a status endpoint every few seconds may be simpler and more resilient.

Use server-sent events for one-way live delivery

If the client sends one request and then receives a stream of updates, Server-Sent Events can be the smaller design. Typical examples include AI token streaming, progress logs, notifications, and a job-status feed.

Vercel's WebSocket versus SSE guide recommends SSE when data flows from server to client and WebSockets when the client also sends a continuous stream. Browser EventSource also includes a reconnection model and can resume from a Last-Event-ID when the server implements it.

Use WebSockets when both sides need an ongoing channel

Collaborative cursors, multiplayer state, live editing operations, typing indicators, voice or device control, and some agent interfaces genuinely need frequent client-to-server and server-to-client messages.

Even then, separate ephemeral signals from durable commands. A cursor position can disappear without damaging customer data. A document edit, approval, payment action, or workflow transition must survive disconnection and be confirmed through durable state.

A useful MVP rule is simple: if periodic refresh still completes the customer's job, validate the workflow before paying the complexity tax of realtime infrastructure.

Keep Durable Truth Outside the Connection

The most common early mistake is to store rooms, presence, pending changes, or counters only in the process that owns the socket.

That works in a single local server. It fails when traffic reaches multiple instances, when an instance ends, or when a reconnect lands elsewhere. Vercel explicitly recommends an external data store for state shared across instances and deployments.

Split the design into three layers:

  1. Authoritative state. Documents, messages, memberships, workflow status, and permissions live in the primary database or another durable system of record.
  2. Coordination state. Channel membership, presence leases, fan-out, and short-lived counters can live in a shared realtime store or pub/sub system.
  3. Connection state. Subscriptions, heartbeat timestamps, and send buffers live with the socket and may disappear at any time.

The socket should carry a notification that state changed, an operation that can be validated and committed, or an ephemeral signal with an acceptable loss policy. It should not be the only place an important business event exists.

For example, a collaborative task board can treat pointer movement as ephemeral. Moving a card between workflow columns is different. The server should authorize that command, commit a versioned change, publish the resulting event, and let clients reconcile against the committed board state.

Design Reconnection Before the Happy Path

Every connection will close eventually. Mobile networks change. Laptops sleep. Proxies time out. Functions reach their duration. Deployments replace code.

Vercel's docs require clients to handle disconnections, reconnect, restore subscriptions, and reload the state needed to continue. Treat that as the starting contract, not an edge case.

A practical reconnect flow needs:

  • a session or device identifier that is not treated as authorization by itself;
  • an expiring authentication credential for the new handshake;
  • a channel list the server revalidates on every subscription;
  • a last applied event ID or version for each durable stream;
  • a bounded replay path from that position;
  • a full snapshot fallback when the replay window is unavailable;
  • exponential backoff with jitter so a regional failure does not trigger a reconnect storm.

Do not ask the client to infer whether it missed something. Give each durable event an ID or monotonically increasing version within the scope that matters. On reconnect, the client can say, “I have applied through version 418.” The server can replay later events or return a current snapshot.

This also makes duplicate delivery manageable. If a client retries an operation because the acknowledgement was lost, an idempotency key lets the server return the existing result instead of applying the change twice.

Authenticate the Upgrade, Authorize Every Action

The initial WebSocket upgrade passes through Vercel's routing and security controls, including Middleware, rewrites, Firewall rules, and rate limits. That is useful protection for the connection attempt.

It is not enough for the session that follows.

Authenticate the handshake with a short-lived credential. Then authorize each subscription and consequential message against current tenant membership, role, resource ownership, and operation policy. Do not trust a client-supplied room name such as tenant-123 merely because the socket was accepted.

Define a small message envelope:

type ClientMessage = {
  id: string;
  type: "subscribe" | "task.move" | "presence.update";
  channel: string;
  expectedVersion?: number;
  payload: unknown;
};

Parse it against a runtime schema. Apply payload and message-size limits before expensive work. Rate-limit both upgrade attempts and messages inside an accepted connection. Keep authorization decisions on the server, and recheck long-lived subscriptions when membership changes.

Presence should be a lease, not a permanent row. If a heartbeat stops, expire the presence record. Never depend on a final “user left” message; the browser or network may disappear without sending one.

Control Ordering, Flow, and Backpressure

WebSockets preserve the order of frames on one connection. They do not give your entire product a global event order.

Events can be published by several workers, pass through shared coordination, and reach clients after a reconnect. Two users can edit the same record concurrently. A slow client can also receive messages faster than it processes them.

Choose ordering scope deliberately. A per-document or per-room version is often enough. Requiring a global sequence across every tenant creates cost and contention without helping the workflow.

For durable commands, use optimistic concurrency or another explicit conflict strategy. Reject a stale expectedVersion, return the current version, and let the client refresh or present a conflict. For ephemeral signals, newer state can replace older state: the latest cursor position matters more than delivering every intermediate pixel.

Browser support adds another constraint. MDN's WebSocket API reference notes that the standard WebSocket interface has no built-in backpressure. If incoming messages outrun the application, buffers and CPU use can grow until the page becomes unresponsive.

Bound server queues, cap message sizes, coalesce replaceable updates, and disconnect persistently slow consumers with a recoverable reason. An unbounded per-connection buffer is a memory incident waiting for traffic.

Treat Deployments as a Mixed-Version Period

After a new deployment, existing sockets may remain connected to the old deployment while new clients reach the new one. For some period, both message contracts are live.

Use versioned envelopes and additive changes. A new optional field is safer than changing the meaning of an existing field. Keep the server able to reject unsupported versions clearly, and make the client reconnect or refresh when compatibility cannot be preserved.

For a breaking protocol change:

  1. deploy a server that accepts the old and new contracts;
  2. release clients that prefer the new contract;
  3. measure old-version connections and failures;
  4. drain or explicitly close old connections with a retryable code;
  5. remove compatibility only after the old population is negligible.

This is one place where boring architecture wins. A small, documented protocol with explicit versions is easier to operate than many clever event shapes. The broader reasoning is covered in Why I Prefer Boring Architecture for SaaS.

Measure Cost and Customer Outcomes Together

WebSockets follow Vercel Function pricing, including Active CPU, Provisioned Memory, invocations, and data transfer. Vercel's Fluid compute pricing documentation explains that CPU billing pauses during I/O waits, while provisioned memory remains billable for the Function instance's lifetime.

An idle socket may use little CPU, but it can keep memory provisioned. One instance can handle multiple concurrent connections, so the cost per connection depends on density, message rate, memory configuration, region, and connection duration. Do not estimate it from connection count alone.

Track at least:

  • accepted and rejected upgrades;
  • active connections by region, tenant, and protocol version;
  • reconnect rate and time to successful resynchronization;
  • messages in, messages out, and bytes transferred;
  • authorization failures and rate-limit events;
  • queue depth, dropped or coalesced messages, and slow-consumer disconnects;
  • replay length, snapshot fallbacks, duplicate operations, and version conflicts;
  • Function CPU, provisioned memory, duration, and cost per completed customer workflow.

The last metric prevents infrastructure success from hiding product failure. A stable connection is not valuable if edits disappear or collaboration becomes confusing. The minimum viable observability guide shows how to organize telemetry around customer outcomes rather than raw platform activity.

A Seven-Step Vercel WebSockets Rollout

  1. Name one realtime outcome. Choose a workflow where bidirectional latency changes what the customer can accomplish.
  2. Compare transports. Test ordinary HTTP, polling, SSE, and WebSockets against direction, frequency, recovery, browser support, and cost.
  3. Define authority. Document which state is durable, which is shared coordination, and which may disappear with the connection.
  4. Write the protocol contract. Version message envelopes, set size limits, define ordering scope, and assign idempotency keys to durable commands.
  5. Build recovery first. Test reconnect, resubscribe, replay, snapshot fallback, token expiry, network changes, and duplicate operations.
  6. Secure every boundary. Authenticate upgrades, authorize channels and commands, rate-limit messages, and expire presence with leases.
  7. Load-test deployment reality. Exercise mixed versions, many idle connections, active bursts, slow consumers, Function-duration closures, and shared-state failure before wider rollout.

When Internal Work Is Enough

A focused internal implementation is reasonable when the feature is narrow, loss is acceptable, the team already operates a shared datastore, and the first release can fall back to refresh or polling.

Get deeper architecture help when realtime behavior controls money, approvals, collaborative documents, safety-sensitive devices, or multi-tenant data; when clients must recover precisely after long offline periods; or when cost depends on high concurrent connection density.

The important threshold is not traffic alone. It is the consequence of lost, duplicated, unauthorized, or conflicting messages.

Related Reading

Next Step

If a realtime feature is moving from demo to product, prepare the workflow, message types, tenant model, expected concurrency, recovery requirements, current data stores, and one failure trace.

A focused custom software development review can turn those inputs into a transport decision and production design that covers authorization, state, reconnects, deployment compatibility, observability, and cost before customers depend on the connection.

Working on a SaaS that's starting to feel fragile?

Talk to an engineer about the parts that break first — without rewriting what already works. We'll recommend focused support or a compact team based on your scope.

Talk to an Engineer