Skip to main content

Modern Data Layer for TypeScript Applications

Intuitive data modeling, type-safe ORM, built-in access control, automatic query services, and more.

Coherent Schema

Coherent Schema

Simple schema language to capture the most important aspects of your application in one place: data and security.

Powerful ORM

Powerful ORM

One-of-a-kind ORM that combines type-safety, query flexibility, and access control in one package.

Limitless Utility

Limitless Utility

Deriving crucial artifacts that streamline development from backend APIs to frontend components.

Intuitive and Expressive Data Modeling

The modeling language allows you to
  • ✅ Define data models and relations
  • ✅ Define access control policies
  • ✅ Express data validation rules
  • ✅ Model polymorphic inheritance
  • ✅ Add custom attributes and functions to introduce custom semantics
  • ✅ Implement custom code generators
The schema language is a superset of Prisma Schema Language. Migrating a Prisma schema is as simple as file renaming.
model User {
id Int @id
email String @unique @email // constraint and validation
role String
posts Post[] // relation to another model
postCount Int @computed // computed field

// access control rules colocated with data
@@allow('all', auth().id == id)
@@allow('create, read', true)
}

model Post {
id Int
title String @length(1, 255)
published Boolean @default(false)
author User @relation(fields: [authorId], references: [id])
authorId Int // relation foreign key

@@allow('read', published)
@@allow('all', auth().id == authorId || auth().role == 'ADMIN')
}

Flexible and Awesomely Typed ORM

import { schema } from './zenstack';
import { ZenStackClient } from '@zenstackhq/runtime';

const db = new ZenStackClient(schema, { ... });

// high-level query API
const usersWithPosts = await db.user.findUnique({
where: { id: userId },
include: { posts: true }
});

// low-level SQL query builder API
const userPostJoin = await db
.$qb
.selectFrom('User')
.innerJoin('Post', 'Post.authorId', 'User.id')
.select(['User.id', 'User.email', 'Post.title'])
.where('User.id', '=', userId)
.execute();
An ORM is derived from the schema that gives you
  • 🔋 High-level ORM query API
  • 🔋 Low-level SQL query builder API
  • 🔋 Access control enforcement
  • 🔋 Runtime data validation
  • 🔋 Computed fields and custom procedures
  • 🔋 Plugin system for tapping into various lifecycle events
ZenStack's ORM is built on top of the awesome Kysely SQL query builder. Its query API is compatible with that of Prisma Client, so migrating an existing Prisma project will require minimal code changes.

Automatic HTTP Query Service
coming soon

Thanks to the ORM's built-in access control, you get an HTTP query service for free
  • 🚀 Fully mirrors the ORM API
  • 🚀 Seamlessly integrates with popular frameworks
  • 🚀 Works with any authentication solution
  • 🚀 Type-safe client SDK powered by TanStack Query
  • 🚀 Highly customizable

Since the ORM is protected with access control, ZenStack can directly map it to an HTTP service. ZenStack provides out-of-the-box integrations with popular frameworks including Next.js, Nuxt, Express, etc.

Client hooks based on TanStack Query can also be derived from the schema, allowing you to make type-safe queries to the service without writing a single line of code.

Next.js Example
import { NextRequestHandler } from '@zenstackhq/server/next';
import { db } from './db'; // ZenStackClient instance
import { getSessionUser } from './auth';

// callback to provide a per-request ORM client
async function getClient() {
// call a framework-specific helper to get session user
const authUser = await getSessionUser();

// return a new ORM client configured with the user,
// the user info will be used to enforce access control
return db.$setAuth(authUser);
}

// Create a request handler for all requests to this route
// All CRUD requests are forwarded to the underlying ORM
const handler = NextRequestHandler({ getClient });

export {
handler as GET,
handler as PUT
handler as POST,
handler as PATCH,
handler as DELETE,
};

Perfect Match for AI-Assisted Programming

Coherent Application Model

Coherent Application Model

When LLMs see a self-contained, non-ambiguous, and well-defined application model, their inference works more efficiently and effectively.

Concise Query API

Concise Query API

Concise and expressive, while leveraging existing knowledge of Prisma and Kysely, the query API makes it easy for LLMs to generate high-quality query code.

Slim Code Base

Slim Code Base

By deriving artifacts from the schema instead of implementing them, ZenStack helps you maintain a slim code base that is easier for AI to digest.