Skip to content

arthurfiorette/prisma-json-types-generator

Repository files navigation

Using this package? Please consider donating to support my open source work ❤️
Help prisma-json-types-generator grow! Star and share this amazing repository with your friends and co-workers!


License Downloads Packagephobia Last commit



Prisma Json Types Generator

Generate your prisma client with strict JSON types and String literals!




Supercharge your @prisma/client by adding strong, custom types to Json and String fields. This generator enhances type safety by replacing Prisma's default JsonValue with your own TypeScript types, ensuring data conforms to your schema before it even reaches the database.

It works with all database drivers supported by Prisma (PostgreSQL, MySQL, SQLite, etc.) without affecting any runtime code.


Key Features

  • Strongly Typed Json: Define complex object shapes for your Json fields.
  • String-Based Enums: Type String fields to create enums without needing native database enums.
  • Full Type-Safety: Get autocomplete, intellisense, and compile-time checks for your data structures.
  • Zero Runtime Overhead: All transformations happen at generation time.
  • Flexible Typing: Define types globally in a namespace or inline directly in your schema.

Installation

Install the package as a development dependency in your project.

npm install -D prisma-json-types-generator

Quick Start

Follow these three steps to get started.

  1. Add the Generator to Your Schema

    In your schema.prisma file, add the json generator block below the default client generator.

    generator client {
      provider = "prisma-client-js"
    }
    
    generator json {
      provider = "prisma-json-types-generator"
    }
  2. Define Your Custom Types

    Create a type declaration file (e.g., src/types.ts) and ensure it's included in your tsconfig.json. Define your types inside the PrismaJson global namespace.

    // This file must be a module, so we include an empty export.
    export {};
    
    declare global {
      namespace PrismaJson {
        // Define a type for a user's profile information.
        type UserProfile = {
          theme: 'dark' | 'light';
          twitterHandle?: string;
        };
      }
    }
  3. Link Types in Your Prisma Schema

    Use an AST comment (/// [TypeName]) above a Json field in your schema.prisma to link it to your custom type.

    model User {
      id    Int    @id @default(autoincrement())
      email String @unique
    
      /// [UserProfile]
      profile Json
    }

Now, run npx prisma generate. The profile field on the User model will be strongly typed!

import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();

async function updateUserProfile() {
  const user = await prisma.user.update({
    where: { id: 1 },
    data: {
      profile: {
        theme: 'dark'
        // twitterHandle is optional
      }
    }
  });

  // user.profile is now fully typed as UserProfile!
  console.log(user.profile.theme); // 'dark'
}

Typing String Fields (Enums)

You can use the same technique to type String fields, which is perfect for creating "string enums" without using Prisma's native enum type. This is useful for maintaining a set of allowed values directly in your application code.

Use the inline type syntax (/// ![Type]) for this.

model Post {
  id    Int    @id @default(autoincrement())
  title String

  /// !['draft' | 'published' | 'archived']
  status String @default("draft")
}

After generating, post.status will be correctly typed as 'draft' | 'published' | 'archived'.


Advanced Typing

The generator offers two ways to define types:

  1. Namespace-based (/// [TypeName]): References a type from the PrismaJson namespace. Best for complex, reusable types.
  2. Inline (/// ![Type]): Defines the type directly in the schema. Best for simple, one-off types like enums or basic objects.

Examples

model Product {
  id Int @id

  // Namespace-based type
  /// [ProductMeta]
  meta Json?

  // Array of namespace-based types
  /// [Tag]
  tags Json[]

  // Inline union type (enum)
  /// !['physical' | 'digital']
  type String

  // Inline object type
  /// ![{ width: number; height: number }]
  dimensions Json
}
export {};

declare global {
  namespace PrismaJson {
    type ProductMeta = {
      sku: string;
      stock: number;
    };

    type Tag = {
      id: string;
      name: string;
    };
  }
}

Configuration

You can configure the generator in your schema.prisma file.

generator json {
  provider  = "prisma-json-types-generator"
  namespace = "PrismaJson"
  allowAny  = false
  // etc...
}
Option Description Default
namespace The global namespace where your custom types are defined. "PrismaJson"
clientOutput Path to the @prisma/client output directory. The generator usually finds this automatically, but you can specify it if needed (e.g., in complex monorepos). (auto-detected)
allowAny If true, untyped Json fields will resolve to any. If false, they will resolve to unknown for stricter type safety. false
useType Specifies a root type within your namespace to use as a fallback for all untyped Json fields. This adds an index signature [key: string]: any to the specified type. undefined

Limitations

  • Complex Filters: To preserve functionality, types like JsonFilter and JsonWithAggregatesFilter remain untyped.
  • Prisma Version: This generator supports Prisma v5+ and generator v3+.
  • Known Gaps: If you find any Json fields that are not being typed correctly, please open an issue.

How It Works

This tool operates as a standard Prisma generator. When npx prisma generate runs, the generator receives the Data Model Meta Format (DMMF), which contains your full schema, including the AST comments. After prisma-client-js finishes, this generator targets its output declaration file (e.g., index.d.ts) and parses it into an Abstract Syntax Tree (AST) using the TypeScript Compiler API.

It then traverses this AST, and for each property signature in a model, it cross-references the DMMF to find a corresponding type comment. If a match is found, it performs a direct AST transformation, replacing the original type node (like Prisma.JsonValue or string) with a new node representing your custom type. Finally, the modified AST is printed back into TypeScript code, overwriting the original declaration file. This entire process occurs at build time and adds no runtime overhead. For a deeper dive, see the core implementation.


License

Licensed under the MIT. See LICENSE for more informations.