Skip to content
tRPCv12
v12 preview

Move Fast and Break Nothing.End-to-end typesafe APIs made easy.

Experience the full power of TypeScript inference: write procedures on the server and call them from the client with their types. No schemas to generate, no code to sync. v12 is rebuilt on Effect, and you don't have to use it.

$ pnpm add @trpc12/trpc zod

src/client.ts
import { function createTrpcClient<TSource, const TLinks extends ReadonlyArray<TrpcLink<any, RouterOf<TSource>>>>(opts: TypedClientOptions<TSource, TLinks> & DuplicateSwitchCheck<TLinks> & UnmetNeedCheck<TLinks>): TrpcClient<RouterOf<TSource>, LinksContext<TLinks>, undefined, LinksTypes<TLinks>>createTrpcClient, function httpLink<TOpts extends HttpLinkOptions>(opts: TOpts): TrpcLink<HttpLinkDecl<TOpts>>httpLink, function routerType<TRouter>(): RouterType<TRouter>routerType } from '@trpc12/trpc/client';

import type { 
type AppRouter = {
    post: {
        byId: BuildProcedure<InputDef<RootDef<{
            userId: string | null;
        }, {}>, ZodObject<{
            id: ZodString;
        }, $strip>>, "query", {
            output: Post;
            errors: TrpcError<"NOT_FOUND", {
                id: string;
            }>;
            services: never;
            unmapped: never;
        }>;
        create: BuildProcedure<InputDef<RootDef<{
            userId: string | null;
        }, {}>, ZodObject<{
            title: ZodString;
        }, $strip>>, "mutation", {
            output: Post;
            errors: never;
            services: never;
            unmapped: never;
        }>;
    };
}
AppRouter
} from './server.ts';
const
const client: TrpcClient<{
    post: {
        byId: BuildProcedure<InputDef<RootDef<{
            userId: string | null;
        }, {}>, ZodObject<{
            id: ZodString;
        }, $strip>>, "query", {
            output: Post;
            errors: TrpcError<"NOT_FOUND", {
                id: string;
            }>;
            services: never;
            unmapped: never;
        }>;
        create: BuildProcedure<InputDef<RootDef<{
            userId: string | null;
        }, {}>, ZodObject<{
            title: ZodString;
        }, $strip>>, "mutation", {
            output: Post;
            errors: never;
            services: never;
            unmapped: never;
        }>;
    };
}, {}, undefined, LinksTypes<...>>
client
=
createTrpcClient<RouterType<{
    post: {
        byId: BuildProcedure<InputDef<RootDef<{
            userId: string | null;
        }, {}>, ZodObject<{
            id: ZodString;
        }, $strip>>, "query", {
            output: Post;
            errors: TrpcError<"NOT_FOUND", {
                id: string;
            }>;
            services: never;
            unmapped: never;
        }>;
        create: BuildProcedure<InputDef<RootDef<{
            userId: string | null;
        }, {}>, ZodObject<{
            title: ZodString;
        }, $strip>>, "mutation", {
            output: Post;
            errors: never;
            services: never;
            unmapped: never;
        }>;
    };
}>, readonly [...]>(opts: TypedClientOptions<...>): TrpcClient<...>
createTrpcClient
({
TypedClientOptions<RouterType<{ post: { byId: BuildProcedure<InputDef<RootDef<{ userId: string | null; }, {}>, ZodObject<{ id: ZodString; }, $strip>>, "query", { ...; }>; create: BuildProcedure<...>; }; }>, readonly [...]>.router: RouterType<{
    post: {
        byId: BuildProcedure<InputDef<RootDef<{
            userId: string | null;
        }, {}>, ZodObject<{
            id: ZodString;
        }, $strip>>, "query", {
            output: Post;
            errors: TrpcError<"NOT_FOUND", {
                id: string;
            }>;
            services: never;
            unmapped: never;
        }>;
        create: BuildProcedure<InputDef<RootDef<{
            userId: string | null;
        }, {}>, ZodObject<{
            title: ZodString;
        }, $strip>>, "mutation", {
            output: Post;
            errors: never;
            services: never;
            unmapped: never;
        }>;
    };
}>
router
:
routerType<{
    post: {
        byId: BuildProcedure<InputDef<RootDef<{
            userId: string | null;
        }, {}>, ZodObject<{
            id: ZodString;
        }, $strip>>, "query", {
            output: Post;
            errors: TrpcError<"NOT_FOUND", {
                id: string;
            }>;
            services: never;
            unmapped: never;
        }>;
        create: BuildProcedure<InputDef<RootDef<{
            userId: string | null;
        }, {}>, ZodObject<{
            title: ZodString;
        }, $strip>>, "mutation", {
            output: Post;
            errors: never;
            services: never;
            unmapped: never;
        }>;
    };
}>(): RouterType<...>
routerType
<
type AppRouter = {
    post: {
        byId: BuildProcedure<InputDef<RootDef<{
            userId: string | null;
        }, {}>, ZodObject<{
            id: ZodString;
        }, $strip>>, "query", {
            output: Post;
            errors: TrpcError<"NOT_FOUND", {
                id: string;
            }>;
            services: never;
            unmapped: never;
        }>;
        create: BuildProcedure<InputDef<RootDef<{
            userId: string | null;
        }, {}>, ZodObject<{
            title: ZodString;
        }, $strip>>, "mutation", {
            output: Post;
            errors: never;
            services: never;
            unmapped: never;
        }>;
    };
}
AppRouter
>(),
TypedClientOptions<RouterType<{ post: { byId: BuildProcedure<InputDef<RootDef<{ userId: string | null; }, {}>, ZodObject<{ id: ZodString; }, $strip>>, "query", { ...; }>; create: BuildProcedure<...>; }; }>, readonly [...]>.links: readonly [TrpcLink<{
    form: JsonForm;
    provides: "response";
}, any>]
links
: [
httpLink<{
    url: string;
}>(opts: {
    url: string;
}): TrpcLink<{
    form: JsonForm;
    provides: "response";
}, any>
httpLink
({ url: stringurl: '/trpc' })],
}); const post = await
const client: TrpcClient<{
    post: {
        byId: BuildProcedure<InputDef<RootDef<{
            userId: string | null;
        }, {}>, ZodObject<{
            id: ZodString;
        }, $strip>>, "query", {
            output: Post;
            errors: TrpcError<"NOT_FOUND", {
                id: string;
            }>;
            services: never;
            unmapped: never;
        }>;
        create: BuildProcedure<InputDef<RootDef<{
            userId: string | null;
        }, {}>, ZodObject<{
            title: ZodString;
        }, $strip>>, "mutation", {
            output: Post;
            errors: never;
            services: never;
            unmapped: never;
        }>;
    };
}, {}, undefined, LinksTypes<...>>
client
.
post: ClientRouter<{
    byId: BuildProcedure<InputDef<RootDef<{
        userId: string | null;
    }, {}>, ZodObject<{
        id: ZodString;
    }, $strip>>, "query", {
        output: Post;
        errors: TrpcError<"NOT_FOUND", {
            id: string;
        }>;
        services: never;
        unmapped: never;
    }>;
    create: BuildProcedure<InputDef<RootDef<{
        userId: string | null;
    }, {}>, ZodObject<{
        title: ZodString;
    }, $strip>>, "mutation", {
        output: Post;
        errors: never;
        services: never;
        unmapped: never;
    }>;
}, {}, undefined, LinksTypes<...>>
post
.
byId: {
    query(input: {
        id: string;
    }, opts?: CallOptions<{}> | undefined): TrpcPromise<{
        id: string;
        title: string;
    }, CallError<{
        type: "query";
        ctx: {
            userId: string | null;
        };
        meta: {};
        input: {
            id: string;
        };
        output: Post;
        errors: TrpcError<"NOT_FOUND", {
            id: string;
        }> | InputValidationError<{
            id: string;
        }>;
        services: never;
    }, JsonForm, never>>;
}
byId
.
function query(input: {
    id: string;
}, opts?: CallOptions<{}> | undefined): TrpcPromise<{
    id: string;
    title: string;
}, CallError<{
    type: "query";
    ctx: {
        userId: string | null;
    };
    meta: {};
    input: {
        id: string;
    };
    output: Post;
    errors: TrpcError<"NOT_FOUND", {
        id: string;
    }> | InputValidationError<{
        id: string;
    }>;
    services: never;
}, JsonForm, never>>
query
({ id: stringid: '1' });
const post: {
    id: string;
    title: string;
}

The client of the router below: the types come from the server, with nothing generated.

How it works

Three files' worth of code, compiled when this site builds: the types you hover are the ones your editor shows.

  1. Define procedures

    A router is a plain object of procedures. Each one validates its input with any Standard Schema library and returns its output, or an error with typed data.

    Export the router's type: it is all the client needs.

    Procedures
    src/server.ts
    const 
    const t: TrpcRoot<{
        userId: string | null;
    }, {}, RootDef<{
        userId: string | null;
    }, {}>>
    t
    =
    initTrpc<{
        ctx: {
            userId: string | null;
        };
    }>(opts?: RootOptions<{}>): TrpcRoot<{
        userId: string | null;
    }, {}, RootDef<{
        userId: string | null;
    }, {}>>
    initTrpc
    <{
    ctx: {
        userId: string | null;
    }
    ctx
    : { userId: string | nulluserId: string | null } }>();
    export const
    const appRouter: {
        post: {
            byId: BuildProcedure<InputDef<RootDef<{
                userId: string | null;
            }, {}>, z.ZodObject<{
                id: z.ZodString;
            }, z.core.$strip>>, "query", {
                output: Post;
                errors: TrpcError<"NOT_FOUND", {
                    id: string;
                }>;
                services: never;
                unmapped: never;
            }>;
            create: BuildProcedure<InputDef<RootDef<{
                userId: string | null;
            }, {}>, z.ZodObject<{
                title: z.ZodString;
            }, z.core.$strip>>, "mutation", {
                output: Post;
                errors: never;
                services: never;
                unmapped: never;
            }>;
        };
    }
    appRouter
    = {
    post: {
        byId: BuildProcedure<InputDef<RootDef<{
            userId: string | null;
        }, {}>, z.ZodObject<{
            id: z.ZodString;
        }, z.core.$strip>>, "query", {
            output: Post;
            errors: TrpcError<"NOT_FOUND", {
                id: string;
            }>;
            services: never;
            unmapped: never;
        }>;
        create: BuildProcedure<InputDef<RootDef<{
            userId: string | null;
        }, {}>, z.ZodObject<{
            title: z.ZodString;
        }, z.core.$strip>>, "mutation", {
            output: Post;
            errors: never;
            services: never;
            unmapped: never;
        }>;
    }
    post
    : {
    byId: BuildProcedure<InputDef<RootDef<{
        userId: string | null;
    }, {}>, z.ZodObject<{
        id: z.ZodString;
    }, z.core.$strip>>, "query", {
        output: Post;
        errors: TrpcError<"NOT_FOUND", {
            id: string;
        }>;
        services: never;
        unmapped: never;
    }>
    byId
    :
    const t: TrpcRoot<{
        userId: string | null;
    }, {}, RootDef<{
        userId: string | null;
    }, {}>>
    t
    .
    TrpcRoot<{ userId: string | null; }, {}, RootDef<{ userId: string | null; }, {}>>.procedure: ProcedureBuilder<RootDef<{
        userId: string | null;
    }, {}>>
    procedure
    .
    ProcedureBuilder<RootDef<{ userId: string | null; }, {}>>.input<z.ZodObject<{
        id: z.ZodString;
    }, z.core.$strip>>(schema: z.ZodObject<{
        id: z.ZodString;
    }, z.core.$strip>): ProcedureBuilder<InputDef<RootDef<{
        userId: string | null;
    }, {}>, z.ZodObject<{
        id: z.ZodString;
    }, z.core.$strip>>> (+1 overload)
    input
    (import zz.
    function object<{
        id: z.ZodString;
    }>(shape?: {
        id: z.ZodString;
    } | undefined, params?: string | {
        error?: string | z.core.$ZodErrorMap<NonNullable<z.core.$ZodIssueInvalidType<unknown> | z.core.$ZodIssueUnrecognizedKeys>> | undefined;
        message?: string | undefined | undefined;
    } | undefined): z.ZodObject<{
        id: z.ZodString;
    }, z.core.$strip>
    object
    ({ id: z.ZodStringid: import zz.function string(params?: string | z.core.$ZodStringParams): z.ZodString (+1 overload)string() }))
    .
    ProcedureBuilder<InputDef<RootDef<{ userId: string | null; }, {}>, ZodObject<{ id: ZodString; }, $strip>>>.query<Post | TrpcError<"NOT_FOUND", {
        id: string;
    }>>(resolver: (opts: ResolverOpts<InputDef<RootDef<{
        userId: string | null;
    }, {}>, z.ZodObject<{
        id: z.ZodString;
    }, z.core.$strip>>>) => Post | TrpcError<"NOT_FOUND", {
        id: string;
    }>): BuildProcedure<InputDef<RootDef<{
        userId: string | null;
    }, {}>, z.ZodObject<{
        id: z.ZodString;
    }, z.core.$strip>>, "query", {
        output: Post;
        errors: TrpcError<"NOT_FOUND", {
            id: string;
        }>;
        services: never;
        unmapped: never;
    }>
    query
    (
    (
    opts: ResolverOpts<InputDef<RootDef<{
        userId: string | null;
    }, {}>, z.ZodObject<{
        id: z.ZodString;
    }, z.core.$strip>>>
    opts
    ) =>
    const posts: Map<string, Post>posts.Map<string, Post>.get(key: string): Post | undefinedget(
    opts: ResolverOpts<InputDef<RootDef<{
        userId: string | null;
    }, {}>, z.ZodObject<{
        id: z.ZodString;
    }, z.core.$strip>>>
    opts
    .
    ResolverOpts<InputDef<RootDef<{ userId: string | null; }, {}>, ZodObject<{ id: ZodString; }, $strip>>>.input: {
        id: string;
    }
    input
    .id: stringid) ??
    error<"NOT_FOUND", {
        id: string;
    }>(opts: Omit<TrpcErrorOptions<"NOT_FOUND", {
        id: string;
    }>, "defined">): TrpcError<"NOT_FOUND", {
        id: string;
    }>
    error
    ({ code: "NOT_FOUND"code: 'NOT_FOUND',
    data?: {
        id: string;
    } | undefined
    data
    : { id: stringid:
    opts: ResolverOpts<InputDef<RootDef<{
        userId: string | null;
    }, {}>, z.ZodObject<{
        id: z.ZodString;
    }, z.core.$strip>>>
    opts
    .
    ResolverOpts<InputDef<RootDef<{ userId: string | null; }, {}>, ZodObject<{ id: ZodString; }, $strip>>>.input: {
        id: string;
    }
    input
    .id: stringid } }),
    ),
    create: BuildProcedure<InputDef<RootDef<{
        userId: string | null;
    }, {}>, z.ZodObject<{
        title: z.ZodString;
    }, z.core.$strip>>, "mutation", {
        output: Post;
        errors: never;
        services: never;
        unmapped: never;
    }>
    create
    :
    const t: TrpcRoot<{
        userId: string | null;
    }, {}, RootDef<{
        userId: string | null;
    }, {}>>
    t
    .
    TrpcRoot<{ userId: string | null; }, {}, RootDef<{ userId: string | null; }, {}>>.procedure: ProcedureBuilder<RootDef<{
        userId: string | null;
    }, {}>>
    procedure
    .
    ProcedureBuilder<RootDef<{ userId: string | null; }, {}>>.input<z.ZodObject<{
        title: z.ZodString;
    }, z.core.$strip>>(schema: z.ZodObject<{
        title: z.ZodString;
    }, z.core.$strip>): ProcedureBuilder<InputDef<RootDef<{
        userId: string | null;
    }, {}>, z.ZodObject<{
        title: z.ZodString;
    }, z.core.$strip>>> (+1 overload)
    input
    (import zz.
    function object<{
        title: z.ZodString;
    }>(shape?: {
        title: z.ZodString;
    } | undefined, params?: string | {
        error?: string | z.core.$ZodErrorMap<NonNullable<z.core.$ZodIssueInvalidType<unknown> | z.core.$ZodIssueUnrecognizedKeys>> | undefined;
        message?: string | undefined | undefined;
    } | undefined): z.ZodObject<{
        title: z.ZodString;
    }, z.core.$strip>
    object
    ({ title: z.ZodStringtitle: import zz.function string(params?: string | z.core.$ZodStringParams): z.ZodString (+1 overload)string()._ZodString<$ZodStringInternals<string>>.min(minLength: number, params?: string | z.core.$ZodCheckMinLengthParams): z.ZodStringmin(1) }))
    .
    ProcedureBuilder<InputDef<RootDef<{ userId: string | null; }, {}>, ZodObject<{ title: ZodString; }, $strip>>>.mutation<Post>(resolver: (opts: ResolverOpts<InputDef<RootDef<{
        userId: string | null;
    }, {}>, z.ZodObject<{
        title: z.ZodString;
    }, z.core.$strip>>>) => Post): BuildProcedure<InputDef<RootDef<{
        userId: string | null;
    }, {}>, z.ZodObject<{
        title: z.ZodString;
    }, z.core.$strip>>, "mutation", {
        output: Post;
        errors: never;
        services: never;
        unmapped: never;
    }>
    mutation
    ((
    opts: ResolverOpts<InputDef<RootDef<{
        userId: string | null;
    }, {}>, z.ZodObject<{
        title: z.ZodString;
    }, z.core.$strip>>>
    opts
    ) => {
    const const post: Postpost: Post = { Post.id: stringid: var crypto: Cryptocrypto.Crypto.randomUUID(): `${string}-${string}-${string}-${string}-${string}`randomUUID(), Post.title: stringtitle:
    opts: ResolverOpts<InputDef<RootDef<{
        userId: string | null;
    }, {}>, z.ZodObject<{
        title: z.ZodString;
    }, z.core.$strip>>>
    opts
    .
    ResolverOpts<InputDef<RootDef<{ userId: string | null; }, {}>, ZodObject<{ title: ZodString; }, $strip>>>.input: {
        title: string;
    }
    input
    .title: stringtitle };
    const posts: Map<string, Post>posts.Map<string, Post>.set(key: string, value: Post): Map<string, Post>set(const post: Postpost.Post.id: stringid, const post: Postpost); return const post: Postpost; }), }, }; export type
    type AppRouter = {
        post: {
            byId: BuildProcedure<InputDef<RootDef<{
                userId: string | null;
            }, {}>, z.ZodObject<{
                id: z.ZodString;
            }, z.core.$strip>>, "query", {
                output: Post;
                errors: TrpcError<"NOT_FOUND", {
                    id: string;
                }>;
                services: never;
                unmapped: never;
            }>;
            create: BuildProcedure<InputDef<RootDef<{
                userId: string | null;
            }, {}>, z.ZodObject<{
                title: z.ZodString;
            }, z.core.$strip>>, "mutation", {
                output: Post;
                errors: never;
                services: never;
                unmapped: never;
            }>;
        };
    }
    AppRouter
    = typeof
    const appRouter: {
        post: {
            byId: BuildProcedure<InputDef<RootDef<{
                userId: string | null;
            }, {}>, z.ZodObject<{
                id: z.ZodString;
            }, z.core.$strip>>, "query", {
                output: Post;
                errors: TrpcError<"NOT_FOUND", {
                    id: string;
                }>;
                services: never;
                unmapped: never;
            }>;
            create: BuildProcedure<InputDef<RootDef<{
                userId: string | null;
            }, {}>, z.ZodObject<{
                title: z.ZodString;
            }, z.core.$strip>>, "mutation", {
                output: Post;
                errors: never;
                services: never;
                unmapped: never;
            }>;
        };
    }
    appRouter
    ;
  2. Serve them anywhere

    createFetchHandler serves the router over HTTP, SSE and WebSockets. Hand handler.fetch to Workers, Bun, Deno or a Next.js route, or serve it on Node with Effect's HttpServer.

    Adapters
    src/server.ts
    export const const handler: FetchHandler<undefined>handler = 
    createFetchHandler<{
        post: {
            byId: BuildProcedure<InputDef<RootDef<{
                userId: string | null;
            }, {}>, z.ZodObject<{
                id: z.ZodString;
            }, z.core.$strip>>, "query", {
                output: Post;
                errors: TrpcError<"NOT_FOUND", {
                    id: string;
                }>;
                services: never;
                unmapped: never;
            }>;
            create: BuildProcedure<InputDef<RootDef<{
                userId: string | null;
            }, {}>, z.ZodObject<{
                title: z.ZodString;
            }, z.core.$strip>>, "mutation", {
                output: Post;
                errors: never;
                services: never;
                unmapped: never;
            }>;
        };
    }, undefined>(opts: FetchHandlerOptions<...>): FetchHandler<...>
    createFetchHandler
    ({
    BaseHandlerOptions<{ post: { byId: BuildProcedure<InputDef<RootDef<{ userId: string | null; }, {}>, ZodObject<{ id: ZodString; }, $strip>>, "query", { ...; }>; create: BuildProcedure<...>; }; }>.router: {
        post: {
            byId: BuildProcedure<InputDef<RootDef<{
                userId: string | null;
            }, {}>, z.ZodObject<{
                id: z.ZodString;
            }, z.core.$strip>>, "query", {
                output: Post;
                errors: TrpcError<"NOT_FOUND", {
                    id: string;
                }>;
                services: never;
                unmapped: never;
            }>;
            create: BuildProcedure<InputDef<RootDef<{
                userId: string | null;
            }, {}>, z.ZodObject<{
                title: z.ZodString;
            }, z.core.$strip>>, "mutation", {
                output: Post;
                errors: never;
                services: never;
                unmapped: never;
            }>;
        };
    }
    router
    :
    const appRouter: {
        post: {
            byId: BuildProcedure<InputDef<RootDef<{
                userId: string | null;
            }, {}>, z.ZodObject<{
                id: z.ZodString;
            }, z.core.$strip>>, "query", {
                output: Post;
                errors: TrpcError<"NOT_FOUND", {
                    id: string;
                }>;
                services: never;
                unmapped: never;
            }>;
            create: BuildProcedure<InputDef<RootDef<{
                userId: string | null;
            }, {}>, z.ZodObject<{
                title: z.ZodString;
            }, z.core.$strip>>, "mutation", {
                output: Post;
                errors: never;
                services: never;
                unmapped: never;
            }>;
        };
    }
    appRouter
    ,
    createContext: (opts: CreateContextOpts<undefined>) => MaybePromise<{
        userId: string | null;
    }>
    createContext
    : (opts: CreateContextOpts<undefined>opts) => ({
    userId: string | nulluserId: opts: CreateContextOpts<undefined>opts.CreateContextOpts<undefined>.request: HttpServerRequestrequest.HttpIncomingMessage<HttpServerError>.headers: Headersheaders['x-user-id'] ?? null, }), }); // Workers, Bun, Deno, Next.js route handlers: any fetch runtime. export default { fetch: (request: Request) => Promise<Response>fetch: const handler: FetchHandler<undefined>handler.FetchHandler<undefined>.fetch: (request: Request) => Promise<Response>fetch };
  3. Call them with their types

    The client is typed from routerType<AppRouter>(), so no server code ships to the browser. Hover a name to see its type.

    safe() turns a call into a result tuple, with the procedure's defined errors narrowed by code.

    The client
    src/client.ts
    import { function createTrpcClient<TSource, const TLinks extends ReadonlyArray<TrpcLink<any, RouterOf<TSource>>>>(opts: TypedClientOptions<TSource, TLinks> & DuplicateSwitchCheck<TLinks> & UnmetNeedCheck<TLinks>): TrpcClient<RouterOf<TSource>, LinksContext<TLinks>, undefined, LinksTypes<TLinks>>createTrpcClient, function httpLink<TOpts extends HttpLinkOptions>(opts: TOpts): TrpcLink<HttpLinkDecl<TOpts>>httpLink, function routerType<TRouter>(): RouterType<TRouter>routerType } from '@trpc12/trpc/client';
    import { 
    function safe<T, E = unknown>(promise: PromiseLike<T> & {
        readonly "~error"?: E;
    }): Promise<SafeResult<T, E>>
    safe
    } from '@trpc12/trpc/client';
    import type {
    type AppRouter = {
        post: {
            byId: BuildProcedure<InputDef<RootDef<{
                userId: string | null;
            }, {}>, ZodObject<{
                id: ZodString;
            }, $strip>>, "query", {
                output: Post;
                errors: TrpcError<"NOT_FOUND", {
                    id: string;
                }>;
                services: never;
                unmapped: never;
            }>;
            create: BuildProcedure<InputDef<RootDef<{
                userId: string | null;
            }, {}>, ZodObject<{
                title: ZodString;
            }, $strip>>, "mutation", {
                output: Post;
                errors: never;
                services: never;
                unmapped: never;
            }>;
        };
    }
    AppRouter
    } from './server.ts';
    const
    const client: TrpcClient<{
        post: {
            byId: BuildProcedure<InputDef<RootDef<{
                userId: string | null;
            }, {}>, ZodObject<{
                id: ZodString;
            }, $strip>>, "query", {
                output: Post;
                errors: TrpcError<"NOT_FOUND", {
                    id: string;
                }>;
                services: never;
                unmapped: never;
            }>;
            create: BuildProcedure<InputDef<RootDef<{
                userId: string | null;
            }, {}>, ZodObject<{
                title: ZodString;
            }, $strip>>, "mutation", {
                output: Post;
                errors: never;
                services: never;
                unmapped: never;
            }>;
        };
    }, {}, undefined, LinksTypes<...>>
    client
    =
    createTrpcClient<RouterType<{
        post: {
            byId: BuildProcedure<InputDef<RootDef<{
                userId: string | null;
            }, {}>, ZodObject<{
                id: ZodString;
            }, $strip>>, "query", {
                output: Post;
                errors: TrpcError<"NOT_FOUND", {
                    id: string;
                }>;
                services: never;
                unmapped: never;
            }>;
            create: BuildProcedure<InputDef<RootDef<{
                userId: string | null;
            }, {}>, ZodObject<{
                title: ZodString;
            }, $strip>>, "mutation", {
                output: Post;
                errors: never;
                services: never;
                unmapped: never;
            }>;
        };
    }>, readonly [...]>(opts: TypedClientOptions<...>): TrpcClient<...>
    createTrpcClient
    ({
    TypedClientOptions<RouterType<{ post: { byId: BuildProcedure<InputDef<RootDef<{ userId: string | null; }, {}>, ZodObject<{ id: ZodString; }, $strip>>, "query", { ...; }>; create: BuildProcedure<...>; }; }>, readonly [...]>.router: RouterType<{
        post: {
            byId: BuildProcedure<InputDef<RootDef<{
                userId: string | null;
            }, {}>, ZodObject<{
                id: ZodString;
            }, $strip>>, "query", {
                output: Post;
                errors: TrpcError<"NOT_FOUND", {
                    id: string;
                }>;
                services: never;
                unmapped: never;
            }>;
            create: BuildProcedure<InputDef<RootDef<{
                userId: string | null;
            }, {}>, ZodObject<{
                title: ZodString;
            }, $strip>>, "mutation", {
                output: Post;
                errors: never;
                services: never;
                unmapped: never;
            }>;
        };
    }>
    router
    :
    routerType<{
        post: {
            byId: BuildProcedure<InputDef<RootDef<{
                userId: string | null;
            }, {}>, ZodObject<{
                id: ZodString;
            }, $strip>>, "query", {
                output: Post;
                errors: TrpcError<"NOT_FOUND", {
                    id: string;
                }>;
                services: never;
                unmapped: never;
            }>;
            create: BuildProcedure<InputDef<RootDef<{
                userId: string | null;
            }, {}>, ZodObject<{
                title: ZodString;
            }, $strip>>, "mutation", {
                output: Post;
                errors: never;
                services: never;
                unmapped: never;
            }>;
        };
    }>(): RouterType<...>
    routerType
    <
    type AppRouter = {
        post: {
            byId: BuildProcedure<InputDef<RootDef<{
                userId: string | null;
            }, {}>, ZodObject<{
                id: ZodString;
            }, $strip>>, "query", {
                output: Post;
                errors: TrpcError<"NOT_FOUND", {
                    id: string;
                }>;
                services: never;
                unmapped: never;
            }>;
            create: BuildProcedure<InputDef<RootDef<{
                userId: string | null;
            }, {}>, ZodObject<{
                title: ZodString;
            }, $strip>>, "mutation", {
                output: Post;
                errors: never;
                services: never;
                unmapped: never;
            }>;
        };
    }
    AppRouter
    >(),
    TypedClientOptions<RouterType<{ post: { byId: BuildProcedure<InputDef<RootDef<{ userId: string | null; }, {}>, ZodObject<{ id: ZodString; }, $strip>>, "query", { ...; }>; create: BuildProcedure<...>; }; }>, readonly [...]>.links: readonly [TrpcLink<{
        form: JsonForm;
        provides: "response";
    }, any>]
    links
    : [
    httpLink<{
        url: string;
    }>(opts: {
        url: string;
    }): TrpcLink<{
        form: JsonForm;
        provides: "response";
    }, any>
    httpLink
    ({ url: stringurl: '/trpc' })],
    }); const post = await
    const client: TrpcClient<{
        post: {
            byId: BuildProcedure<InputDef<RootDef<{
                userId: string | null;
            }, {}>, ZodObject<{
                id: ZodString;
            }, $strip>>, "query", {
                output: Post;
                errors: TrpcError<"NOT_FOUND", {
                    id: string;
                }>;
                services: never;
                unmapped: never;
            }>;
            create: BuildProcedure<InputDef<RootDef<{
                userId: string | null;
            }, {}>, ZodObject<{
                title: ZodString;
            }, $strip>>, "mutation", {
                output: Post;
                errors: never;
                services: never;
                unmapped: never;
            }>;
        };
    }, {}, undefined, LinksTypes<...>>
    client
    .
    post: ClientRouter<{
        byId: BuildProcedure<InputDef<RootDef<{
            userId: string | null;
        }, {}>, ZodObject<{
            id: ZodString;
        }, $strip>>, "query", {
            output: Post;
            errors: TrpcError<"NOT_FOUND", {
                id: string;
            }>;
            services: never;
            unmapped: never;
        }>;
        create: BuildProcedure<InputDef<RootDef<{
            userId: string | null;
        }, {}>, ZodObject<{
            title: ZodString;
        }, $strip>>, "mutation", {
            output: Post;
            errors: never;
            services: never;
            unmapped: never;
        }>;
    }, {}, undefined, LinksTypes<...>>
    post
    .
    byId: {
        query(input: {
            id: string;
        }, opts?: CallOptions<{}> | undefined): TrpcPromise<{
            id: string;
            title: string;
        }, CallError<{
            type: "query";
            ctx: {
                userId: string | null;
            };
            meta: {};
            input: {
                id: string;
            };
            output: Post;
            errors: TrpcError<"NOT_FOUND", {
                id: string;
            }> | InputValidationError<{
                id: string;
            }>;
            services: never;
        }, JsonForm, never>>;
    }
    byId
    .
    function query(input: {
        id: string;
    }, opts?: CallOptions<{}> | undefined): TrpcPromise<{
        id: string;
        title: string;
    }, CallError<{
        type: "query";
        ctx: {
            userId: string | null;
        };
        meta: {};
        input: {
            id: string;
        };
        output: Post;
        errors: TrpcError<"NOT_FOUND", {
            id: string;
        }> | InputValidationError<{
            id: string;
        }>;
        services: never;
    }, JsonForm, never>>
    query
    ({ id: stringid: '1' });
    const post: {
        id: string;
        title: string;
    }
    var console: Consoleconsole.Console.log(...data: any[]): voidlog(
    const post: {
        id: string;
        title: string;
    }
    post
    .title: stringtitle);
    const [
    const created: {
        id: string;
        title: string;
    } | undefined
    created
    ,
    const err: UnexpectedError | (TrpcError<"BAD_REQUEST", {
        readonly issues: readonly InputIssue<{
            title: string;
        }>[];
    }> & {
        readonly defined: true;
    }) | undefined
    err
    ] = await
    safe<{
        id: string;
        title: string;
    }, UnexpectedError | (TrpcError<"BAD_REQUEST", {
        readonly issues: readonly InputIssue<{
            title: string;
        }>[];
    }> & {
        readonly defined: true;
    })>(promise: PromiseLike<{
        id: string;
        title: string;
    }> & {
        readonly '~error'?: UnexpectedError | (TrpcError<"BAD_REQUEST", {
            readonly issues: readonly InputIssue<{
                title: string;
            }>[];
        }> & {
            readonly defined: true;
        }) | undefined;
    }): Promise<SafeResult<{
        id: string;
        title: string;
    }, UnexpectedError | (TrpcError<"BAD_REQUEST", {
        readonly issues: readonly InputIssue<{
            title: string;
        }>[];
    }> & {
        readonly defined: true;
    })>>
    safe
    (
    const client: TrpcClient<{
        post: {
            byId: BuildProcedure<InputDef<RootDef<{
                userId: string | null;
            }, {}>, ZodObject<{
                id: ZodString;
            }, $strip>>, "query", {
                output: Post;
                errors: TrpcError<"NOT_FOUND", {
                    id: string;
                }>;
                services: never;
                unmapped: never;
            }>;
            create: BuildProcedure<InputDef<RootDef<{
                userId: string | null;
            }, {}>, ZodObject<{
                title: ZodString;
            }, $strip>>, "mutation", {
                output: Post;
                errors: never;
                services: never;
                unmapped: never;
            }>;
        };
    }, {}, undefined, LinksTypes<...>>
    client
    .
    post: ClientRouter<{
        byId: BuildProcedure<InputDef<RootDef<{
            userId: string | null;
        }, {}>, ZodObject<{
            id: ZodString;
        }, $strip>>, "query", {
            output: Post;
            errors: TrpcError<"NOT_FOUND", {
                id: string;
            }>;
            services: never;
            unmapped: never;
        }>;
        create: BuildProcedure<InputDef<RootDef<{
            userId: string | null;
        }, {}>, ZodObject<{
            title: ZodString;
        }, $strip>>, "mutation", {
            output: Post;
            errors: never;
            services: never;
            unmapped: never;
        }>;
    }, {}, undefined, LinksTypes<...>>
    post
    .
    create: {
        mutate(input: {
            title: string;
        }, opts?: CallOptions<{}> | undefined): TrpcPromise<{
            id: string;
            title: string;
        }, CallError<{
            type: "mutation";
            ctx: {
                userId: string | null;
            };
            meta: {};
            input: {
                title: string;
            };
            output: Post;
            errors: InputValidationError<{
                title: string;
            }>;
            services: never;
        }, JsonForm, never>>;
    }
    create
    .
    function mutate(input: {
        title: string;
    }, opts?: CallOptions<{}> | undefined): TrpcPromise<{
        id: string;
        title: string;
    }, CallError<{
        type: "mutation";
        ctx: {
            userId: string | null;
        };
        meta: {};
        input: {
            title: string;
        };
        output: Post;
        errors: InputValidationError<{
            title: string;
        }>;
        services: never;
    }, JsonForm, never>>
    mutate
    ({ title: stringtitle: '' }));
    if (
    const err: UnexpectedError | (TrpcError<"BAD_REQUEST", {
        readonly issues: readonly InputIssue<{
            title: string;
        }>[];
    }> & {
        readonly defined: true;
    }) | undefined
    err
    ?.defined: boolean | undefineddefined &&
    const err: TrpcError<"BAD_REQUEST", {
        readonly issues: readonly InputIssue<{
            title: string;
        }>[];
    }> & {
        readonly defined: true;
    }
    err
    .TrpcError<"BAD_REQUEST", { readonly issues: readonly InputIssue<{ title: string; }>[]; }>.code: "BAD_REQUEST"code === 'BAD_REQUEST') {
    var console: Consoleconsole.Console.log(...data: any[]): voidlog(
    const err: TrpcError<"BAD_REQUEST", {
        readonly issues: readonly InputIssue<{
            title: string;
        }>[];
    }> & {
        readonly defined: true;
    }
    err
    .
    TrpcError<"BAD_REQUEST", { readonly issues: readonly InputIssue<{ title: string; }>[]; }>.data: {
        readonly issues: readonly InputIssue<{
            title: string;
        }>[];
    }
    data
    .
    issues: readonly InputIssue<{
        title: string;
    }>[]
    issues
    );
    } else if (
    const created: {
        id: string;
        title: string;
    } | undefined
    created
    ) {
    var console: Consoleconsole.Console.log(...data: any[]): voidlog(
    const created: {
        id: string;
        title: string;
    }
    created
    .id: stringid);
    }

What's in v12

One package, @trpc12/trpc, with an entry point per job and nothing to install twice.