Déployer un SaaS Next.js en production sur Vercel : checklist complète
De la configuration des variables d'environnement au monitoring post-deploy — tout ce qu'il faut vérifier avant de mettre votre SaaS en production.
Le déploiement n'est pas un git push
Techniquement, Vercel déploie votre app à chaque push sur main. En pratique, il y a 20 choses à vérifier avant que votre SaaS soit réellement prêt pour la production.
Voici la checklist complète qu'on utilise pour HeartCo.
1. Variables d'environnement
# Base de données
DATABASE_URL="postgresql://..."
DIRECT_URL="postgresql://..." # Pour les migrations Prisma
# Auth
NEXTAUTH_URL="https://votre-app.fr"
NEXTAUTH_SECRET="openssl rand -base64 32"
# Stripe
STRIPE_SECRET_KEY="sk_live_..."
STRIPE_WEBHOOK_SECRET="whsec_..."
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY="pk_live_..."
# Email
RESEND_API_KEY="re_..."
# IA
MISTRAL_API_KEY="..."Règle d'or
Jamais de secrets dans le code ou le .env commité. Utilisez les Environment Variables de Vercel, avec des valeurs différentes pour Preview et Production.
2. Configuration Vercel
// vercel.json
{
"framework": "nextjs",
"buildCommand": "pnpm turbo build --filter=web",
"installCommand": "pnpm install",
"outputDirectory": "apps/web/.next"
}Monorepo : Root Directory
Si votre app est dans apps/web/, configurez le Root Directory dans les settings Vercel, ou utilisez outputDirectory dans vercel.json.
3. Base de données
Migrations
# En local, créer la migration
npx prisma migrate dev --name init
# En production, appliquer
npx prisma migrate deployImportant : migrate dev est pour le développement (crée + applique). migrate deploy est pour la production (applique seulement).
Connection pooling
Supabase fournit deux URLs :
- Transaction mode (
?pgbouncer=true) → pourDATABASE_URL(queries normales) - Session mode → pour
DIRECT_URL(migrations)
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
directUrl = env("DIRECT_URL")
}4. Domaine et SSL
- Ajoutez votre domaine dans Vercel → Settings → Domains
- Configurez les DNS chez votre registrar (CNAME vers
cname.vercel-dns.com) - Vercel provisionne automatiquement le certificat SSL (Let's Encrypt)
- Ajoutez la redirection
www→apex(ou l'inverse)
5. Headers de sécurité
// next.config.ts
const securityHeaders = [
{ key: "X-Frame-Options", value: "DENY" },
{ key: "X-Content-Type-Options", value: "nosniff" },
{ key: "Referrer-Policy", value: "origin-when-cross-origin" },
{ key: "X-XSS-Protection", value: "1; mode=block" },
{
key: "Strict-Transport-Security",
value: "max-age=63072000; includeSubDomains; preload",
},
];6. Crons et tâches planifiées
// vercel.json
{
"crons": [
{
"path": "/api/cron/reset-usage",
"schedule": "0 0 1 * *"
},
{
"path": "/api/cron/trial-expiry",
"schedule": "0 8 * * *"
}
]
}N'oubliez pas de protéger vos endpoints cron avec un header secret :
export async function GET(req: Request) {
const authHeader = req.headers.get("authorization");
if (authHeader !== `Bearer ${process.env.CRON_SECRET}`) {
return new Response("Unauthorized", { status: 401 });
}
// ... logique cron
}7. Monitoring et alertes
Vercel Analytics
// app/layout.tsx
import { Analytics } from "@vercel/analytics/react";
import { SpeedInsights } from "@vercel/speed-insights/next";
export default function RootLayout({ children }) {
return (
<html>
<body>
{children}
<Analytics />
<SpeedInsights />
</body>
</html>
);
}Logs structurés
// Toujours logger le contexte
console.error("[WEBHOOK_STRIPE]", {
eventType: event.type,
organizationId: orgId,
error: error.message,
});Checklist finale avant le go-live
Infrastructure
- Variables d'environnement configurées (Production ≠ Preview)
- Base de données migrée (
prisma migrate deploy) - Domaine configuré + SSL actif
- Crons configurés et protégés
Sécurité
- Headers de sécurité en place
-
NEXTAUTH_SECRETgénéré (pas la valeur par défaut) - Webhook Stripe vérifié par signature
- Pas de secrets dans le code source
Performance
- Images optimisées (next/image)
- Fonts optimisées (next/font)
- Bundle analysé (
@next/bundle-analyzer)
Fonctionnel
- Inscription → connexion → dashboard fonctionne
- Paiement Stripe fonctionne (mode live)
- Emails transactionnels arrivent
- Dark mode fonctionnel
Monitoring
- Vercel Analytics activé
- Error tracking configuré (Sentry recommandé)
- Uptime monitoring (Vercel / Better Uptime)
Un déploiement réussi, ce n'est pas quand l'app tourne — c'est quand elle tourne, paie, envoie des emails, et vous prévient quand quelque chose casse.