Installation & Setup
Créer un projet Next.js
npmcreate-next-app

La commande officielle create-next-app configure TypeScript, Tailwind, ESLint et l'App Router automatiquement.

Bash
# Créer un projet (assistant interactif)
npx create-next-app@latest mon-app
cd mon-app

# Scripts npm
npm run dev      # serveur de développement (http://localhost:3000)
npm run build    # build de production
npm run start    # démarrer le build de production
npm run lint     # vérification ESLint
Structure du projet
Organisation des dossiers (App Router)
app/conventions

Avec l'App Router, toutes les pages et layouts vivent dans le dossier app/. Le nom du fichier détermine son rôle.

Structure
mon-app/
├── app/
│   ├── layout.tsx        # Layout racine (obligatoire)
│   ├── page.tsx          # Page d'accueil  →  /
│   ├── globals.css
│   ├── about/
│   │   └── page.tsx      # Page about      →  /about
│   ├── blog/
│   │   ├── page.tsx      # Liste blog       →  /blog
│   │   └── [slug]/
│   │       └── page.tsx  # Article          →  /blog/:slug
│   └── api/
│       └── hello/
│           └── route.ts  # Route API        →  /api/hello
├── public/               # Fichiers statiques (images, fonts…)
├── components/           # Composants réutilisables
├── lib/                  # Fonctions utilitaires, configs
└── next.config.js        # Configuration Next.js

Fichiers spéciaux reconnus par Next.js :

Conventions
page.tsx        # UI d'une route, la rend accessible
layout.tsx      # UI partagée autour des enfants (persist entre navigations)
loading.tsx     # UI de chargement (Suspense automatique)
error.tsx       # UI d'erreur (Error Boundary automatique)
not-found.tsx   # UI 404
template.tsx    # Comme layout mais re-monté à chaque navigation
route.ts        # Route API (GET, POST, PUT, DELETE…)
Routing (App Router)
Routes statiques, dynamiques et groupées
file-systemdynamic

Le routing est basé sur le système de fichiers. Des conventions de nommage permettent de créer tous les types de routes.

Structure
app/
├── page.tsx              →  /
├── about/page.tsx        →  /about
├── blog/[slug]/page.tsx  →  /blog/:slug      (segment dynamique)
├── shop/[...slug]/page.tsx → /shop/a/b/c    (catch-all)
├── (marketing)/          →  groupe (n'affecte pas l'URL)
│   ├── about/page.tsx    →  /about
│   └── pricing/page.tsx  →  /pricing
└── _components/          →  dossier privé (ignoré par le router)
Récupérer les params d'une route dynamique
paramssearchParams

Les pages reçoivent params (segments dynamiques) et searchParams (query string) en props.

TSX
// app/blog/[slug]/page.tsx
type Props = {
  params: { slug: string };
  searchParams: { [key: string]: string | string[] | undefined };
};

export default function BlogPost({ params, searchParams }: Props) {
  const { slug } = params;           // ex: "mon-article"
  const page = searchParams.page;   // ex: "2" si ?page=2

  return <h1>Article : {slug}</h1>;
}

// Générer des routes statiques au build (SSG)
export async function generateStaticParams() {
  const articles = await getArticles();
  return articles.map(a => ({ slug: a.slug }));
}
Route Handler (API)
route.tsGETPOST

Les fichiers route.ts remplacent les anciennes pages/api/. Chaque méthode HTTP est exportée séparément.

TSX
// app/api/users/route.ts
import { NextRequest, NextResponse } from "next/server";

export async function GET(request: NextRequest) {
  const users = await fetchUsers();
  return NextResponse.json(users);
}

export async function POST(request: NextRequest) {
  const body = await request.json();
  const newUser = await createUser(body);
  return NextResponse.json(newUser, { status: 201 });
}

// app/api/users/[id]/route.ts
export async function DELETE(
  request: NextRequest,
  { params }: { params: { id: string } }
) {
  await deleteUser(params.id);
  return new NextResponse(null, { status: 204 });
}
Server vs Client Components
Server Components (par défaut)
RSCasync/await

Tous les composants sont des Server Components par défaut. Ils s'exécutent uniquement côté serveur : pas de JavaScript envoyé au client, accès direct à la BDD.

TSX
// Server Component — pas besoin de "use server"
// Peut être async, accès direct BDD, env vars privées
async function UserList() {
  // Fetch direct côté serveur (pas d'API nécessaire)
  const users = await prisma.user.findMany();

  return (
    <ul>
      {users.map(u => <li key={u.id}>{u.name}</li>)}
    </ul>
  );
}

// Limites des Server Components :
// ✗ Pas de useState, useEffect, useContext
// ✗ Pas d'event handlers (onClick, onChange…)
// ✗ Pas d'accès aux APIs navigateur (window, localStorage…)
Client Components
"use client"hooks

Ajouter "use client" en tête de fichier pour activer les hooks React et les interactions navigateur. Utiliser uniquement quand nécessaire.

TSX
"use client";

import { useState } from "react";

// Client Component — hooks et events disponibles
export function Counter() {
  const [count, setCount] = useState(0);

  return (
    <button onClick={() => setCount(c => c + 1)}>
      Clics : {count}
    </button>
  );
}

// Règle d'or : pousser "use client" aussi bas que possible
// dans l'arbre pour maximiser le rendu serveur
//
// ✓ Utiliser "use client" pour : états, events, localStorage,
//   animations, composants tiers qui utilisent des hooks
Layouts & Templates
Layout racine et layouts imbriqués
layout.tsxchildren

Le layout racine (app/layout.tsx) est obligatoire. Les layouts se nichent et persistent entre les navigations (pas de re-montage).

TSX
// app/layout.tsx — Layout racine (obligatoire, doit avoir <html> et <body>)
export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="fr">
      <body>
        <Header />
        <main>{children}</main>
        <Footer />
      </body>
    </html>
  );
}

// app/dashboard/layout.tsx — Layout imbriqué pour /dashboard/*
export default function DashboardLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <div className="flex">
      <Sidebar />
      <section>{children}</section>
    </div>
  );
}
Loading & Error UI
loading.tsxerror.tsx

Next.js encapsule automatiquement dans Suspense et ErrorBoundary si ces fichiers existent dans le dossier de la route.

TSX
// app/blog/loading.tsx
export default function Loading() {
  return <div className="spinner">Chargement…</div>;
}

// app/blog/error.tsx — doit être un Client Component
"use client";

export default function Error({
  error,
  reset,
}: {
  error: Error & { digest?: string };
  reset: () => void;
}) {
  return (
    <div>
      <h2>Une erreur est survenue !</h2>
      <p>{error.message}</p>
      <button onClick={reset}>Réessayer</button>
    </div>
  );
}

// app/not-found.tsx
export default function NotFound() {
  return <h2>Page introuvable (404)</h2>;
}
Data Fetching
fetch & cache dans les Server Components
fetchcacherevalidate

Next.js étend l'API fetch native avec des options de cache. Par défaut les données sont mises en cache indéfiniment (SSG). On peut contrôler la revalidation.

TSX
// SSG — mis en cache indéfiniment (par défaut)
const data = await fetch("https://api.example.com/posts");

// ISR — revalider toutes les 60 secondes
const data = await fetch("https://api.example.com/posts", {
  next: { revalidate: 60 },
});

// SSR — toujours refetcher (pas de cache)
const data = await fetch("https://api.example.com/posts", {
  cache: "no-store",
});

// Revalidation par tag (on-demand)
const data = await fetch("https://api.example.com/posts", {
  next: { tags: ["posts"] },
});
// Puis dans une Server Action :
import { revalidateTag } from "next/cache";
revalidateTag("posts"); // invalide tout ce qui a le tag "posts"
generateStaticParams & generateMetadata
SSGdynamic

Fonctions exportées depuis une page pour pré-générer des routes au moment du build.

TSX
// app/blog/[slug]/page.tsx

// Pré-génère toutes les pages /blog/:slug au build
export async function generateStaticParams() {
  const articles = await getArticles();
  return articles.map(a => ({ slug: a.slug }));
}

// Comportement pour les slugs non générés au build
export const dynamicParams = true;  // génère à la demande (défaut)
// export const dynamicParams = false; // retourne 404

// Forcer le rendu dynamique pour toute la page
export const dynamic = "force-dynamic";
// ou forcer le cache statique
export const dynamic = "force-static";
Server Actions
Définir et appeler une Server Action
"use server"form

Les Server Actions sont des fonctions async qui s'exécutent côté serveur et peuvent être appelées depuis des formulaires ou du code client. Elles remplacent les requêtes API classiques pour les mutations.

TSX
// lib/actions.ts — fichier dédié aux actions
"use server";

import { revalidatePath } from "next/cache";
import { redirect } from "next/navigation";

export async function createArticle(formData: FormData) {
  const title = formData.get("title") as string;
  const content = formData.get("content") as string;

  // Valider, insérer en BDD…
  await db.article.create({ data: { title, content } });

  revalidatePath("/blog");   // invalide le cache de /blog
  redirect("/blog");          // redirige après succès
}

export async function deleteArticle(id: string) {
  await db.article.delete({ where: { id } });
  revalidatePath("/blog");
}
TSX
// Utilisation dans un Server Component (form natif)
import { createArticle } from "@/lib/actions";

export default function NewArticlePage() {
  return (
    <form action={createArticle}>
      <input name="title" placeholder="Titre" />
      <textarea name="content" />
      <button type="submit">Créer</button>
    </form>
  );
}

// Utilisation dans un Client Component
"use client";
import { deleteArticle } from "@/lib/actions";

function DeleteButton({ id }: { id: string }) {
  return (
    <button onClick={() => deleteArticle(id)}>
      Supprimer
    </button>
  );
}
Metadata & SEO
Metadata statique et dynamique
MetadatagenerateMetadata

Next.js gère le SEO via l'export d'un objet metadata (statique) ou de la fonction generateMetadata (dynamique) depuis n'importe quelle page ou layout.

TSX
import type { Metadata } from "next";

// Metadata statique
export const metadata: Metadata = {
  title: "Mon Site",
  description: "Description de la page",
  keywords: ["next.js", "react"],
  openGraph: {
    title: "Mon Site",
    description: "Description OG",
    images: ["/og-image.png"],
  },
};

// Metadata dynamique (ex: page d'article)
export async function generateMetadata(
  { params }: { params: { slug: string } }
): Promise<Metadata> {
  const article = await getArticle(params.slug);

  return {
    title: article.title,
    description: article.excerpt,
    openGraph: {
      title: article.title,
      images: [article.coverImage],
    },
  };
}

// Template de titre (dans layout.tsx)
export const metadata: Metadata = {
  title: {
    template: "%s | Mon Site",  // "Article X | Mon Site"
    default: "Mon Site",         // si aucune page ne définit title
  },
};
Image & Font
Composant Image optimisé
next/imagelazy loading

Le composant Image de Next.js optimise automatiquement les images : lazy loading, formats WebP/AVIF, redimensionnement à la demande.

TSX
import Image from "next/image";

// Image locale (width/height obligatoires ou fill)
<Image
  src="/photos/chat.jpg"
  alt="Un chat"
  width={500}
  height={300}
  priority               // charger en priorité (LCP)
/>

// Image distante (déclarer le domaine dans next.config.js)
<Image
  src="https://example.com/photo.jpg"
  alt="Photo distante"
  width={800}
  height={600}
/>

// Image en mode fill (remplit son conteneur)
<div style={{ position: "relative", width: "100%", height: "400px" }}>
  <Image src="/hero.jpg" alt="Hero" fill style={{ objectFit: "cover" }} />
</div>
JS
// next.config.js — autoriser les images distantes
/** @type {import('next').NextConfig} */
const nextConfig = {
  images: {
    remotePatterns: [
      {
        protocol: "https",
        hostname: "example.com",
      },
    ],
  },
};
module.exports = nextConfig;
Fonts optimisées (next/font)
next/fontGoogle Fonts

next/font charge les polices sans requête externe (auto-hébergement), élimine le layout shift et améliore les performances.

TSX
// app/layout.tsx
import { Inter, Roboto_Mono } from "next/font/google";

const inter = Inter({
  subsets: ["latin"],
  variable: "--font-inter",
});

const robotoMono = Roboto_Mono({
  subsets: ["latin"],
  variable: "--font-roboto-mono",
});

export default function RootLayout({ children }) {
  return (
    <html lang="fr" className={`${inter.variable} ${robotoMono.variable}`}>
      <body className={inter.className}>{children}</body>
    </html>
  );
}
Variables d'environnement
Fichiers .env et exposition client
.envNEXT_PUBLIC_

Les variables sans préfixe restent côté serveur uniquement. Ajouter le préfixe NEXT_PUBLIC_ pour les exposer côté client (incluses dans le bundle JS).

Bash
# .env.local (jamais commité — secrets)
DATABASE_URL=postgresql://user:pass@localhost/mydb
API_SECRET_KEY=super-secret

# Variable accessible côté client (bundle JS)
NEXT_PUBLIC_API_URL=https://api.example.com
NEXT_PUBLIC_GA_ID=G-XXXXXXXXXX

# Fichiers de priorité (du plus prioritaire au moins prioritaire) :
# .env.local > .env.development / .env.production > .env
TSX
// Côté serveur (Server Component, route handler, Server Action)
const dbUrl = process.env.DATABASE_URL;         // ✓
const secret = process.env.API_SECRET_KEY;       // ✓

// Côté client (Client Component)
const apiUrl = process.env.NEXT_PUBLIC_API_URL;  // ✓
const secret = process.env.API_SECRET_KEY;        // ✗ undefined !
Déploiement
Déployer sur Vercel
VercelCI/CD

Vercel est la plateforme créée par les auteurs de Next.js. Le déploiement est automatique à chaque push sur GitHub.

Bash
# Installer Vercel CLI
npm install -g vercel

# Déploiement depuis le terminal
vercel          # déploiement de preview
vercel --prod   # déploiement de production

# Via GitHub : connecter le repo sur vercel.com
# → chaque push sur main déclenche un déploiement automatique
# → chaque PR crée un environnement de preview unique
Build autonome (Docker / VPS)
buildstandalone

Pour déployer sans Vercel, activer le mode standalone pour obtenir un build minimaliste sans node_modules.

JS
// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  output: "standalone",
};
module.exports = nextConfig;
Bash
# Build de production
npm run build

# Lancer le serveur standalone
node .next/standalone/server.js

# Variables d'environnement en production
PORT=3000 HOSTNAME=0.0.0.0 node .next/standalone/server.js
ORM Prisma
Installation & initialisation
installinit

Prisma est un ORM TypeScript moderne. Il se compose de trois outils : Prisma CLI (migrations & génération), Prisma Client (requêtes type-safe) et Prisma Studio (GUI BDD).

BASH
# 1. Installer les dépendances
npm install prisma --save-dev
npm install @prisma/client

# 2. Initialiser Prisma (crée prisma/schema.prisma + .env)
npx prisma init

# Avec un provider spécifique
npx prisma init --datasource-provider postgresql
npx prisma init --datasource-provider mysql
npx prisma init --datasource-provider sqlite
Schema Prisma (prisma/schema.prisma)
schemamodelsrelations

Le fichier schema.prisma est la source de vérité : il définit la connexion BDD, le générateur client et tous les modèles de données.

PRISMA
// prisma/schema.prisma

generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"   // "mysql" | "sqlite" | "mongodb"
  url      = env("DATABASE_URL")
}

// --- Modèles ---

model User {
  id        Int      @id @default(autoincrement())
  email     String   @unique
  name      String?
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  posts     Post[]   // relation one-to-many
  profile   Profile? // relation one-to-one
}

model Profile {
  id     Int    @id @default(autoincrement())
  bio    String
  user   User   @relation(fields: [userId], references: [id])
  userId Int    @unique
}

model Post {
  id        Int        @id @default(autoincrement())
  title     String
  content   String?
  published Boolean    @default(false)
  author    User       @relation(fields: [authorId], references: [id])
  authorId  Int
  tags      Tag[]      @relation("PostToTag") // many-to-many
  createdAt DateTime   @default(now())
}

model Tag {
  id    Int    @id @default(autoincrement())
  name  String @unique
  posts Post[] @relation("PostToTag")
}
Commandes de migration
migratedbstudio

Prisma gère les migrations SQL automatiquement à partir du schema. Chaque migration est un fichier SQL versionné dans prisma/migrations/.

BASH
# Créer et appliquer une migration (dev uniquement)
npx prisma migrate dev --name init
npx prisma migrate dev --name add_profile_table

# Appliquer les migrations en production (sans créer de nouvelle migration)
npx prisma migrate deploy

# Réinitialiser la BDD (efface TOUT et rejoue toutes les migrations) - dev uniquement
npx prisma migrate reset

# Vérifier l'état des migrations
npx prisma migrate status

# Synchroniser le schema sans migration (prototype rapide, écrase les données)
npx prisma db push

# Introspection : générer le schema depuis une BDD existante
npx prisma db pull

# Regénérer le Prisma Client après une modif du schema
npx prisma generate

# Ouvrir Prisma Studio (GUI pour explorer/éditer la BDD)
npx prisma studio
Prisma Client — singleton Next.js
clientsingletonbest practice

En développement, le Hot Module Replacement de Next.js crée plusieurs instances de PrismaClient. Le pattern singleton évite d'épuiser les connexions à la BDD.

TSX
// lib/prisma.ts
import { PrismaClient } from "@prisma/client";

const globalForPrisma = globalThis as unknown as {
  prisma: PrismaClient | undefined;
};

export const prisma =
  globalForPrisma.prisma ?? new PrismaClient({ log: ["query"] });

if (process.env.NODE_ENV !== "production") {
  globalForPrisma.prisma = prisma;
}

// Utilisation dans n'importe quel Server Component ou Server Action :
import { prisma } from "@/lib/prisma";

Ajouter DATABASE_URL dans .env :

ENV
# PostgreSQL
DATABASE_URL="postgresql://user:password@localhost:5432/mydb"

# MySQL
DATABASE_URL="mysql://user:password@localhost:3306/mydb"

# SQLite (développement local simple)
DATABASE_URL="file:./dev.db"
CRUD — opérations de base
createreadupdatedelete

Toutes les méthodes Prisma retournent des Promises et sont entièrement typées en fonction du schema.

TSX
import { prisma } from "@/lib/prisma";

// --- CREATE ---
const user = await prisma.user.create({
  data: { email: "alice@example.com", name: "Alice" },
});

// Créer avec des relations imbriquées
const userWithPost = await prisma.user.create({
  data: {
    email: "bob@example.com",
    posts: {
      create: { title: "Mon premier article" },
    },
  },
});

// Créer plusieurs enregistrements
await prisma.user.createMany({
  data: [
    { email: "a@ex.com", name: "A" },
    { email: "b@ex.com", name: "B" },
  ],
  skipDuplicates: true,
});

// --- READ ---
// Récupérer un enregistrement par son id
const post = await prisma.post.findUnique({ where: { id: 1 } });

// Récupérer le premier résultat correspondant
const user = await prisma.user.findFirst({
  where: { email: { contains: "@example.com" } },
});

// Récupérer tous les enregistrements avec filtres
const posts = await prisma.post.findMany({
  where: { published: true },
  orderBy: { createdAt: "desc" },
  take: 10,   // LIMIT
  skip: 0,    // OFFSET
  select: { id: true, title: true, author: { select: { name: true } } },
});

// Inclure des relations (JOIN)
const users = await prisma.user.findMany({
  include: { posts: true, profile: true },
});

// Compter
const count = await prisma.post.count({ where: { published: true } });

// --- UPDATE ---
const updated = await prisma.user.update({
  where: { id: 1 },
  data: { name: "Alice B." },
});

// Upsert : créer ou mettre à jour
const upserted = await prisma.user.upsert({
  where: { email: "alice@example.com" },
  update: { name: "Alice Updated" },
  create: { email: "alice@example.com", name: "Alice" },
});

// --- DELETE ---
await prisma.post.delete({ where: { id: 1 } });

await prisma.post.deleteMany({ where: { published: false } });
Filtres & requêtes avancées
wherefilteraggregate

Prisma propose des opérateurs riches pour filtrer, trier, agréger et paginer les données.

TSX
// Opérateurs de comparaison
const posts = await prisma.post.findMany({
  where: {
    AND: [
      { published: true },
      { createdAt: { gte: new Date("2024-01-01") } },
    ],
    OR: [
      { title: { contains: "Next.js" } },
      { title: { startsWith: "Prisma" } },
    ],
    NOT: { authorId: 5 },
  },
});

// Filtres sur les relations (WHERE EXISTS / NOT EXISTS)
const usersWithPosts = await prisma.user.findMany({
  where: { posts: { some: { published: true } } },
});

const usersWithoutPosts = await prisma.user.findMany({
  where: { posts: { none: {} } },
});

// Agrégations
const stats = await prisma.post.aggregate({
  _count: { id: true },
  _avg:   { id: true },
  _max:   { createdAt: true },
  where:  { published: true },
});

// groupBy
const grouped = await prisma.post.groupBy({
  by: ["authorId"],
  _count: { id: true },
  orderBy: { _count: { id: "desc" } },
});
Transactions
transactionatomique

Les transactions garantissent que plusieurs opérations réussissent ou échouent ensemble. Prisma propose deux API : séquentielle (tableau) et interactive (callback).

TSX
// Transaction séquentielle (tableau de promesses)
const [newUser, newPost] = await prisma.$transaction([
  prisma.user.create({ data: { email: "carol@example.com" } }),
  prisma.post.create({ data: { title: "Hello", authorId: 1 } }),
]);

// Transaction interactive (plus flexible, supporte la logique conditionnelle)
const result = await prisma.$transaction(async (tx) => {
  const user = await tx.user.findUnique({ where: { id: 1 } });
  if (!user) throw new Error("Utilisateur introuvable");

  const post = await tx.post.create({
    data: { title: "Article transactionnel", authorId: user.id },
  });

  return { user, post };
});
Prisma dans les Server Actions
Server Actionsformsrevalidate

Les Server Actions de Next.js s'exécutent côté serveur et peuvent appeler Prisma directement — pas d'API intermédiaire nécessaire.

TSX
// app/posts/actions.ts
"use server";

import { prisma } from "@/lib/prisma";
import { revalidatePath } from "next/cache";
import { redirect } from "next/navigation";

export async function createPost(formData: FormData) {
  const title   = formData.get("title") as string;
  const content = formData.get("content") as string;

  await prisma.post.create({
    data: { title, content, authorId: 1 },
  });

  revalidatePath("/posts"); // invalide le cache de la liste
  redirect("/posts");
}

export async function deletePost(id: number) {
  await prisma.post.delete({ where: { id } });
  revalidatePath("/posts");
}

// app/posts/new/page.tsx
import { createPost } from "../actions";

export default function NewPostPage() {
  return (
    <form action={createPost}>
      <input name="title"   placeholder="Titre"   required />
      <textarea name="content" placeholder="Contenu" />
      <button type="submit">Publier</button>
    </form>
  );
}
Prisma dans les Server Components & Route Handlers
Server ComponentAPI Route

Prisma peut être appelé directement dans les Server Components (pour le rendu) et dans les Route Handlers (pour les endpoints REST/JSON).

TSX
// app/posts/page.tsx — Server Component
import { prisma } from "@/lib/prisma";

export default async function PostsPage() {
  const posts = await prisma.post.findMany({
    where:   { published: true },
    include: { author: { select: { name: true } } },
    orderBy: { createdAt: "desc" },
  });

  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>
          <h2>{post.title}</h2>
          <p>Par {post.author.name}</p>
        </li>
      ))}
    </ul>
  );
}

// app/api/posts/route.ts — Route Handler (REST API)
import { NextResponse } from "next/server";
import { prisma } from "@/lib/prisma";

export async function GET() {
  const posts = await prisma.post.findMany({ where: { published: true } });
  return NextResponse.json(posts);
}

export async function POST(req: Request) {
  const body  = await req.json();
  const post  = await prisma.post.create({ data: body });
  return NextResponse.json(post, { status: 201 });
}
Seeding — peupler la base de données
seeddev

Un script de seed permet d'insérer des données initiales ou de test dans la BDD.

TSX
// prisma/seed.ts
import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();

async function main() {
  const alice = await prisma.user.upsert({
    where:  { email: "alice@example.com" },
    update: {},
    create: {
      email: "alice@example.com",
      name:  "Alice",
      posts: {
        create: [
          { title: "Hello Next.js", published: true },
          { title: "Prisma is great", published: false },
        ],
      },
    },
  });
  console.log("Seed OK :", alice);
}

main()
  .catch(console.error)
  .finally(() => prisma.$disconnect());

Configurer le script dans package.json :

JSON
{
  "prisma": {
    "seed": "ts-node --compiler-options {\"module\":\"CommonJS\"} prisma/seed.ts"
  }
}
BASH
# Lancer le seed
npx prisma db seed

# Le seed est aussi lancé automatiquement après :
npx prisma migrate reset

Aucun résultat pour votre recherche.