Manual Setup
Starting from a SvelteKit project. If you don’t have one yet:
npx sv create my-app && cd my-app && npm install 1. Install
npm install svelte-adapter-uws svelte-realtime
npm install uNetworking/uWebSockets.js#v20.60.0
npm install -D ws | Package | Purpose |
|---|---|
svelte-adapter-uws | SvelteKit adapter that runs on uWebSockets.js with WebSocket support |
svelte-realtime | RPC + streams on top of the adapter |
uWebSockets.js | Native C++ HTTP/WebSocket server (from GitHub, not npm) |
ws | Dev-only WebSocket polyfill for npm run dev |
2. Configure the adapter
// svelte.config.js
import adapter from 'svelte-adapter-uws';
export default {
kit: {
adapter: adapter({ websocket: true })
}
}; 3. Add Vite plugins
// vite.config.js
import { sveltekit } from '@sveltejs/kit/vite';
import uws from 'svelte-adapter-uws/vite';
import realtime from 'svelte-realtime/vite';
export default {
plugins: [sveltekit(), uws(), realtime()]
}; All three plugins are required.
4. Create the WebSocket hooks file
// src/hooks.ws.js
import { createMessage } from 'svelte-realtime/server';
export function upgrade({ cookies }) {
return { id: crypto.randomUUID() };
}
export const message = createMessage(); upgrade runs on every new WebSocket connection. Return user data to attach to the connection, or false to reject it. createMessage() creates the handler that routes WebSocket messages to your src/live/ functions.
This file is required. Without it, all RPC calls silently time out.
5. Write a server function
Create src/live/ and add a file:
// src/live/chat.js
import { live, LiveError } from 'svelte-realtime/server';
export const sendMessage = live(async (ctx, text) => {
if (!ctx.user) throw new LiveError('UNAUTHORIZED', 'Login required');
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'
}); 6. Use it in a component
<script>
import { sendMessage, messages } from '$live/chat';
let text = $state('');
async function send() {
await sendMessage(text);
text = '';
}
</script>
{#if $messages === undefined}
<p>Loading...</p>
{:else if $messages?.error}
<p>Failed: {$messages.error.message}</p>
{:else}
{#each $messages as msg (msg.id)}
<p>{msg.text}</p>
{/each}
{/if}
<input bind:value={text} />
<button onclick={send}>Send</button> $live/chat is a virtual import. The Vite plugin reads your src/live/chat.js, finds live() and live.stream() exports, and generates client stubs that call them over WebSocket.
Run npm run dev. It works.
Was this page helpful?