DEV Community

explita
explita

Posted on

Stop manually stripping Prisma inputs. Generate Zod schemas & guard your DB automatically.

If you use Prisma, you already know it's a fantastic ORM with excellent developer experience. But there's a common friction point almost all of us hit when building real-world APIs: input validation and sanitization.

Prisma is strict. If a user passes an unknown field in a .create() or .update() payload (like an injected isAdmin: true), Prisma throws an error. So what do you do? You end up writing tedious mapping functions, picking fields manually, or writing massive Zod schemas by hand to validate and strip out the junk before it reaches Prisma.

What if your Prisma schema could just... do it all for you?

Enter Prisma Guard 🛡️.


What is Prisma Guard?

Prisma Guard is the ultimate Prisma companion designed to bridge the gap between database models and API validation. It does two main things:

  1. Runtime Protection (The Guard): A Prisma Client extension that silently strips unknown fields from your queries at runtime.
  2. Schema Generation (The Magic): Automatically transforms your .prisma models into robust, decorated Zod schemas with complete type-safety.

It's completely zero-config out of the box (it even manages your .gitignore and Prettier formatting for generated files), but offers immense power for those who need custom validation logic.


✌️ Two Ways to Use It

Depending on your needs, you can use Prisma Guard in two modes.

Mode 1: Runtime Protection Only (The Quick Fix)

If you just want to stop Prisma from throwing errors when random fields are passed from the frontend, just add the extension to your client:

import { PrismaClient } from "@prisma/client";
import { prismaGuard } from "@explita/prisma-guard";

const prisma = new PrismaClient().$extends(prismaGuard());

// Any extra fields passed to 'data' will be silently stripped
await prisma.user.create({
  data: {
    email: "user@example.com",
    poisonField: "will be removed", // Poof! Gone.
  },
});
Enter fullscreen mode Exit fullscreen mode

Mode 2: Full Validation & Schema Generation (Recommended)

This is where the real magic happens. By running npx prisma-guard, it reads your Prisma schema and generates perfect Zod schemas.

Your Prisma Schema:

model User {
  id        String   @id @default(cuid())
  email     String   @unique
  password  String
  createdAt DateTime @default(now())
}
Enter fullscreen mode Exit fullscreen mode

What you get:

export const UserCreateSchema = z.object({
  email: z.string().trim().min(1, { message: "This field is required" }),
  password: z.string().trim().min(1),
  // id and createdAt are managed by Prisma defaults or omitted entirely depending on your config!
});
Enter fullscreen mode Exit fullscreen mode

💎 Advanced Type Ergonomics & Dual Schemas

One of the biggest headaches with schema generation is that a "public" API schema shouldn't include sensitive internal database fields (like secretApiKey or tenantId).

Prisma Guard handles this beautifully by generating Dual Schemas for every model:

  1. Public Schemas (UserCreateSchema): Respects your omission rules. Perfect for API request validation.
  2. Scalar Schemas (UserCreateScalarSchema): Includes every database field. Perfect for internal services and database operations.

It also exports a suite of ergonomic TypeScript types (UserCreate, UserUpdate, UserCreateRequired) so your service layers are always perfectly typed.


🎨 The Power of Decorators (and the v proxy)

Sometimes z.string() isn't enough. You need .email(), .min(8), or custom refinement logic. Prisma Guard lets you define this cleanly using triple-slash comments (///).

Instead of polluting your Prisma schema with massive strings of Zod code, Prisma Guard introduces the v proxy in a prisma-guard.config.js file:

// prisma-guard.config.js
import { defineConfig, v } from "@explita/prisma-guard";

export default defineConfig({
  decorators: {
    // Chain validations onto the inferred Prisma type
    email: v.chain.email().trim().toLowerCase(),

    // Completely override a type
    strongPassword: v.string().min(12).regex(/[A-Z]/),
  },
});
Enter fullscreen mode Exit fullscreen mode

Then, you just use them in your Prisma schema!

model User {
  id       String @id

  /// @zod.use(email)
  email    String

  /// @zod.use(strongPassword)
  password String
}
Enter fullscreen mode Exit fullscreen mode

IDE Superpowers 🪄

No one likes typing out decorators from memory. Prisma Guard includes an incredible npx prisma-guard metadata --vscode command that automatically installs VS Code snippets for every Zod method. You literally get autocompletion inside your .prisma files!


⚡ Blazing Fast Performance

You might be thinking: "Doesn't a runtime guard slow down my queries?"

The answer is no. The runtime guard is designed for ultra-low latency. It uses strict $O(n)$ complexity (looping only over predefined schema fields instead of arbitrary user input), memoized whitelists, and hot-path early exits.

In benchmarks of 100,000 recursive sanitization iterations on a complex payload:

  • Total duration: 221.26ms
  • Average per query: 2.21 microseconds (0.0022ms)

If your database query takes 10-50ms, adding 0.0022ms introduces virtually 0% overhead.


🚀 Get Started in 2 Minutes

Stop wasting time manually maintaining Zod schemas that drift out of sync with your database.

  1. Install the package:
npm install @explita/prisma-guard
Enter fullscreen mode Exit fullscreen mode
  1. Initialize your config:
npx prisma-guard init
Enter fullscreen mode Exit fullscreen mode
  1. Generate the magic:
npx prisma-guard
Enter fullscreen mode Exit fullscreen mode

Check out the full documentation, advanced relation handling, and custom schema generation features on our GitHub Repository.

If Prisma Guard saves you time, I'd deeply appreciate a ⭐ on GitHub! Let me know what you think in the comments below. Happy coding! 🚀

Top comments (0)