Skip to main content
Prisma Documentation Docs

Search documentation

Type to search this documentation.

On this pageOverview

Custom models

As your application grows, you may find the need to group related logic together. We suggest either:

  • Creating static methods using a Prisma Client extension
  • Wrapping a model in a class
  • Extending Prisma Client model object

The following example demonstrates how to create a Prisma Client extension that adds a signUp and findManyByDomain methods to a User model.

Client
import bcrypt from "bcryptjs";

import { PrismaClient } from "../prisma/generated/client";

const prisma = new PrismaClient().$extends({

  model: {

    user: {

      async signUp(email: string, password: string) {

        const hash = await bcrypt.hash(password, 10);

        return prisma.user.create({

          data: {

            email,

            password: {

              create: {

                hash,

              },

            },

          },

        });

      },

      async findManyByDomain(domain: string) {

        return prisma.user.findMany({

          where: { email: { endsWith: `@${domain}` } },

        });

      },

    },

  },

});

async function main() {

  // Example usage

  await prisma.user.signUp("user2@example2.com", "s3cret");

  await prisma.user.findManyByDomain("example2.com");

}
Prisma schema
datasource db {
  provider = "postgresql"
}

generator client {
  provider = "prisma-client"
  output   = "./generated"
}

model User {
  id       String    @id @default(cuid())
  email    String
  password Password?
}

model Password {
  hash   String
  user   User   @relation(fields: [userId], references: [id], onDelete: Cascade)
  userId String @unique
}

In the example below, you'll see how you can wrap the user model in the Prisma Client within a Users class.

import { PrismaClient, User } from "@prisma/client";

type Signup = {

  email: string;

  firstName: string;

  lastName: string;

};

class Users {

  constructor(private readonly prismaUser: PrismaClient["user"]) {}

  // Signup a new user

  async signup(data: Signup): Promise<User> {

    // do some custom validation...

    return this.prismaUser.create({ data });

  }

}

async function main() {

  const prisma = new PrismaClient();

  const users = new Users(prisma.user);

  const user = await users.signup({

    email: "alice@prisma.io",

    firstName: "Alice",

    lastName: "Prisma",

  });

}

With this new Users class, you can define custom functions like signup:

Note that in the example above, you're only exposing a signup method from Prisma Client. The Prisma Client is hidden within the Users class, so you're no longer be able to call methods like findMany and upsert.

This approach works well when you have a large application and you want to intentionally limit what your models can do.

If you want to group custom functions together without hiding existing functionality, use Object.assign to extend Prisma Client:

import { PrismaClient, User } from "@prisma/client";

type Signup = {

  email: string;

  firstName: string;

  lastName: string;

};

function Users(prismaUser: PrismaClient["user"]) {

  return Object.assign(prismaUser, {

    /**

     * Signup the first user and create a new team of one. Return the User with

     * a full name and without a password

     */

    async signup(data: Signup): Promise<User> {

      return prismaUser.create({ data });

    },

  });

}

async function main() {

  const prisma = new PrismaClient();

  const users = Users(prisma.user);

  const user = await users.signup({

    email: "alice@prisma.io",

    firstName: "Alice",

    lastName: "Prisma",

  });

  const numUsers = await users.count();

  console.log(user, numUsers);

}

Now you can use your custom signup method alongside count, updateMany, groupBy() and the other methods that Prisma Client provides, and the result stays type-safe.

We recommend using Prisma Client extensions to extend your models with custom model methods.

Suggest an edit

Propose a replacement for this page. The site team reviews it before applying any changes.

Export
Documentation menu