This guide continues from Get started and replaces the in-memory user repository with Prisma and PostgreSQL.
By the end of this guide, users created through /auth/sign-up will be stored in a persistent database instead of memory.
Prerequisites
Section titled “Prerequisites”- A project completed from Get started
- A PostgreSQL database
Install Prisma
Section titled “Install Prisma”Install Prisma, Prisma Client, the PostgreSQL driver adapter, and pg:
pnpm add -D prismapnpm add @prisma/client @prisma/adapter-pg pgnpm install -D prismanpm install @prisma/client @prisma/adapter-pg pgyarn add -D prismayarn add @prisma/client @prisma/adapter-pg pgInitialize Prisma
Section titled “Initialize Prisma”Run the Prisma init command from the project root:
pnpm dlx prisma init --output ../generated/prismanpx prisma init --output ../generated/prismayarn dlx prisma init --output ../generated/prismaThis creates a prisma/schema.prisma file and configures the generated Prisma Client output path.
Configure the database connection
Section titled “Configure the database connection”Add DATABASE_URL to your existing .env file:
DATABASE_URL="postgresql://USER:PASSWORD@localhost:5432/DB_NAME?schema=public"Replace USER, PASSWORD, and DB_NAME with your PostgreSQL username, password, and database name.
Define the user model
Section titled “Define the user model”Update prisma/schema.prisma:
generator client { provider = "prisma-client" output = "../generated/prisma" moduleFormat = "cjs"}
datasource db { provider = "postgresql"}
model User { id Int @id @default(autoincrement()) name String email String @unique password String}The User model matches the example user shape from Get started. brkpt-auth does not require this exact model. Your adapters decide which fields are used for JWT payloads, password validation, and safe user responses.
Run the migration
Section titled “Run the migration”Create and apply the initial migration:
pnpm dlx prisma migrate dev --name initnpx prisma migrate dev --name inityarn dlx prisma migrate dev --name initThen generate Prisma Client:
pnpm dlx prisma generatenpx prisma generateyarn dlx prisma generateCreate PrismaModule
Section titled “Create PrismaModule”Create the following files:
Directorysrc/
Directoryprisma/
- prisma.module.ts
- prisma.service.ts
Create PrismaService
Create prisma.service.ts and wrap the generated PrismaClient:
import { Injectable } from '@nestjs/common';import { PrismaPg } from '@prisma/adapter-pg';
import { PrismaClient } from '../../generated/prisma/client';
@Injectable()export class PrismaService extends PrismaClient { constructor() { const adapter = new PrismaPg({ connectionString: process.env.DATABASE_URL as string, });
super({ adapter }); }}Create PrismaModule
Create prisma.module.ts and export PrismaService so the adapters can inject it:
import { Module } from '@nestjs/common';
import { PrismaService } from './prisma.service';
@Module({ providers: [PrismaService], exports: [PrismaService],})export class PrismaModule {}Replace UserModule with PrismaModule
Section titled “Replace UserModule with PrismaModule”In Get started, BrkptAuthModule imported UserModule so the adapters could inject MemoryUserRepository.
Now replace UserModule with PrismaModule:
import { UserModule } from '../user/user.module';import { PrismaModule } from '../prisma/prisma.module';
@Module({ imports: [UserModule], imports: [PrismaModule], controllers: [...features.flatMap((f) => f.controllers)], providers: [...features.flatMap((f) => f.providers)],})export class BrkptAuthModule { // ...}Update the adapters
Section titled “Update the adapters”The brkpt-auth features do not need to change. Only the adapters need to use PrismaService instead of MemoryUserRepository.
Update CoreAdapter
Update CoreAdapter to use PrismaService instead of MemoryUserRepository:
import { Injectable } from '@nestjs/common';
import { User } from '../../../generated/prisma/client';import { PrismaService } from '../../prisma/prisma.service';import { CorePort } from '../features/core/core.port';import { AuthJwtPayload } from './types';
@Injectable()export class CoreAdapter implements CorePort<User> { constructor(private readonly prisma: PrismaService) {}
mapUserToJwtPayload(user: User): AuthJwtPayload { return { sub: user.id, email: user.email, }; }
shrinkJwtPayload(payload: AuthJwtPayload): Record<string, unknown> { return { sub: payload.sub, }; }
findUserByJwtPayload(payload: AuthJwtPayload): Promise<User | null> { return this.prisma.user.findUnique({ where: { id: payload.sub, }, }); }
toSafeUser(user: User): Record<string, unknown> { const { password: _password, ...safe } = user; return safe; }
extractUserIdFromJwtPayload(payload: AuthJwtPayload): number { return payload.sub; }}Update CredentialsAdapter
Update CredentialsAdapter to use PrismaService instead of MemoryUserRepository:
import { Injectable } from '@nestjs/common';import * as bcrypt from 'bcrypt';
import { User } from '../../../generated/prisma/client';import { PrismaService } from '../../prisma/prisma.service';import { CredentialsPort } from '../features/credentials/credentials.port';import { SignInDto } from '../features/credentials/dto/sign-in.dto';import { SignUpDto } from '../features/credentials/dto/sign-up.dto';
@Injectable()export class CredentialsAdapter implements CredentialsPort<User> { constructor(private readonly prisma: PrismaService) {}
findUserByDto(dto: SignInDto | SignUpDto): Promise<User | null> { return this.prisma.user.findUnique({ where: { email: dto.email, }, }); }
validatePassword(user: User, dto: SignInDto): Promise<boolean> { return bcrypt.compare(dto.password, user.password); }
async createUser(dto: SignUpDto): Promise<User> { const password = await bcrypt.hash(dto.password, 10); return this.prisma.user.create({ data: { name: dto.name, email: dto.email, password, }, }); }
extractUserIdFromUser(user: User): number { return user.id; }}Remove the in-memory user module
Section titled “Remove the in-memory user module”You can now remove the src/user/ folder created in Get started:
Directorysrc/
Directoryuser/
Directoryrepositories/
- memory-user.repository.ts
- user.entity.ts
- user.module.ts
That folder only existed to provide MemoryUserRepository for the in-memory example. After switching the adapters to PrismaService, it is no longer used.
Run and verify
Section titled “Run and verify”Start the application:
pnpm start:devnpm run start:devyarn start:devCreate a user through /auth/sign-up, restart the server, then sign in with the same account again.
The sign-in request should still succeed because the user is now stored in PostgreSQL.