Automatiser CI/CD pour Strapi 5 + Next.js : Reconstruire à chaque publication avec GitHub Actions
Apprenez pas à pas à configurer les webhooks Strapi 5, un endpoint ISR on‑demand dans Next.js et un workflow GitHub Actions afin que chaque publication déclenche un nouveau build et déploiement.
Par l’équipe Revisionary · · 4 min de lecture
Lorsqu’un·e rédacteur·rice de contenu publie une entrée dans Strapi 5, le site doit afficher la modification immédiatement, sans redeploiement manuel. Vous pouvez y parvenir en connectant les webhooks de Strapi à une pipeline CI/CD (GitHub Actions) qui déclenche une construction et un déploiement de Next.js. Ce guide présente la configuration complète : configuration du webhook Strapi, une API sécurisée de revalidation on‑demand dans Next.js, et un workflow GitHub Actions qui s’exécute à la réception des webhooks.
Vue d’ensemble du workflow
- Le webhook Strapi se déclenche sur l’événement
entry.publish. - Le webhook appelle une route API protégée (
/api/revalidate) dans l’application Next.js. - La route API invoque
revalidatePath(ourevalidateTag) pour purger le cache ISR. - La route déclenche également un workflow GitHub Actions via l’événement
repository_dispatch. - GitHub Actions récupère le dépôt, exécute
npm install && npm run build && npm run start(ou déploie sur Vercel/Netlify), complétant le cycle CI/CD.
L’ensemble du processus s’exécute dans le runtime Node.js, car les runtimes Edge ne peuvent pas effectuer d’ISR on‑demand.
1. Configurer le webhook Strapi
Créez un webhook dans le panneau d’administration de Strapi (Settings → Webhooks) ou ajoutez‑le programmatiquement dans config/server.ts.
// ./config/server.ts
import { defineConfig } from '@strapi/types';
export default defineConfig({
// Paramètres globaux du webhook (optionnel)
webhook: {
// Ajoute un en‑tête Authorization qui sera vérifié par Next.js
headers: {
Authorization: 'Bearer MY_STRAPI_WEBHOOK_SECRET',
},
// Vérifie les signatures du payload (recommandé)
signature: {
secret: process.env.STRAPI_WEBHOOK_SECRET,
},
},
// Enregistre le webhook de publication
webhook: {
enabled: true,
events: ['entry.publish'],
url: `${process.env.NEXT_PUBLIC_SITE_URL}/api/revalidate`,
// Ne se déclenche que pour les types de contenu nécessitant l’ISR
contentTypes: ['api::article.article', 'api::page.page'],
},
});Considérations de sécurité
- Vérifiez l’en‑tête
Authorization. - Validez la signature HMAC si vous activez
signaturedans Strapi (voir l’exemple de vérification de signature de webhook dans la documentation Strapi【3†L112-L136】). - Restreignez l’URL du webhook aux seules requêtes POST.
2. Créer un endpoint de revalidation protégé dans Next.js
Placez le fichier sous app/api/revalidate/route.ts (App Router) et marquez‑le comme route Node.js en ajoutant export const runtime = 'nodejs'; – cela évite la limitation du runtime Edge【8†L16-L17】.
// app/api/revalidate/route.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export const runtime = 'nodejs'; // Garantir le runtime Node.js pour l’ISR
/**
* Vérifier le secret envoyé par Strapi.
*/
function verifySecret(req: NextRequest): boolean {
const auth = req.headers.get('authorization');
return auth === `Bearer ${process.env.NEXT_WEBHOOK_SECRET}`;
}
export async function POST(req: NextRequest) {
if (!verifySecret(req)) {
return new NextResponse('Invalid secret', { status: 401 });
}
const payload = await req.json();
const { model, uid, entry } = payload;
// Déterminer le(s) chemin(s) à revalider.
// Exemple : les slugs d’article sont stockés dans entry.slug
const paths = [] as string[];
if (model === 'api::article.article') {
paths.push(`/articles/${entry.slug}`);
} else if (model === 'api::page.page') {
paths.push(`/${entry.slug}`);
}
try {
// Revalider chaque chemin à la demande.
for (const path of paths) {
await revalidatePath(path);
}
// Déclencher un run GitHub Actions via repository_dispatch.
await triggerGitHubDispatch();
return NextResponse.json({ revalidated: true, paths });
} catch (err) {
console.error('Revalidation error:', err);
return new NextResponse('Revalidation failed', { status: 500 });
}
}
/**
* Call the GitHub repository_dispatch endpoint.
*/
async function triggerGitHubDispatch() {
const token = process.env.GITHUB_TOKEN; // jeton d’accès personnel avec le scope repo
const repo = process.env.GITHUB_REPO; // par ex. "owner/repo"
const response = await fetch(`https://api.github.com/repos/${repo}/dispatches`, {
method: 'POST',
headers: {
Accept: 'application/vnd.github+json',
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
event_type: 'strapi-publish',
client_payload: { source: 'strapi' },
}),
});
if (!response.ok) {
throw new Error('GitHub dispatch failed');
}
}revalidatePathest le helper on‑demand ISR de Next.js【6†L226-L233】.- La route s’exécute uniquement en Node.js, satisfaisant l’exigence de runtime.
- La fonction
triggerGitHubDispatchenvoie un événementrepository_dispatchque GitHub Actions peut écouter.
3. Configurer le workflow GitHub Actions
Créez le fichier .github/workflows/strapi-publish.yml dans votre dépôt.
name: Rebuild on Strapi Publish
on:
repository_dispatch:
types: [strapi-publish]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
permissions:
contents: read
pages: write # if deploying to GitHub Pages
id-token: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
run: npm ci
- name: Build Next.js app
run: npm run build
- name: Deploy to Vercel (or Netlify, etc.)
env:
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
run: |
npm install -g vercel
vercel --prod --token $VERCEL_TOKENFonctionnement
- Lorsque Strapi publie du contenu, le webhook appelle
/api/revalidate. - La route API valide la requête, revalide les chemins ISR, puis envoie un événement
repository_dispatchà GitHub. - GitHub Actions récupère l’événement
strapi-publish, exécute la construction et déploie la nouvelle sortie statique.
4. Variables d’environnement
| Variable | Où il/elle se trouve | Objectif |
|---|---|---|
STRAPI_WEBHOOK_SECRET | .env de Strapi | Secret HMAC pour la signature du webhook |
NEXT_WEBHOOK_SECRET | .env.local de Next.js | Même secret utilisé pour vérifier la requête |
GITHUB_TOKEN | Secret GitHub Actions GITHUB_TOKEN | Jeton d’accès personnel pour repository_dispatch |
GITHUB_REPO | Secret GitHub Actions GITHUB_REPO | Identifiant owner/repo |
VERCEL_TOKEN, VERCEL_ORG_ID, VERCEL_PROJECT_ID | Secrets GitHub Actions | Identifiants de déploiement Vercel |
5. Tester l’intégration localement
- Exécuter Strapi :
npm run develop(requiert Node 18‑24 et une base de données comme indiqué sur la page des prérequis)【/docs/getting-started/requirements】. - Exécuter Next.js en mode Node :
npm run devet définissezNEXT_PUBLIC_SITE_URL=http://localhost:3000. - Utilisez un outil tel que
curlpour POST un payload de webhook factice :bash curl -X POST http://localhost:3000/api/revalidate \ -H "Content-Type: application/json" \ -H "Authorization: Bearer MY_STRAPI_WEBHOOK_SECRET" \ -d '{"model":"api::article.article","uid":"article","entry":{"slug":"hello-world"}}' - Vérifiez que la console affiche
revalidatedet que la requête de dispatch GitHub réussit (vérifiez l’onglet Actions).
6. Option : Revalidation basée sur les tags pour les pages de liste
Si vous avez une page qui liste de nombreux articles (/articles), vous pouvez taguer l’appel fetch et revalider le tag au lieu de chaque chemin individuel.
// app/articles/page.tsx
export const fetchCache = 'force-no-store'; // optionnel pour des données fraîches
export const revalidate = 60; // ISR de secours
export default async function ArticlesPage() {
const res = await fetch(`${process.env.STRAPI_API_URL}/articles`, {
next: { tags: ['articles'] },
});
const data = await res.json();
// rendre la liste …
}Dans le gestionnaire du webhook, remplacez revalidatePath par :
await revalidateTag('articles');7. Déployer l’application Next.js
- Vercel – le service par défaut pour Next.js. La commande CLI
verceldu workflow pousse la dernière construction. - Netlify – utilisez le CLI Netlify (
netlify deploy --prod) à la place des commandes Vercel. - Auto‑hébergé – si vous exécutez Next.js sur un VPS, remplacez l’étape de déploiement par un script SSH qui récupère le dépôt, exécute
npm ci && npm run build && pm2 restart next.
8. Observabilité et surveillance
- Le journal d’audit de Strapi enregistre chaque action
entry.publish, vous offrant une trace immuable de qui a déclenché une reconstruction【12†L12-L13】. - Next.js ajoute automatiquement les en‑têtes de réponse
x‑nextjs‑cache(HIT,STALE,MISS,REVALIDATED) pour vous aider à déboguer le comportement ISR【9†L23-L25】. - Dans GitHub Actions, activez le drapeau
--debugdu CLI Vercel pour capturer les logs de déploiement.
9. Pièges courants
| Symptom | Cause | Solution |
|---|---|---|
401 Invalid secret depuis /api/revalidate | Secret incohérent entre Strapi et Next.js | Assurez‑vous que STRAPI_WEBHOOK_SECRET et NEXT_WEBHOOK_SECRET sont identiques et chargés depuis les fichiers d’environnement. |
| L’ISR ne s’exécute pas sur le runtime Edge | Utilisation du runtime Edge au lieu de Node.js | Ajoutez export const runtime = 'nodejs'; au fichier de route. |
| Le dispatch GitHub échoue avec 404 | owner/repo incorrect ou scopes du token manquants | Vérifiez GITHUB_REPO et accordez le scope repo au PAT. |
| Les temps de build sont longs | node_modules non mis en cache dans le CI | Ajoutez une étape de cache : actions/cache@v4 pour ~/.npm ou node_modules. |
10. Étendre le pipeline
- Versionnage du contenu – Si vous utilisez le plugin Revisionary, vous pouvez également écouter les événements
entry.unpublishetentry.deletepour nettoyer les pages obsolètes. - Builds de prévisualisation – Combinez le webhook avec les déploiements preview de Vercel pour générer une URL de brouillon pour les rédacteurs.
- Feature flags – Transmettez un flag
previewdans le payload et laissez la route Next.js décider de revalider le site en production ou un déploiement de prévisualisation.
En connectant les webhooks de Strapi 5 à un endpoint ISR on‑demand protégé dans Next.js et à un workflow GitHub Actions, vous obtenez une boucle CI/CD entièrement automatisée : chaque publication invalide instantanément le cache statique et déclenche un nouveau build. L’approche respecte les bonnes pratiques de sécurité, fonctionne avec TypeScript, et peut être étendue avec le journal d’audit de Revisionary pour une traçabilité complète.
Lectures complémentaires
- Documentation des webhooks Strapi – https://docs.strapi.io/cms/backend-customization/webhooks
- Regeneration statique incrémentale de Next.js – https://nextjs.org/docs/app/guides/incremental-static-regeneration
repository_dispatchde GitHub Actions – https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#repository_dispatch
Sources
L’équipe Revisionary
Les développeurs de Revisionary, un plugin d’historique des versions pour Strapi 5. Nous écrivons sur Strapi, le développement web, l’IA et la sécurité des applications.
Cet article a été rédigé avec l'aide d'une IA.