# WebSockets

WebSockets are available in [Beta](/content/docs/release-phases#beta/index.html) on [all plans](/content/docs/plans/index.html).

Vercel Functions can serve WebSocket connections, keeping a bidirectional connection open between a client and your server-side code. Use WebSockets for realtime features such as interactive AI streaming, chat, and collaborative apps.

A single WebSocket connection is pinned to one Vercel Function instance. Messages sent over that connection reach the same function instance for the lifetime of the connection, and Fluid compute allows a single function instance to handle multiple WebSocket connections.

[View and deploy a starter template](/content/templates/nitro/nitro-websockets-starter/index.html).

## Request lifecycle

A WebSocket connection starts as an HTTP `GET` request with an `Upgrade` header. Before the connection is upgraded, the request goes through the same routing and security controls as other requests to Vercel Functions, including Routing Middleware, rewrites, Firewall rules, and rate limits.

After the upgrade succeeds, messages sent over the WebSocket connection are delivered to the Vercel Function instance that accepted the connection.

## Set up a WebSocket endpoint

WebSockets in Vercel Functions work exactly like any distributed WebSocket server, so you can use libraries like `ws` to upgrade connections with no additional configuration:

```javascript
import http from 'http';
import { WebSocketServer } from 'ws';

const server = http.createServer();
const wss = new WebSocketServer({ server });

wss.on('connection', (ws) => {
  ws.on('message', (data) => {
    ws.send(data);
  });
});

export default server;
```

You can also use higher-level realtime libraries like [Socket.IO](https://socket.io/) with a client configured to use the WebSocket transport directly:

```javascript
import http from 'http';
import { Server } from 'socket.io';

const server = http.createServer();
const io = new Server(server);

io.on('connection', (socket) => {
  socket.on('message', (data) => {
    socket.send(data);
  });
});

export default server;
```

### Client code

```javascript
import { io } from 'socket.io-client';

const socket = io('https://your-domain.com', {
  path: '/api/socket-io/socket.io',
  transports: ['websocket'], // required — Socket.IO defaults to HTTP long-polling
});
```

Python applications can use [`python-socketio`](https://pypi.org/project/python-socketio/) with Asynchronous Server Gateway Interface (ASGI) or Web Server Gateway Interface (WSGI) applications. See the [`python-socketio` server documentation](https://python-socket.io/docs/) for setup options. Flask applications can use [`Flask-SocketIO`](https://pypi.org/project/Flask-SocketIO/) for a Flask-specific integration. See the [Flask-SocketIO documentation](https://flask-socketio.readthedocs.io/en/latest/) for configuration details. These libraries implement the Socket.IO protocol, so clients must use a compatible Socket.IO client.

## Handle disconnections and reconnects

WebSocket connections close when a Vercel Function reaches its [maximum duration](/content/docs/functions/limitations#max-duration/index.html).

Follow WebSocket client best practices by handling reconnects when a connection closes. Reconnect logic should recreate the connection, resubscribe to any channels or topics, and reload any state the client needs to continue.

### Client reconnect code

```javascript
let socket;
let reconnectDelay = 1000;

function connect() {
  socket = new WebSocket('wss://your-domain.com/api/ws');

socket.addEventListener('open', () => {
    reconnectDelay = 1000;
  });

socket.addEventListener('message', (event) => {
    console.log(event.data);
  });

socket.addEventListener('close', () => {
    setTimeout(connect, reconnectDelay);
    reconnectDelay = Math.min(reconnectDelay * 2, 30000);
  });
}

connect();
```

## Manage persistent state

New WebSocket connections are not guaranteed to reach the same Vercel Function instance. Store durable state, presence, counters, rooms, and pub/sub coordination in an external data store instead of relying on in-memory variables. For example, you can use [Redis from the Vercel Marketplace](/content/marketplace/redis/index.html) to share state across function instances and deployments.

## Use with frameworks

Frameworks with native WebSocket support can serve WebSocket connections on Vercel Functions without additional Vercel-specific configuration. Choose the example that matches your framework.

### Bun

Vercel Functions using the [Bun runtime](/content/docs/functions/runtimes/bun/index.html) support the native `Bun.serve()` WebSocket API. Call `server.upgrade()` from the `fetch` handler:

```javascript
Bun.serve({
  fetch(request, server) {
    if (server.upgrade(request)) {
      return;
    }

return new Response('Expected a WebSocket connection', { status: 400 });
  },
  websocket: {
    message(socket, message) {
      socket.send(message);
    },
  },
});
```

### Node.js server frameworks

Node.js server frameworks such as Express, Hono, and h3 can also serve WebSocket connections on Vercel:

```javascript
import { serve, upgradeWebSocket } from '@hono/node-server';
import { Hono } from 'hono';
import { WebSocketServer } from 'ws';

const app = new Hono();

app.get('/ws', upgradeWebSocket(() => ({
  onMessage(event, ws) {
    ws.send(event.data);
  },
}));

const wss = new WebSocketServer({ noServer: true });

const server = serve({
  fetch: app.fetch,
  websocket: { server: wss },
});

export default server;
```

### Nitro

Nitro has native WebSocket support powered by [crossws](https://crossws.h3.dev/guide). Enable WebSockets in your Nitro config:

```typescript
import { defineConfig } from 'nitro';

export default defineConfig({
  features: {
    websocket: true,
  },
});
```

### Next.js

Next.js does not expose an API for handling WebSocket upgrades. As a workaround, you can use the `experimental_upgradeWebSocket()` API:

```javascript
import {
  experimental_upgradeWebSocket,
  type WebSocketData,
} from '@vercel/functions';

export async function GET() {
  return experimental_upgradeWebSocket((ws) => {
    ws.on('message', (data: WebSocketData) => {
      ws.send(data);
    });
  });
}
```

## Limits and pricing

WebSocket connections use Vercel Functions and follow the same [limits](/content/docs/functions/limitations/index.html) and [pricing model](/content/docs/functions/usage-and-pricing/index.html) as other Function invocations. WebSockets require [Fluid compute](/content/docs/fluid-compute/index.html) to be enabled. This is the default for new projects created on or after April 23, 2025.

## Last updated August 10, 2026
