Skip to main content

Framework Integrations

socket-serve works seamlessly with all major backend frameworks. Choose your framework below for detailed setup instructions.

Supported Frameworks

Quick Comparison

FrameworkBest ForRuntimeDeployment
Next.jsReact apps, VercelNode.js / EdgeVercel, Netlify
ExpressTraditional appsNode.jsAny Node host
HonoEdge computingEdge / Node.jsCloudflare Workers, Vercel
FastifyHigh performanceNode.jsAny Node host, Docker

Common Patterns

SSE Connection Handler

All frameworks need to handle Server-Sent Events (SSE) connections:
// Pattern for all frameworks
async function handleSSE(sessionId: string, send: (data: any) => void) {
  // 1. Set SSE headers
  headers['Content-Type'] = 'text/event-stream';
  headers['Cache-Control'] = 'no-cache';
  headers['Connection'] = 'keep-alive';
  
  // 2. Send session ID
  send({ type: 'session', sessionId });
  
  // 3. Handle connection
  await socketServer.handleConnect(sessionId, { send });
  
  // 4. Setup heartbeat
  const heartbeat = setInterval(() => {
    send(': heartbeat\n\n');
  }, 30000);
  
  // 5. Cleanup on close
  onClose(() => {
    clearInterval(heartbeat);
    socketServer.handleDisconnect(sessionId);
  });
}

POST Message Handler

async function handleMessage(sessionId: string, event: string, data: any) {
  if (!sessionId) {
    throw new Error('Session ID required');
  }
  
  await socketServer.handleMessage(sessionId, event, data);
  return { success: true };
}

Framework-Specific Examples

Next.js (App Router)

// app/api/socket/[[...path]]/route.ts
import { SocketServer } from 'socket-serve/server';

const server = new SocketServer({
  redisUrl: process.env.REDIS_URL!
});

export async function GET(req: Request) {
  // SSE connection
}

export async function POST(req: Request) {
  // Message handling
}
Full Next.js Guide →

Express

// server.js
import express from 'express';
import { SocketServer } from 'socket-serve/server';

const app = express();
const socketServer = new SocketServer({
  redisUrl: process.env.REDIS_URL!
});

app.get('/socket', async (req, res) => {
  // SSE connection
});

app.post('/socket', async (req, res) => {
  // Message handling
});
Full Express Guide →

Hono (Edge)

// src/index.ts
import { Hono } from 'hono';
import { SocketServer } from 'socket-serve/server';

const app = new Hono();
const socketServer = new SocketServer({
  redisUrl: process.env.REDIS_URL!
});

app.get('/socket', async (c) => {
  // SSE connection
});

app.post('/socket', async (c) => {
  // Message handling
});
Full Hono Guide →

Fastify

// server.ts
import Fastify from 'fastify';
import { SocketServer } from 'socket-serve/server';

const fastify = Fastify({ logger: true });
const socketServer = new SocketServer({
  redisUrl: process.env.REDIS_URL!
});

fastify.get('/socket', async (request, reply) => {
  // SSE connection
});

fastify.post('/socket', async (request, reply) => {
  // Message handling
});
Full Fastify Guide →

Universal Client Code

The client works the same regardless of backend framework:
import { connect } from 'socket-serve/client';

const socket = connect('http://localhost:3000/socket');

socket.on('connect', () => {
  console.log('Connected!');
});

socket.emit('message', { text: 'Hello!' });

socket.on('message', (data) => {
  console.log('Received:', data);
});

Authentication Patterns

JWT Authentication

import { verify } from 'jsonwebtoken';

export async function GET(req: Request) {
  const token = req.headers.get('authorization')?.replace('Bearer ', '');
  const user = verify(token!, process.env.JWT_SECRET!);
  
  // Use user in socket
}

CORS Configuration

// next.config.js
module.exports = {
  async headers() {
    return [{
      source: '/api/socket/:path*',
      headers: [
        { key: 'Access-Control-Allow-Origin', value: '*' },
        { key: 'Access-Control-Allow-Methods', value: 'GET, POST' }
      ]
    }];
  }
};

Rate Limiting

import { Ratelimit } from '@upstash/ratelimit';
import { Redis } from '@upstash/redis';

const ratelimit = new Ratelimit({
  redis: Redis.fromEnv(),
  limiter: Ratelimit.slidingWindow(10, '10 s')
});

export async function POST(req: Request) {
  const ip = req.headers.get('x-forwarded-for');
  const { success } = await ratelimit.limit(ip!);
  
  if (!success) {
    return new Response('Rate limit exceeded', { status: 429 });
  }
  
  // Handle message
}

Deployment Targets

Vercel

  • Next.js (recommended)
  • Hono
  • Express (with adapters)

Cloudflare Workers

  • Hono (recommended)
  • Next.js Pages Functions (limited)
  • Express and Fastify not supported

Traditional Hosts (AWS, DigitalOcean, etc.)

  • Express
  • Fastify
  • Next.js standalone
  • Hono

Docker

  • Express
  • Fastify
  • Next.js standalone
  • Hono

Performance Comparison

Based on benchmarks with 1000 concurrent connections:
FrameworkReq/secLatency (p95)Memory
Hono (Edge)15,00012ms80MB
Fastify12,00015ms120MB
Express8,00025ms150MB
Next.js7,00030ms180MB
Note: Performance varies based on configuration and deployment platform

Choosing the Right Framework

Use Next.js if you’re:

  • Building a React application
  • Deploying to Vercel
  • Using SSR or SSG features
  • Want integrated routing and API routes

Use Express if you’re:

  • Working with an existing Express codebase
  • Need broad middleware ecosystem support
  • Prefer traditional Node.js patterns
  • Running on traditional servers

Use Hono if you’re:

  • Deploying to edge runtimes
  • Need lightweight and fast performance
  • Targeting Cloudflare Workers
  • Want minimal dependencies

Use Fastify if you’re:

  • Building high-performance APIs
  • Need built-in schema validation
  • Prefer modern Node.js patterns
  • Creating microservices

Migration Guide

From Socket.IO

socket-serve provides a similar API to Socket.IO:
// Socket.IO
io.on('connection', (socket) => {
  socket.emit('welcome', { msg: 'hi' });
  socket.on('chat', (data) => {
    io.emit('chat', data);
  });
});

// socket-serve
socketServer.onConnect((socket) => {
  socket.emit('welcome', { msg: 'hi' });
});
socketServer.onMessage('chat', async (socket, data) => {
  await socket.broadcast('chat', data);
});
Key differences:
  • All operations are async/await
  • Uses Redis for state (required)
  • No WebSocket requirement
  • HTTP-based transport

Troubleshooting

SSE Not Working

Check headers are correct:
'Content-Type': 'text/event-stream'
'Cache-Control': 'no-cache'
'Connection': 'keep-alive'

Connection Drops

Implement heartbeat:
setInterval(() => {
  send(': heartbeat\n\n');
}, 30000);

CORS Errors

Enable CORS for your domain:
'Access-Control-Allow-Origin': 'https://yourdomain.com'
'Access-Control-Allow-Methods': 'GET, POST'

Next Steps

Choose your framework and follow the detailed guide: