0
# WebSocket Links
1
2
Real-time communication through WebSocket connections for subscriptions and bidirectional communication. WebSocket links provide persistent connections for real-time data streaming and notifications.
3
4
## Capabilities
5
6
### wsLink
7
8
Creates a WebSocket transport link for real-time subscriptions and bidirectional communication with tRPC servers.
9
10
```typescript { .api }
11
/**
12
* Creates a WebSocket transport link for real-time communication
13
* @param opts - WebSocket link configuration options
14
* @returns WebSocket transport link for the client chain
15
*/
16
function wsLink<TRouter extends AnyRouter>(
17
opts: WebSocketLinkOptions<TRouter>
18
): TRPCLink<TRouter>;
19
20
interface WebSocketLinkOptions<TRouter extends AnyRouter> {
21
/** WebSocket client instance */
22
client: TRPCWebSocketClient;
23
/** Data transformation configuration */
24
transformer?: inferClientTypes<TRouter>['transformer'];
25
}
26
```
27
28
**Usage Examples:**
29
30
```typescript
31
import { createTRPCClient, wsLink, createWSClient } from "@trpc/client";
32
33
// Basic WebSocket setup
34
const wsClient = createWSClient({
35
url: "ws://localhost:3001",
36
});
37
38
const client = createTRPCClient<AppRouter>({
39
links: [
40
wsLink({
41
client: wsClient,
42
}),
43
],
44
});
45
46
// Subscribe to real-time updates
47
const unsubscribe = client.posts.onUpdate.subscribe(undefined, {
48
onData: (post) => {
49
console.log("Post updated:", post);
50
},
51
onError: (err) => {
52
console.error("Subscription error:", err);
53
},
54
});
55
56
// Clean up when done
57
unsubscribe.unsubscribe();
58
```
59
60
### createWSClient
61
62
Factory function for creating WebSocket clients with connection management, reconnection logic, and configuration options.
63
64
```typescript { .api }
65
/**
66
* Creates a WebSocket client with connection management
67
* @param opts - WebSocket client configuration options
68
* @returns Configured WebSocket client instance
69
*/
70
function createWSClient(opts: WebSocketClientOptions): TRPCWebSocketClient;
71
72
interface WebSocketClientOptions {
73
/** WebSocket server URL */
74
url: string;
75
76
/** WebSocket implementation (for Node.js environments) */
77
WebSocket?: typeof WebSocket;
78
79
/** Retry delay calculation function */
80
retryDelayMs?: (attemptIndex: number) => number;
81
82
/** Connection opened event handler */
83
onOpen?: () => void;
84
85
/** Connection error event handler */
86
onError?: (event?: Event) => void;
87
88
/** Connection closed event handler */
89
onClose?: (cause?: { code?: number }) => void;
90
91
/** Lazy connection configuration */
92
lazy?: LazyOptions;
93
94
/** Keep-alive ping/pong configuration */
95
keepAlive?: KeepAliveOptions;
96
}
97
98
type TRPCWebSocketClient = ReturnType<typeof createWSClient>;
99
```
100
101
**Usage Examples:**
102
103
```typescript
104
import { createWSClient } from "@trpc/client";
105
106
// Basic WebSocket client
107
const wsClient = createWSClient({
108
url: "ws://localhost:3001",
109
});
110
111
// WebSocket client with event handlers
112
const wsClient = createWSClient({
113
url: "ws://localhost:3001",
114
onOpen: () => {
115
console.log("Connected to WebSocket");
116
},
117
onError: (event) => {
118
console.error("WebSocket error:", event);
119
},
120
onClose: (cause) => {
121
console.log("WebSocket closed:", cause?.code);
122
},
123
});
124
125
// Node.js environment with WebSocket polyfill
126
import WebSocket from "ws";
127
128
const wsClient = createWSClient({
129
url: "ws://localhost:3001",
130
WebSocket: WebSocket as any,
131
});
132
133
// Custom retry strategy
134
const wsClient = createWSClient({
135
url: "ws://localhost:3001",
136
retryDelayMs: (attemptIndex) => {
137
// Custom backoff: 1s, 3s, 5s, 10s, then 10s
138
const delays = [1000, 3000, 5000, 10000];
139
return delays[attemptIndex] || 10000;
140
},
141
});
142
```
143
144
### Retry and Backoff
145
146
Configurable retry logic with exponential backoff for handling connection failures.
147
148
```typescript { .api }
149
/**
150
* Default exponential backoff calculation
151
* @param attemptIndex - Zero-based retry attempt index
152
* @returns Delay in milliseconds (0ms → 1s → 2s → 4s ... → 30s max)
153
*/
154
function exponentialBackoff(attemptIndex: number): number;
155
```
156
157
**Retry Examples:**
158
159
```typescript
160
import { createWSClient, exponentialBackoff } from "@trpc/client";
161
162
// Using default exponential backoff
163
const wsClient = createWSClient({
164
url: "ws://localhost:3001",
165
retryDelayMs: exponentialBackoff, // Default behavior
166
});
167
168
// Custom retry logic
169
const wsClient = createWSClient({
170
url: "ws://localhost:3001",
171
retryDelayMs: (attemptIndex) => {
172
if (attemptIndex === 0) return 0; // Immediate first retry
173
if (attemptIndex < 3) return 1000; // 1s for first 3 attempts
174
if (attemptIndex < 6) return 5000; // 5s for next 3 attempts
175
return 15000; // 15s for subsequent attempts
176
},
177
});
178
179
// Aggressive retry for critical connections
180
const wsClient = createWSClient({
181
url: "ws://localhost:3001",
182
retryDelayMs: (attemptIndex) => Math.min(500 * attemptIndex, 5000),
183
});
184
```
185
186
### Lazy Connections
187
188
Lazy connection management that automatically opens and closes WebSocket connections based on activity.
189
190
```typescript { .api }
191
interface LazyOptions {
192
/** Enable lazy connection mode */
193
enabled: boolean;
194
/** Close connection after this many milliseconds of inactivity */
195
closeMs: number;
196
}
197
198
/** Default lazy connection configuration */
199
const lazyDefaults: LazyOptions = {
200
enabled: false,
201
closeMs: 0,
202
};
203
```
204
205
**Lazy Connection Examples:**
206
207
```typescript
208
// Enable lazy connections with 30-second timeout
209
const wsClient = createWSClient({
210
url: "ws://localhost:3001",
211
lazy: {
212
enabled: true,
213
closeMs: 30000, // Close after 30s of inactivity
214
},
215
});
216
217
// Lazy connections for mobile apps (battery optimization)
218
const wsClient = createWSClient({
219
url: "ws://localhost:3001",
220
lazy: {
221
enabled: true,
222
closeMs: 10000, // Aggressive 10s timeout for mobile
223
},
224
});
225
```
226
227
### Keep-Alive Configuration
228
229
Ping/pong keep-alive mechanism to maintain WebSocket connections and detect connection issues.
230
231
```typescript { .api }
232
interface KeepAliveOptions {
233
/** Enable keep-alive ping/pong */
234
enabled: boolean;
235
/** Send ping every this many milliseconds */
236
intervalMs?: number;
237
/** Timeout for pong response in milliseconds */
238
pongTimeoutMs?: number;
239
}
240
241
/** Default keep-alive configuration */
242
const keepAliveDefaults: KeepAliveOptions = {
243
enabled: false,
244
pongTimeoutMs: 1000,
245
intervalMs: 5000,
246
};
247
```
248
249
**Keep-Alive Examples:**
250
251
```typescript
252
// Enable keep-alive with default settings
253
const wsClient = createWSClient({
254
url: "ws://localhost:3001",
255
keepAlive: {
256
enabled: true,
257
},
258
});
259
260
// Custom keep-alive timing
261
const wsClient = createWSClient({
262
url: "ws://localhost:3001",
263
keepAlive: {
264
enabled: true,
265
intervalMs: 10000, // Ping every 10 seconds
266
pongTimeoutMs: 2000, // Wait 2 seconds for pong
267
},
268
});
269
270
// Aggressive keep-alive for unstable networks
271
const wsClient = createWSClient({
272
url: "ws://localhost:3001",
273
keepAlive: {
274
enabled: true,
275
intervalMs: 3000, // Frequent pings
276
pongTimeoutMs: 1000, // Quick timeout detection
277
},
278
});
279
```
280
281
### Connection State Management
282
283
WebSocket links provide connection state information for handling reconnections and connection issues.
284
285
```typescript { .api }
286
/** Connection state types */
287
type TRPCConnectionState<TError = unknown> =
288
| { type: 'connecting' }
289
| { type: 'open' }
290
| { type: 'closed' }
291
| { type: 'error'; error: TError };
292
293
/** WebSocket client with connection state observable */
294
interface TRPCWebSocketClient {
295
connectionState: Observable<TRPCConnectionState>;
296
request(opts: { op: Operation; transformer: any }): Observable<any>;
297
close(): void;
298
}
299
```
300
301
**Connection State Examples:**
302
303
```typescript
304
import { createTRPCClient, wsLink, createWSClient } from "@trpc/client";
305
306
const wsClient = createWSClient({
307
url: "ws://localhost:3001",
308
});
309
310
// Monitor connection state
311
wsClient.connectionState.subscribe({
312
next: (state) => {
313
switch (state.type) {
314
case 'connecting':
315
console.log("Connecting to WebSocket...");
316
showConnectingIndicator(true);
317
break;
318
case 'open':
319
console.log("WebSocket connected");
320
showConnectingIndicator(false);
321
break;
322
case 'closed':
323
console.log("WebSocket disconnected");
324
showOfflineIndicator(true);
325
break;
326
case 'error':
327
console.error("WebSocket error:", state.error);
328
handleConnectionError(state.error);
329
break;
330
}
331
},
332
});
333
334
const client = createTRPCClient<AppRouter>({
335
links: [
336
wsLink({
337
client: wsClient,
338
}),
339
],
340
});
341
```
342
343
### Combined HTTP and WebSocket Setup
344
345
Common pattern combining HTTP transport for queries/mutations with WebSocket transport for subscriptions.
346
347
```typescript { .api }
348
import {
349
createTRPCClient,
350
httpBatchLink,
351
wsLink,
352
splitLink,
353
createWSClient
354
} from "@trpc/client";
355
```
356
357
**Combined Setup Examples:**
358
359
```typescript
360
// Split transport based on operation type
361
const wsClient = createWSClient({
362
url: "ws://localhost:3001",
363
});
364
365
const client = createTRPCClient<AppRouter>({
366
links: [
367
splitLink({
368
condition: (op) => op.type === 'subscription',
369
true: wsLink({
370
client: wsClient,
371
}),
372
false: httpBatchLink({
373
url: "http://localhost:3000/trpc",
374
}),
375
}),
376
],
377
});
378
379
// Use queries/mutations over HTTP, subscriptions over WebSocket
380
const user = await client.user.getById.query({ id: 1 }); // HTTP
381
const newUser = await client.user.create.mutate({ name: "Alice" }); // HTTP
382
383
const unsubscribe = client.posts.onUpdate.subscribe(undefined, { // WebSocket
384
onData: (post) => console.log("Post updated:", post),
385
});
386
```
387
388
### Error Handling
389
390
WebSocket connections provide specific error handling for connection and communication issues.
391
392
```typescript { .api }
393
// WebSocket-specific error handling
394
const wsClient = createWSClient({
395
url: "ws://localhost:3001",
396
onError: (event) => {
397
console.error("WebSocket connection error:", event);
398
399
// Handle specific error scenarios
400
if (event?.type === 'error') {
401
// Network error, server down, etc.
402
showRetryPrompt();
403
}
404
},
405
onClose: (cause) => {
406
if (cause?.code === 1006) {
407
// Abnormal closure - network issue
408
console.log("Unexpected disconnection, will retry");
409
} else if (cause?.code === 1000) {
410
// Normal closure
411
console.log("Connection closed normally");
412
}
413
},
414
});
415
```
416
417
**Subscription Error Handling:**
418
419
```typescript
420
const unsubscribe = client.posts.onUpdate.subscribe(undefined, {
421
onData: (post) => {
422
updateUI(post);
423
},
424
onError: (err) => {
425
if (err instanceof TRPCClientError) {
426
// Server-side subscription error
427
console.error("Subscription error:", err.message);
428
handleSubscriptionError(err);
429
} else {
430
// Connection-level error
431
console.error("Connection error:", err);
432
handleConnectionError(err);
433
}
434
},
435
onConnectionStateChange: (state) => {
436
if (state.type === 'error') {
437
console.error("Connection state error:", state.error);
438
// Attempt manual reconnection or show error UI
439
}
440
},
441
});
442
```