npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@rs-tech-hub/nestjs-prisma

v1.0.0

Published

A prisma service and module for NestJS applications, providing seamless integration with Prisma ORM for database management.

Readme

@rs-tech-hub/nestjs-prisma

Prisma ORM integration for NestJS applications with PostgreSQL adapter, providing seamless database management, type-safe queries, and repository pattern support.

✨ Features

  • 🔌 PostgreSQL Adapter - Built-in PrismaPg adapter with connection pooling
  • 🎯 Type-Safe Queries - Full TypeScript support with Prisma Client
  • 🏗️ Repository Factory - Generic repository pattern with automatic type inference
  • 🔄 Lifecycle Hooks - Automatic connection management (connect/disconnect)
  • 🧹 Data Cleanup - Helper methods to clean nested Prisma results
  • 🌐 Global Module - Available throughout your application
  • 📝 Comprehensive CRUD - Find, create, update, upsert, delete operations

📋 Prerequisites

  • Node.js ≥ 20.11.1
  • NestJS ≥ 11.1.6
  • TypeScript ≥ 5.1.0
  • Prisma ≥ 7.0.0
  • PostgreSQL database

📦 Installation

npm install @rs-tech-hub/nestjs-prisma \
            @rs-tech-hub/nestjs-service-operation \
            @prisma/client \
            @prisma/adapter-pg \
            @nestjs/common \
            @nestjs/config \
            pg
yarn add @rs-tech-hub/nestjs-prisma \
         @rs-tech-hub/nestjs-service-operation \
         @prisma/client \
         @prisma/adapter-pg \
         @nestjs/common \
         @nestjs/config \
         pg
pnpm add @rs-tech-hub/nestjs-prisma \
         @rs-tech-hub/nestjs-service-operation \
         @prisma/client \
         @prisma/adapter-pg \
         @nestjs/common \
         @nestjs/config \
         pg

Schema

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

// Copy the generated client folder into the @rs-tech-hub/nestjs-prisma module
// -> src/lib/generated/.prisma/client

datasource db {
provider = "postgresql"
}

🚀 Module Registration

Basic Registration

import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { PrismaModule } from '@rs-tech-hub/nestjs-prisma';

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
    }),
    PrismaModule, // Global module - available everywhere
  ],
})
export class AppModule {}

Environment Configuration

Set your database connection string in .env:

DATABASE_URL="postgresql://user:password@localhost:port/mydb?schema=public"

💻 Service Usage

Direct PrismaService Usage

import { Injectable } from '@nestjs/common';
import { PrismaService } from '@rs-tech-hub/nestjs-prisma';

@Injectable()
export class UserService {
  constructor(private prisma: PrismaService) {}

  async findAll() {
    return this.prisma.user.findMany();
  }

  async findOne(id: string) {
    return this.prisma.user.findUnique({
      where: { id },
    });
  }

  async create(data: { name: string; email: string }) {
    return this.prisma.user.create({ data });
  }

  async update(id: string, data: { name?: string; email?: string }) {
    return this.prisma.user.update({
      where: { id },
      data,
    });
  }

  async delete(id: string) {
    return this.prisma.user.delete({
      where: { id },
    });
  }
}

Data Cleanup Helper

Remove Prisma internal fields (fields starting with _):

import { Injectable } from '@nestjs/common';
import { PrismaService } from '@rs-tech-hub/nestjs-prisma';

@Injectable()
export class PostService {
  constructor(private prisma: PrismaService) {}

  async getPostsWithCommentCount() {
    const posts = await this.prisma.post.findMany({
      include: {
        _count: {
          select: { comments: true },
        },
      },
    });

    // Clean up _count and other internal fields
    return this.prisma.cleanupData(posts);
  }
}

🏗️ Repository Pattern

Creating a Repository

Use the factory to create type-safe repositories:

import { Injectable } from '@nestjs/common';
import { PrismaService, createRepository } from '@rs-tech-hub/nestjs-prisma';
import { ServiceFacilitatorService } from '@rs-tech-hub/nestjs-service-operation';
import type { User } from '@prisma/client';

const UserRepositoryBase = createRepository<User, PrismaService['user']>(
  (prisma) => prisma.user,
  'user'
);

@Injectable()
export class UserRepository extends UserRepositoryBase {
  constructor(
    prisma: PrismaService,
    serviceFacilitator: ServiceFacilitatorService
  ) {
    super(prisma, serviceFacilitator);
  }

  // Add custom methods here
  async findByEmail(email: string) {
    return this.findUnique({ email });
  }

  async findActiveUsers() {
    return this.findMany({ isActive: true });
  }
}

Repository Usage in Service

import { Injectable } from '@nestjs/common';

@Injectable()
export class UserService {
  constructor(private userRepository: UserRepository) {}

  async getUser(id: string) {
    return this.userRepository.findUnique({ id });
  }

  async getUserByEmail(email: string) {
    return this.userRepository.findByEmail(email);
  }

  async createUser(data: CreateUserDto) {
    return this.userRepository.create(data);
  }

  async updateUser(id: string, data: UpdateUserDto) {
    return this.userRepository.update({ id }, data);
  }

  async deleteUser(id: string) {
    return this.userRepository.delete({ id });
  }
}

📖 Repository API Reference

Find Methods

findMany(where?, options?)

Find multiple records with optional filtering and pagination.

const users = await repository.findMany(
  { isActive: true },
  {
    orderBy: { createdAt: 'desc' },
    take: 10,
    skip: 0,
    select: { id: true, name: true, email: true },
  }
);

findUnique(where, options?)

Find a unique record by unique identifier.

const user = await repository.findUnique(
  { id: 'user-123' },
  { include: { posts: true } }
);

findWithSelect(where, select)

Find with specific field selection (type-safe).

const user = await repository.findWithSelect(
  { email: '[email protected]' },
  { id: true, name: true, email: true }
);
// Returns: { id: string, name: string, email: string } | null

findManyWithSelect(where?, select?, options?)

Find multiple records with specific field selection.

const users = await repository.findManyWithSelect(
  { isActive: true },
  { id: true, name: true },
  { orderBy: { name: 'asc' }, take: 5 }
);

findOneWithSelect(where?, select?)

Find first record matching criteria with field selection.

const user = await repository.findOneWithSelect(
  { email: '[email protected]' },
  { id: true, name: true }
);

findWithInclude(where?, include?)

Find with included relations.

const user = await repository.findWithInclude(
  { id: 'user-123' },
  { posts: true, profile: true }
);

findManyWithInclude(where?, include?, options?)

Find multiple records with included relations.

const users = await repository.findManyWithInclude(
  { isActive: true },
  { posts: true },
  { orderBy: { createdAt: 'desc' } }
);

findWithFields(where?, fields?)

Find with specific fields (simplified API).

const user = await repository.findWithFields({ id: 'user-123' }, [
  'id',
  'name',
  'email',
]);

findManyWithFields(where?, fields?)

Find multiple records with specific fields.

const users = await repository.findManyWithFields({ isActive: true }, [
  'id',
  'name',
]);

findUniqueWithSelect(where, select)

Find unique record with field selection.

const user = await repository.findUniqueWithSelect(
  { id: 'user-123' },
  { id: true, name: true, email: true }
);

Create/Update Methods

create(data, select?)

Create a new record.

const user = await repository.create({
  name: 'John Doe',
  email: '[email protected]',
});

update(where, data, select?)

Update an existing record.

const user = await repository.update({ id: 'user-123' }, { name: 'Jane Doe' });

upsert(where, create, update, select?)

Create if not exists, update if exists.

const user = await repository.upsert(
  { email: '[email protected]' },
  { name: 'John Doe', email: '[email protected]' },
  { name: 'John Updated' }
);

Delete Methods

delete(where)

Delete a single record.

const deleted = await repository.delete({ id: 'user-123' });

deleteMany(where?)

Delete multiple records.

const result = await repository.deleteMany({ isActive: false });
// Returns: { count: number }

Utility Methods

count(where?)

Count records matching criteria.

const total = await repository.count({ isActive: true });

exists(where?)

Check if records exist.

const hasUsers = await repository.exists({ isActive: true });

Data Cleanup

cleanupData(data)

Remove internal Prisma fields (starting with _).

const cleanData = this.prisma.cleanupData(result);

📊 Advanced Usage

Transactions

import { Injectable } from '@nestjs/common';
import { PrismaService } from '@rs-tech-hub/nestjs-prisma';

@Injectable()
export class OrderService {
  constructor(private prisma: PrismaService) {}

  async createOrderWithItems(orderData: any, items: any[]) {
    return this.prisma.$transaction(async (tx) => {
      const order = await tx.order.create({ data: orderData });

      const orderItems = await Promise.all(
        items.map((item) =>
          tx.orderItem.create({
            data: { ...item, orderId: order.id },
          })
        )
      );

      return { order, orderItems };
    });
  }
}

Raw Queries

const users = await this.prisma.$queryRaw`
  SELECT * FROM "User" WHERE "email" = ${email}
`;

Middleware

constructor(configService: ConfigService) {
  super(/* ... */);

  this.$use(async (params, next) => {
    const before = Date.now();
    const result = await next(params);
    const after = Date.now();
    console.log(`Query ${params.model}.${params.action} took ${after - before}ms`);
    return result;
  });
}

💡 Best Practices

  1. Use Repository Pattern: Encapsulate data access logic in repositories
  2. Type Safety: Leverage TypeScript for compile-time type checking
  3. Connection Pooling: The service uses pg Pool for efficient connection management
  4. Transactions: Use $transaction for operations that must succeed or fail together
  5. Select Fields: Use select to fetch only needed fields for better performance
  6. Error Handling: Repository methods use ServiceFacilitator for consistent error handling
  7. Cleanup Data: Use cleanupData() to remove Prisma internal fields from API responses

📄 License

This package is free and open source under the MIT License.

🆘 Support

For issues, questions, or contributions, please visit the RS-Tech-Hub repository.