Skip to main content
Version: 2.x

Using With tRPC

tRPC is a fantastic library that magically turns server-side procedures into client-callable functions without requiring you to provide any formal contract. The popular T3 stack promotes the combo of Prisma + tRPC for achieving type safety from your frontend all the way down to the database.

ZenStack makes things even easier by automatically generating tRPC routers from the ZModel schema. You can use the generated routers together with an enhanced Prisma client; since the Prisma client has the ability to enforce access policies, there is no need to implement authorization code anymore.

Details

1. Initializing the project

If you haven't initialized your tRPC project with ZenStack, run the following command to do it:

npx zenstack@latest init
info

The "init" command does the following things for you:

  1. Install Prisma if it's not already installed.
  2. Install the zenstack CLI package as a dev dependency.
  3. Install the @zenstackhq/runtime package - used for enhancing PrismaClient at the runtime.
  4. Copy the prisma/schema.prisma file to schema.zmodel if it exists; otherwise, create a new template schema.zmodel file.

You can always manually complete the steps above if you have a special project setup that the "init" command doesn't work with.

After the initialization, please remember that you should edit the schema.zmodel moving forward. The prisma/schema.prisma file will be automatically regenerated when you run zenstack generate.

2. Installing the tRPC plugin

You can enable tRPC router generation with the @zenstackhq/trpc plugin.

First install the trpc package:

npm install -D @zenstackhq/trpc@latest

Then, add the following plugin configuration to your ZModel schema. Note that the configuration is different for tRPC v10 and v11:

/schema.zmodel
plugin trpc {
provider = '@zenstackhq/trpc'
output = 'src/server/routers/generated'
}

3. Setting up the tRPC context

Usually in your tRPC project, you have a function to create a tRPC context. You need to make sure the context contains a prisma field that is an instance of Prisma client. The generated tRPC routers use that to talk to the database.

For most of the cases you should use a Prisma client that's "enhanced" by ZenStack so that the CRUD operations are guarded by the access policies defined in the ZModel schema. Here's a quick example with Next.js:

/src/server/context.ts

import { enhance } from '@zenstackhq/runtime';
import { prisma } from './db';
import { getSessionUser } from './auth';

export const createContext = async ({ req, res }: CreateNextContextOptions) => {
return {
...,
// use access-control-enabled Prisma client
prisma: await enhance(prisma, { user: getSessionUser(req, res) }),
};
};

4. Using the generated routers

Now run the zenstack CLI to generate artifacts:

npx zenstack generate

You should find a bunch of tRPC routers generated in the output folder, one per each data model. A createRouter helper function is also generated, which returns a router instance for all models. You can use it as your top-level tRPC router, or merge it with other routers to form a more complex setup.

/src/server/routers/_app.ts
import { createRouter } from './generated/routers';

const t = initTRPC.context<Context>().create();

export const appRouter = createRouter(t.router, t.procedure);
export type AppRouter = typeof appRouter;

NOTE: The ZenStack trpc plugin is based on the awesome work by Omar Dulaimi.


Please refer to the @zenstackhq/trpc plugin documentation for more details. You can also use the sample-todo-trpc project as a reference.

Comments
Feel free to ask questions, give feedback, or report issues.

Don't Spam


You can edit/delete your comments by going directly to the discussion, clicking on the 'comments' link below