Use Prisma migrations as the authoritative history of application schema changes.
Course navigationPhase 09⌄
Prisma 7.9.1 Architecture, Configuration & Migrations
Integrate Prisma 7.9.1 as a repeatable persistence layer with schema, generated client, adapter/configuration, migrations, and NestJS lifecycle.
Phase outcome and project increment
Learning outcome
Integrate Prisma 7.9.1 as a repeatable persistence layer with schema, generated client, adapter/configuration, migrations, and NestJS lifecycle.
Concrete deliverable
Prisma schema + migration history + generated client + NestJS PrismaService connected to TaskFlow PostgreSQL.
Principles to keep while coding
Keep generated Prisma Client code derived from the schema instead of hand-editing it.
Use a shared Prisma service in NestJS so connection lifecycle and access patterns remain controlled.
Pin Prisma versions deliberately when the course architecture depends on a specific configuration model.
Guided phase lab
Do these in order. Each step should end with evidence before the next one starts.
- 01
Pin Prisma packages to the course version contract and verify all Prisma package versions match.
- 02
Initialize Prisma with the intended generated-client output and PostgreSQL configuration.
- 03
Model one entity, create the first migration, and inspect the SQL before applying it.
- 04
Generate the client and wire a PrismaService into NestJS with controlled lifecycle.
- 05
Perform a smoke query through the service, then inspect the created database object independently.
- 06
Cause a safe migration/configuration failure and practice reading Prisma error codes instead of reinstalling randomly.
pnpm exec prisma version
pnpm exec prisma validate
pnpm exec prisma migrate dev --name <name>
pnpm exec prisma generatePredict what each command proves before running it. A command is useful only when its output answers a question.
Failures you should know how to diagnose
CLI/client version mismatch
Predict the symptom, capture evidence at the nearest boundary, change one variable, and verify the same reproduction after the fix.
Editing generated client code
Predict the symptom, capture evidence at the nearest boundary, change one variable, and verify the same reproduction after the fix.
Using db push as a substitute for migration history in team environments
Predict the symptom, capture evidence at the nearest boundary, change one variable, and verify the same reproduction after the fix.
Creating a new PrismaClient per request
Predict the symptom, capture evidence at the nearest boundary, change one variable, and verify the same reproduction after the fix.
Lessons
The source chapters come first. Every phase now ends with a guided build, a debugging workshop, and an independent challenge so reading turns into transferable skill.
Prisma Mental Model and Architecture
PHASE 09 / BOOK 01 Prisma Mental Model & Architecture Understand every Prisma layer before installing it NestJS PrismaService Prisma Client PrismaPg driver adapter Supabase PostgreSQL Figure
Install and Lock Prisma 7 9 1
PHASE 09 / BOOK 02 Install & Lock Prisma 7.9.1 Exact dependencies, local CLI and reproducible tooling NestJS PrismaService Prisma Client PrismaPg driver adapter Supabase PostgreSQL Figure -
Prisma Init and File Anatomy
PHASE 09 / BOOK 03 prisma init & File Anatomy Understand the files before editing them NestJS PrismaService Prisma Client PrismaPg driver adapter Supabase PostgreSQL Figure - The database ac
Schema Generator and First Model
PHASE 09 / BOOK 04 Schema, Generator & First Model Prisma Schema Language without hiding the relational model NestJS PrismaService Prisma Client PrismaPg driver adapter Supabase PostgreSQL F
Prisma Config Supabase URLs and Shadow Database
PHASE 09 / BOOK 05 Prisma Config, Supabase URLs & Shadow Database Separate runtime traffic from migration tooling NestJS PrismaService Prisma Client PrismaPg driver adapter Supabase PostgreS
Prisma Client Adapter and NestJS PrismaService
PHASE 09 / BOOK 06 Prisma Client, PrismaPg & NestJS PrismaService Turn generated types into reusable backend infrastructure NestJS PrismaService Prisma Client PrismaPg driver adapter Supabas
Migration Lifecycle and First Migration
PHASE 09 / BOOK 07 Migration Lifecycle & First Migration Create schema history you can inspect, commit and deploy NestJS PrismaService Prisma Client PrismaPg driver adapter Supabase PostgreS
Prisma CLI Workflow Development and Production
PHASE 09 / BOOK 08 Prisma CLI Workflow: Development & Production Use the smallest correct command for each stage NestJS PrismaService Prisma Client PrismaPg driver adapter Supabase PostgreSQ
Debugging Prisma and Common Failures
PHASE 09 / BOOK 09 Debugging Prisma & Common Failures Diagnose the failing layer instead of replacing the project NestJS PrismaService Prisma Client PrismaPg driver adapter Supabase PostgreS
Hands On Lab and Phase Exit
PHASE 09 / BOOK 10 Hands-On Lab & Phase Exit Install, configure, integrate, migrate and explain the system NestJS PrismaService Prisma Client PrismaPg driver adapter Supabase PostgreSQL Figu
Guided Build Lab
Purpose Integrate Prisma 7.9.1 as a repeatable persistence layer with schema, generated client, adapter/configuration, migrations, and NestJS lifecycle.
Debugging Workshop
Goal Learn to diagnose this phase's failures systematically instead of reinstalling packages, changing random configuration, or copying a fix without understanding it.
Phase Synthesis & Independent Challenge
Mission Rebuild the capability of Phase 09 without following the exact code line-by-line. The goal is transfer: can you use the ideas when the variable names, UI, or route shape changes?
Mastery Capstone Lab
Integrate Phase 09 without following a transcript.
Exercises that increase independence
Pin Prisma packages to the course version contract and verify all Prisma package versions match.
Model one entity, create the first migration, and inspect the SQL before applying it.
reproduce and diagnose — CLI/client version mismatch.
deliver Prisma schema + migration history + generated client + NestJS PrismaService connected to TaskFlow PostgreSQL.
Can explain schema vs migration vs generated client and Can create and inspect a migration.
Do not leave the phase only because you reached the bottom
Phase exit criteria
Scenario and concept quiz
These questions test engineering choices rather than whether you remember a lesson title.
Reference files
Attempt the work first. Use snapshots to compare a checkpoint, not as a substitute for understanding.
reference/TaskFlow_Prisma_Snapshot/.env.example
# Runtime application connection (Phase 08 recommends a session-capable pooled URL for local NestJS). DATABASE_URL= # Prisma CLI / migration connection. Prefer a direct URL when reachable. DIRECT_URL= # Optional only if migrate dev cannot create an automatic shadow database. # NEVER point this at the same database as DIRECT_URL. SHADOW_DATABASE_URL=
reference/TaskFlow_Prisma_Snapshot/README.txt
TaskFlow Phase 09 Prisma reference snapshot These files are reference outputs for the end of Phase 09. Do not paste them blindly over an existing project. Compare responsibilities and adapt the existing files. Important: - Prisma packages are locked to 7.9.1. - DATABASE_URL is for runtime PrismaPg. - DIRECT_URL is for Prisma CLI/migrations. - If SHADOW_DATABASE_URL is used, it must point to a separate disposable shadow database. - src/generated/prisma is generated by `pnpm exec prisma generate`; it is intentionally not included here.
reference/TaskFlow_Prisma_Snapshot/install-prisma.ps1
pnpm add -D prisma@7.9.1 @types/pg pnpm add @prisma/client@7.9.1 @prisma/adapter-pg@7.9.1 pg dotenv @nestjs/config
reference/TaskFlow_Prisma_Snapshot/prisma/schema.prisma
generator client {
provider = "prisma-client"
output = "../src/generated/prisma"
moduleFormat = "cjs"
}
datasource db {
provider = "postgresql"
}
model Todo {
id String @id @default(cuid())
title String
completed Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}reference/TaskFlow_Prisma_Snapshot/prisma.config.ts
import "dotenv/config";
import { defineConfig, env } from "prisma/config";
export default defineConfig({
schema: "prisma/schema.prisma",
migrations: {
path: "prisma/migrations",
},
datasource: {
// CLI / migrations: direct or session-capable connection.
url: env("DIRECT_URL"),
},
});reference/TaskFlow_Prisma_Snapshot/src/app.module.ts
import { Module } from "@nestjs/common";
import { ConfigModule } from "@nestjs/config";
import { HealthModule } from "./health/health.module";
import { TodosModule } from "./todos/todos.module";
import { PrismaModule } from "./prisma/prisma.module";
@Module({
imports: [
ConfigModule.forRoot({ isGlobal: true }),
PrismaModule,
HealthModule,
TodosModule,
],
})
export class AppModule {}reference/TaskFlow_Prisma_Snapshot/src/prisma/prisma.module.ts
import { Global, Module } from "@nestjs/common";
import { PrismaService } from "./prisma.service";
@Global()
@Module({
providers: [PrismaService],
exports: [PrismaService],
})
export class PrismaModule {}reference/TaskFlow_Prisma_Snapshot/src/prisma/prisma.service.ts
import { Injectable, OnModuleDestroy, OnModuleInit } from "@nestjs/common";
import { ConfigService } from "@nestjs/config";
import { PrismaPg } from "@prisma/adapter-pg";
import { PrismaClient } from "../generated/prisma/client";
@Injectable()
export class PrismaService
extends PrismaClient
implements OnModuleInit, OnModuleDestroy
{
constructor(config: ConfigService) {
const connectionString = config.getOrThrow<string>("DATABASE_URL");
const adapter = new PrismaPg({ connectionString });
super({ adapter });
}
async onModuleInit() {
await this.$connect();
}