Coming from Socket.io

Concept mapping

Socket.iosvelte-realtime
io.emit('event', data)ctx.publish(topic, event, data)
socket.on('event', cb)$live/module store subscription
io.to(room).emit(...)Topic-scoped publishing
RoomsTopics (first arg to live.stream())
socket.join(room)Automatic on stream subscription
Middleware (io.use())upgrade() + guard()
AcknowledgementsRPC return values
socket.broadcast.emit(...)ctx.publish() (always broadcasts)
NamespacesSeparate files in src/live/
socket.idctx.user.id (from upgrade())

Side-by-side: Chat app

Socket.io

// Server
const io = require('socket.io')(server);

io.use((socket, next) => {
  const token = socket.handshake.auth.token;
  const user = verifyToken(token);
  if (!user) return next(new Error('unauthorized'));
  socket.user = user;
  next();
});

io.on('connection', (socket) => {
  socket.join('chat');

  socket.on('sendMessage', (text, callback) => {
    const msg = { id: Date.now(), text, userId: socket.user.id };
    io.to('chat').emit('newMessage', msg);
    callback(msg);
  });
});
// Client
const socket = io({ auth: { token } });

socket.on('newMessage', (msg) => {
  messages = [...messages, msg];
});

socket.emit('sendMessage', text, (response) => {
  console.log('sent:', response);
});

34 lines. Manual event wiring, callback-based acknowledgements, manual room management.

svelte-realtime

// src/live/chat.js
import { live } from 'svelte-realtime/server';

export const sendMessage = live(async (ctx, text) => {
  const msg = { id: crypto.randomUUID(), text, userId: ctx.user.id };
  ctx.publish('messages', 'created', msg);
  return msg;
});

export const messages = live.stream('messages', () => [], {
  merge: 'crud', key: 'id'
});
<script>
  import { sendMessage, messages } from '$live/chat';
</script>

{#each $messages as msg (msg.id)}
  <p>{msg.text}</p>
{/each}

17 lines. No event listeners, no callbacks, no room management. The stream is a Svelte store.

Key differences

  • No event names. Socket.io requires matching string event names between emit and on. svelte-realtime uses typed imports - typos are caught by the bundler.
  • No manual rooms. Topics are automatic. Subscribe to a stream and you’re in the room.
  • RPC, not callbacks. sendMessage(text) returns a promise. No callback argument, no acknowledgement protocol.
  • Merge strategies. Socket.io gives you raw events - you manage state yourself. svelte-realtime merges events into stores automatically.

Migration steps

  1. Replace io.use() middleware with upgrade() in hooks.ws.js
  2. Replace socket.on('event', cb) listeners with live.stream() subscriptions
  3. Replace socket.emit('event', data, cb) with live() RPC calls
  4. Replace io.to(room).emit() with ctx.publish(topic, event, data)
  5. Remove all client-side event listener boilerplate - $live/* stores handle it

Was this page helpful?