Skip to main content
Version: 2.x

Fastify Adapter

The @zenstackhq/server/fastify module provides a quick way to install API routes onto a Fastify project for database CRUD operations. Combined with ZenStack's power of enhancing Prisma with access policies, it's surprisingly simple to achieve a secure data backend without manually coding it.


npm install @zenstackhq/server

Mounting the API

You can integrate ZenStack into your project with the ZenStackFastifyPlugin fastify plugin:

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

const server = fastify();

// serve OpenAPI at /api/model
server.register(ZenStackFastifyPlugin, {
prefix: '/api/model',
// getSessionUser extracts the current session user from the request, its
// implementation depends on your auth solution
getPrisma: (request) => enhance(prisma, { user: getSessionUser(request) }),

The Fastify adapter takes the following options to initialize:

  • prefix


    Prefix for the mounted API endpoints. E.g.: /api/model.

  • getPrisma (required)

    (request: FastifyRequest, reply: FastifyReply) => unknown | Promise<unknown>

    A callback for getting a PrismaClient instance for talking to the database. Usually you'll use an enhanced instance created with ZenStack's enhance API to ensure access policies are enforced.

  • logger (optional)


    Configuration for customizing logging behavior.

  • modelMeta (optional)


    Model metadata. By default loaded from the node_module/.zenstack/model-meta module. You can pass it in explicitly if you configured ZenStack to output to a different location. E.g.: require('output/model-meta').default.

  • zodSchemas (optional)

    ModelZodSchema | boolean | undefined

    Provides the Zod schemas used for validating CRUD request input. The Zod schemas can be generated with the @core/zod plugin. Pass true for this option to load the schemas from the default location. If you configured @core/zod plugin to output to a custom location, you can load the schemas explicitly and pass the loaded module to this option. E.g.:

    zodSchemas: require('./zod'),

    Not passing this option or passing in undefined disables input validation.

  • handler (optional)

    (req: RequestContext) => Promise<Response>

    The request handler function. This option determines the API endpoints and its input and output formats. Currently ZenStack supports two styles of APIs: RPC (the default) and RESTful.

    • RPC

      The goal of the RPC-style API handler is to fully mirror PrismaClient's API across the network, so that developers can continue enjoying the convenience and flexibility of Prisma's query syntax. This is the default choice for the handler option.

      The RPC-style handler can be created like:

      import { RPCApiHandler } from '@zenstackhq/server/api';
      const handler = RPCApiHandler();

      For more details, please check out RPC API Handler.

    • RESTful

      The goal of RESTful-style API handler is to provide a resource-centric RESTful API using JSON:API as transportation format.

      The RESTful-style handler can be created like:

      import { RestApiHandler } from '@zenstackhq/server/api';
      const handler = RestApiHandler({ endpoint: 'http://myhost/api' });

      For more details, please check out RESTful API Handler.

Using the API

The APIs can be used in the following three ways:

  1. With generated client hooks

    ZenStack provides plugins to generate client hooks from the ZModel targeting the most popular frontend data fetching libraries: TanStack Query and SWR. The generated hooks can be used to make API calls to the server adapters. Refer to the follow docs for detailed usage:


    The generated client hooks assumes the server adapter uses RPC-style API handler (which is the default setting).

  2. With direct HTTP calls

    You can make direct HTTP calls to the server adapter using your favorite client libraries like fetch or axios. Refer to the documentation of the API Handlers for the API endpoints and data formats.

    Here's an example using fetch:

    // create a user with two posts
    const r = await fetch(`/api/user/create`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
    include: { posts: true },
    data: {
    email: '',
    posts: {
    create: [{ title: 'Post 1' }, { title: 'Post 2' }],

    console.log(await r.json());


    "id": 1,
    "email": "",
    "posts": [
    "id": 1,
    "createdAt": "2023-03-14T07:45:04.036Z",
    "updatedAt": "2023-03-14T07:45:04.036Z",
    "title": "Post 1",
    "authorId": 1
    "id": 2,
    "createdAt": "2023-03-14T07:45:04.036Z",
    "updatedAt": "2023-03-14T07:45:04.036Z",
    "title": "Post 2",
    "authorId": 1
  3. With third-party client generators

    ZenStack provides an OpenAPI plugin for generating Open API 3.x specification from the ZModel. The generated OpenAPI spec can be used to generate client libraries for various languages and frameworks. For example, you can use openapi-typescript to generate a typescript client.

Error Handling

Refer to the specific sections for RPC Handler and RESTful Handler.

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