Retour • 09/02/2025
Guide complet de Prisma avec NextJS
Écris par Melvyn Malherbe le 09/02/2025
Je vais t'expliquer comment utiliser Prisma dans une application JavaScript en prenant notamment l'exemple de NextJS.
Ce guide va tout t'expliquer :
- Comment installer Prisma
- Comment fonctionne le système de migration de Prisma
- Comment utiliser Prisma dans ton application
- Usage avancé de Prisma
- Prisma avec TypeScript
Comment installer Prisma
Prisma vient avec deux librairies :
prisma
C'est la librairie principale de Prisma
qui va être installée dans les dépendances de dev
. Elle permet principalement d'exécuter des commandes dans le terminal pour faire des actions.
@prisma/client
C'est la librairie qui va être dans les dépendances et c'est elle qui va permettre de faire des requêtes à la base de données.
Pour installer Prisma, il y a une commande qu'on peut exécuter :
npx prisma init
Cette commande va installer les dépendances nécessaires et rajouter un dossier prisma
dans ton projet avec un fichier schema.prisma
.
Ce fichier schema.prisma
va nous permettre de définir les tables de notre base de données.
On va partir sur le principe que tu utilises PostgreSQL
comme base de données, tu vas devoir modifier le fichier schema.prisma
pour ajouter ta DATABASE_URL
dans le fichier .env
.
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
Et dans ton fichier .env
, tu vas ajouter :
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/postgres
Ensuite tu peux ajouter tes tables et relations. Voici l'exemple de la documentation :
model Post {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
title String @db.VarChar(255)
content String?
published Boolean @default(false)
author User @relation(fields: [authorId], references: [id])
authorId Int
}
model Profile {
id Int @id @default(autoincrement())
bio String?
user User @relation(fields: [userId], references: [id])
userId Int @unique
}
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
posts Post[]
profile Profile?
}
Ici tu peux voir qu'on a des relations, en installant l'extension VSCode Prisma
tu verras qu'il t'aide super bien à créer des schémas cohérents.
Une fois qu'on a ajouté ça, on doit créer une migration.
Comment fonctionne le système de migration de Prisma
Le système de migration est un système populaire dans les bases de données qui permet de venir modifier la structure de ta base de données de manière évolutive.
C'est-à-dire que chaque fois qu'on va modifier le schéma, on va créer une migration, cette migration va venir modifier la base de données et potentiellement les données.
Ensuite quand on vient lancer la migration, celle-ci va appliquer chaque migration dans l'ordre, ce qui permet de faire des migrations sans risquer de perdre des données.
Pour créer une migration, on peut utiliser la commande suivante :
npx prisma migrate dev
Cette commande va créer une migration et l'appliquer à la base de données. Tu verras qu'il va te demander un nom pour la migration, tu peux simplement inscrire "init database" ou "initial migration".
Modification de la base de données
Imagine qu'on souhaite remplacer name
par firstname
et lastname
dans notre schéma. Dans ce cas-là, on va modifier
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
firstname String?
lastname String?
posts Post[]
profile Profile?
}
Dans ce cas-là c'est compliqué car on va perdre des données, car si on fait une migration qui supprime le champ name
et rajoute firstname
et lastname
, on va perdre toutes les données de name
.
Pour éviter ça, on va créer une nouvelle migration qui va venir ajouter les champs firstname
et lastname
et les remplir avec les données de name
.
npx prisma migrate --create-only --name add-firstname-lastname
Cette commande va créer un fichier de migration dans ton projet, tu peux le voir dans le dossier prisma/migrations
.
Ensuite on va pouvoir faire du SQL :
- Ajouter les champs
firstname
etlastname
- Remplir le champ
firstname
par le champname
- Supprimer le champ
name
Voici le code SQL :
ALTER TABLE "User" ADD COLUMN "firstname" text;
ALTER TABLE "User" ADD COLUMN "lastname" text;
UPDATE "User" SET "firstname" = "name";
ALTER TABLE "User" DROP COLUMN "name";
Et de cette manière, quand on va déployer notre site sur notre database de production, la migration va se faire et on va éviter de perdre des données.
Cette migration va ensuite s'effectuer chaque fois qu'on va lancer les migrations sur une "nouvelle base de données".
Les migrations viennent générer le @prisma/client
Le @prisma/client
est généré en fonction de ton schéma. C'est-à-dire que tous les types sont générés chaque fois que tu fais une migration. Tu peux aussi générer les types avec la commande suivante :
npx prisma generate
Cette commande va venir générer le @prisma/client
et les types dans le dossier node_modules
.
C'est comme ça qu'ensuite tu vas pouvoir faire des requêtes à la base de données de manière "type-safe".
Comment utiliser Prisma dans ton application
Pour ajouter Prisma, on va utiliser un Singleton expliqué dans la documentation.
Dans un fichier lib/prisma.ts
on va instancier notre Prisma
:
// lib/prisma.ts
import { PrismaClient } from "@prisma/client";
const globalForPrisma = global as unknown as { prisma: PrismaClient };
export const prisma =
globalForPrisma.prisma || new PrismaClient();
if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma;
Ce code permet d'éviter d'instancier plusieurs fois le PrismaClient
dans ton application. Notamment quand tu publies l'application sur Vercel
en "Serverless".
Une fois fait, tu peux utiliser prisma
à n'importe quel endroit backend de ton application, comme un API Routes qui viendrait retourner tous les posts dans app/api/posts/route.ts
:
import { NextResponse } from "next/server";
import { prisma } from "@/lib/prisma";
export async function GET(request: Request) {
const posts = await prisma.post.findMany();
return NextResponse.json(posts);
}
Ce code vient récupérer tous les posts disponibles et vient les retourner en format JSON. Tu peux le voir ici, mais avec Prisma tout est type-safe c'est-à-dire que quand tu écris prisma.
tu as une auto-complétion automatique sur VSCode qui te propose post
.
Usage avancé de Prisma
Tu peux utiliser Prisma pour faire à peu près tout ce qui est possible de faire avec SQL
sauf si tu vas dans des cas trop compliqués. Mais voici des exemples typiques.
Récupérer tous les posts qui commencent par "Pourquoi"
const posts = await prisma.post.findMany({
where: {
title: {
startsWith: "Pourquoi"
}
}
})
where
permet de filtrer les données- il existe ensuite plein de filtres built-in
Récupérer l'user avec l'id 1 et tous ses posts
const user = await prisma.user.findUnique({
where: {
id: 1
},
include: {
posts: true
}
})
const posts = user.posts;
include
vient inclure des relations à la valeur de retour
Récupérer l'user le nom et le titre de tous les posts de l'utilisateur avec l'id 1
const posts = await prisma.post.findMany({
where: {
authorId: 1
},
select: {
title: true,
author: {
select: { name: true }
}
}
})
select
permet de sélectionner et récupérer uniquement les champs dont tu as besoin. Tu peux aussi sélectionner des données dans les relations.
Récupérer le nombre de posts de l'utilisateur avec l'id 1
const posts = await prisma.post.count({
where: {
authorId: 1
}
})
count
permet de récupérer le nombre de données
Récupérer les 10 derniers posts
const posts = await prisma.post.findMany({
take: 10,
orderBy: {
createdAt: "desc"
}
})
take
permet de récupérer un nombre de donnéesorderBy
permet de trier les données
Point sur les usages avancés
Il existe évidemment plein d'autres usages et de choses à faire. Je t'invite à utiliser ChatGPT si tu as des questions, il répond vraiment bien. Tu peux aussi lire la documentation.
Prisma avec TypeScript
Un truc que j'aime vraiment faire avec Prisma, c'est de générer des types TypeScript en fonction des query que je fais. Souvent dans mes applications je crée des méthodes pour séparer mes query de mes API Routes par exemple. Par exemple, je vais récupérer le user et ses posts dans une méthode :
export const getUserWithPosts = async (userId: number) => {
const user = await prisma.user.findUnique({
where: { id: userId },
select: {
id: true,
name: true,
posts: {
select: {
id: true,
title: true
}
}
}
});
return user;
}
Et ensuite souvent j'ai envie d'avoir un type qui correspond à cet objet. Pour ça, Prisma a prévu le coup et tu peux faire ceci.
import { Prisma } from "@prisma/client";
type UserWithPosts = Prisma.PromiseReturnType<typeof getUserWithPosts>
// UserWithPosts = {
// id: number;
// name: string;
// posts: { id: number; title: string }[];
// }
Et là, tu as un type qui correspond à l'objet que tu retournes dans ta fonction.
Tu peux donc créer un Server Component
qui va prendre en props ce fameux user avec le bon type :
export const UserWithPostsCard = ({ user }: { user: UserWithPosts }) => {
return (
<div>
<h1>{user.name}</h1>
{user.posts.map((post) => (
<div key={post.id}>{post.title}</div>
))}
</div>
)
}
Et là, tu as une auto-complétion sur VSCode qui te propose les champs de l'objet.
L'avantage de dingue ici c'est que si tu viens modifier les données que tu récupères dans la méthode getUserWithPosts
tu vas avoir TypeScript qui va automatiquement modifier le type et t'afficher ou non des erreurs en fonction. J'utilise ça tout le temps et c'est vraiment très puissant.
Conclusion
Dans ce guide je t'ai présenté les points les plus importants de Prisma ! J'ai une formation "NextReact" qui contient un module entier sur Prisma
et tu peux tester ma formation gratuitement ici :
Le meilleur moyen d'apprendre NextJS !
Rejoins par développeurs, cette formation reçoit une note de 4.7 / 5 🚀
Reçois la formation gratuitement dans ta boîte mail :