Free 40-page Claude guide — setup, 120 prompt codes, MCP servers, AI agents. Download free →
CLSkills
API DevelopmentadvancedNew

tRPC Subscription

Share

Implement real-time subscriptions with tRPC and WebSocket

Works with OpenClaude

You are a backend developer implementing real-time features. The user wants to set up tRPC subscriptions with WebSocket to enable live data streaming between server and clients.

What to check first

  • Run npm list trpc @trpc/server @trpc/client ws to verify tRPC and WebSocket dependencies are installed
  • Confirm your Node.js version supports EventEmitter (v14+)
  • Check that your HTTP server setup allows WebSocket upgrades (Next.js, Express, or Fastify)

Steps

  1. Install ws package: npm install ws @trpc/server @trpc/client @trpc/react-query (if not already present)
  2. Create a WebSocket server instance that tRPC can use for subscription handling
  3. Define your tRPC router with a subscription procedure using t.procedure.subscription()
  4. Pass an observable that emits data; use observable() from @trpc/server to wrap your event source
  5. On the client, use client.procedure.subscribe() instead of .query() or .mutate()
  6. Handle the subscription by listening to onData(), onError(), and onComplete() callbacks
  7. Implement proper cleanup: unsubscribe when the component unmounts or when the observable completes
  8. Test with multiple clients to ensure messages broadcast correctly across all subscribers

Code

// server/router.ts
import { initTRPC } from "@trpc/server";
import { observable } from "@trpc/server/observable";
import { EventEmitter } from "events";

const t = initTRPC.create();
const publicProcedure = t.procedure;
const router = t.router;

// Create an EventEmitter for broadcasting messages
const messageEmitter = new EventEmitter();

export const appRouter = router({
  chat: router({
    // Subscription that emits new messages in real-time
    onMessage: publicProcedure.subscription(() => {
      return observable<{ id: string; text: string; user: string }>((emit) => {
        const onMessage = (data: { id: string; text: string; user: string }) => {
          emit.next(data);
        };

        messageEmitter.on("message", onMessage);

        // Cleanup: remove listener when subscription ends
        return () => {
          messageEmitter.off("message", onMessage);
        };
      });
    }),

    // Mutation to send a message (triggers subscription)
    sendMessage: publicProcedure
      .input((val: unknown) => {
        if (typeof val === "object" && val !== null && "text" in val && "user" in val) {
          return val as { text: string; user: string };
        }
        throw new Error("Invalid input");
      })
      .mutation(({ input }) => {
        const message = {
          id: Math.random().toString(36),
          text:

Note: this example was truncated in the source. See the GitHub repo for the latest full version.

Common Pitfalls

  • Not validating request bodies before processing — attackers will send malformed payloads to crash your service
  • Returning detailed error messages in production — leaks internal architecture to attackers
  • Forgetting CORS headers — frontend will silently fail with cryptic browser errors
  • Hardcoding API keys in code — use environment variables and secret management
  • No rate limiting — one client can DoS your entire API

When NOT to Use This Skill

  • When a single shared library would suffice — APIs add network latency and failure modes
  • For internal-only data flow within the same process — use direct function calls
  • When you need transactional consistency across services — APIs can't guarantee this without distributed transactions

How to Verify It Worked

  • Test all CRUD operations end-to-end including error cases (404, 401, 403, 500)
  • Run an OWASP ZAP scan against your API — catches common security issues automatically
  • Load test with k6 or Artillery — verify your API holds up under realistic traffic
  • Verify rate limits actually trigger when exceeded — they often don't due to misconfiguration

Production Considerations

  • Version your API from day one (/v1/) — breaking changes are inevitable, give yourself a path
  • Set request size limits — prevents memory exhaustion attacks
  • Add structured logging with request IDs — trace every request across your stack
  • Document your API with OpenAPI — generates client SDKs and interactive docs for free

Quick Info

Difficultyadvanced
Version1.0.0
AuthorClaude Skills Hub
trpcsubscriptionswebsocket

Install command:

curl -o ~/.claude/skills/trpc-subscription.md https://clskills.in/skills/api/trpc-subscription.md

Related API Development Skills

Other Claude Code skills in the same category — free to download.

Want a API Development skill personalized to YOUR project?

This is a generic skill that works for everyone. Our AI can generate one tailored to your exact tech stack, naming conventions, folder structure, and coding patterns — with 3x more detail.