Skip to content

Quick Start

This guide walks through a minimal setup where a renderer process calls procedures on the main process.

  1. Define your tRPC router (main process)

    src/main/router.ts
    import { initTRPC } from '@trpc/server';
    import { z } from 'zod';
    const t = initTRPC.create();
    export const appRouter = t.router({
    greet: t.procedure
    .input(z.object({ name: z.string() }))
    .query(({ input }) => {
    return `Hello, ${input.name}!`;
    }),
    });
    export type AppRouter = typeof appRouter;
  2. Attach your router to the window (main process)

    src/main/index.ts
    import { app, BrowserWindow } from 'electron';
    import { createWindowMessagePortHandler } from 'electron-messageport-trpc/main';
    import { appRouter } from './router';
    app.whenReady().then(() => {
    const win = new BrowserWindow({
    webPreferences: {
    preload: '/path/to/preload.js',
    },
    });
    win.loadFile('index.html');
    createWindowMessagePortHandler({
    router: appRouter,
    windows: [win],
    });
    });
  3. Expose the port receiver (preload script)

    src/preload/index.ts
    import { exposePortReceiver } from 'electron-messageport-trpc/preload';
    exposePortReceiver();
  4. Create the tRPC client (renderer process)

    src/renderer/index.ts
    import { createTRPCClient } from '@trpc/client';
    import { getPort, portLink } from 'electron-messageport-trpc/renderer';
    import type { AppRouter } from '../main/router';
    const trpc = createTRPCClient<AppRouter>({
    links: [portLink({ port: getPort() })],
    });
    // Now you can call procedures with full type safety!
    const greeting = await trpc.greet.query({ name: 'World' });
    console.log(greeting); // "Hello, World!"
  1. createWindowMessagePortHandler() watches each window for did-finish-load, creates a new MessagePort pair, and attaches the main-process side to your router.
  2. exposePortReceiver() in the preload script receives the transferred port and forwards it into the renderer’s main world.
  3. In the renderer, getPort() resolves the transferred port and portLink({ port }) plugs it into a standard tRPC client.
  4. Reloads are handled by the main-process helper, so your application code does not need to manually recreate handlers.