Getting Started
electron-trpc lets the renderer processes of your Electron app call a tRPC router in the main process, over Electron’s IPC.
Requirements
Section titled “Requirements”- Electron 35 or later
- tRPC 11.10 or later
- Context isolation, which Electron enables by default
Installation
Section titled “Installation”pnpm add electron-trpc @trpc/server @trpc/clientnpm install electron-trpc @trpc/server @trpc/clientyarn add electron-trpc @trpc/server @trpc/clientYou’ll need TypeScript to work across your main and renderer code to get inferred types in the renderer. The examples show setups with Vite and with webpack.
-
Define a tRPC router in the main process, as you would for any tRPC server:
api.ts import { EventEmitter, on } from 'node:events';import { initTRPC } from '@trpc/server';import z from 'zod';const ee = new EventEmitter();const t = initTRPC.create({ isServer: true });export const router = t.router({greeting: t.procedure.input(z.object({ name: z.string() })).query(({ input }) => `Hello ${input.name}`),greet: t.procedure.input(z.object({ name: z.string() })).mutation(({ input }) => {ee.emit('greeting', `Greeted ${input.name}`);}),greetings: t.procedure.subscription(async function* ({ signal }) {for await (const [text] of on(ee, 'greeting', { signal })) {yield text as string;}}),});export type AppRouter = typeof router; -
Create an IPC handler for the router in the main process. It also registers electron-trpc’s preload script, so create it before any window loads a page:
main.ts import { app, BrowserWindow } from 'electron';import { createIPCHandler } from 'electron-trpc/main';import { router } from './api';app.whenReady().then(() => {createIPCHandler({ router });const win = new BrowserWindow();win.loadFile('index.html');});The handler answers requests from all of your app’s windows.
-
Create a tRPC client in the renderer with
ipcLink, which takes the place of the HTTP and WebSocket links:renderer.ts import { createTRPCClient } from '@trpc/client';import { ipcLink } from 'electron-trpc/renderer';import type { AppRouter } from './api';export const client = createTRPCClient<AppRouter>({links: [ipcLink()],});const greeting = await client.greeting.query({ name: 'Electron' });
From here, use the client however you would with tRPC, including with TanStack React Query.
Next steps
Section titled “Next steps”- Preload script: how electron-trpc reaches your pages, and what to do if your build can’t include its preload script.
- Request lifetimes: when requests and subscriptions end.
- Security: limiting which pages can call your router.