📍 Article principal du cluster : Directus 2026 : guide complet.
Backend Directus prêt, frontend à connecter. Ce tutoriel détaille l’intégration dans Next.js 15 (App Router) et Astro 4, avec SDK TypeScript officiel, types auto-générés, SSG/ISR pour performance maximale.
Prérequis
- Directus en production avec collections + données.
- Next.js 15 ou Astro 4.
- API key Directus créée pour le frontend.
- Niveau attendu : intermédiaire.
- Temps estimé : 1-2 heures.
Setup Next.js 15
Installation
npm install @directus/sdk
# Pour types auto : npx directus-sdk-typegen
Client Directus
// lib/directus.ts
import { createDirectus, rest, staticToken } from '@directus/sdk';
import type { Schema } from '@/types/directus';
export const directus = createDirectus<Schema>(process.env.NEXT_PUBLIC_DIRECTUS_URL!)
.with(rest())
.with(staticToken(process.env.DIRECTUS_TOKEN!));
Server Component liste produits
// app/produits/page.tsx
import { directus } from '@/lib/directus';
import { readItems } from '@directus/sdk';
export const revalidate = 60; // ISR 60s
export default async function ProductsPage() {
const products = await directus.request(readItems('products', {
fields: ['*', 'category.name', 'images.*', 'translations.*'],
filter: { status: { _eq: 'published' } },
sort: ['-date_created'],
limit: 24,
}));
return (
<div className="grid grid-cols-3 gap-6">
{products.map(p => (
<article key={p.id}>
<img src={`${process.env.NEXT_PUBLIC_DIRECTUS_URL}/assets/${p.images[0]?.id}?width=400`} />
<h3>{p.name}</h3>
<p>{p.price.toLocaleString()} {p.currency}</p>
</article>
))}
</div>
);
}
Page produit dynamique
// app/produits/[slug]/page.tsx
export async function generateStaticParams() {
const products = await directus.request(readItems('products', {
fields: ['slug'],
filter: { status: { _eq: 'published' } },
}));
return products.map(p => ({ slug: p.slug }));
}
export default async function ProductPage({ params }: { params: { slug: string } }) {
const = await directus.request(readItems('products', {
fields: ['*', 'category.*', 'images.*', 'variants.*', 'reviews.*'],
filter: { slug: { _eq: params.slug } },
limit: 1,
}));
if (!product) notFound();
return <ProductDetail product={product} />;
}
Webhook ISR Revalidate
Configurer dans Directus Settings → Webhooks → Add :
- URL :
https://votre-site.com/api/revalidate?secret=... - Triggers : items.update, items.create.
- Collections : products.
// app/api/revalidate/route.ts
import { revalidatePath } from 'next/cache';
export async function POST(req: Request) {
const { searchParams } = new URL(req.url);
if (searchParams.get('secret') !== process.env.REVALIDATE_SECRET) {
return new Response('Unauthorized', { status: 401 });
}
revalidatePath('/produits');
return Response.json({ revalidated: true });
}
Setup Astro 4
Installation
npm install @directus/sdk
Client Directus pour Astro
// src/lib/directus.ts
import { createDirectus, rest, staticToken } from '@directus/sdk';
export const directus = createDirectus(import.meta.env.DIRECTUS_URL)
.with(rest())
.with(staticToken(import.meta.env.DIRECTUS_TOKEN));
Page liste articles
---
// src/pages/blog/index.astro
import { directus } from '@/lib/directus';
import { readItems } from '@directus/sdk';
const articles = await directus.request(readItems('articles', {
fields: ['*', 'author.name', 'cover_image.*'],
filter: { status: { _eq: 'published' } },
sort: ['-date_created'],
}));
---
<Layout>
{articles.map(a => (
<article>
<a href={`/blog/${a.slug}`}>{a.title}</a>
<p>par {a.author.name}</p>
</article>
))}
</Layout>
Page article dynamique
---
// src/pages/blog/[slug].astro
import { directus } from '@/lib/directus';
import { readItems } from '@directus/sdk';
export async function getStaticPaths() {
const articles = await directus.request(readItems('articles', { fields: ['slug'] }));
return articles.map(a => ({ params: { slug: a.slug } }));
}
const { slug } = Astro.params;
const [article] = await directus.request(readItems('articles', {
filter: { slug: { _eq: slug } },
fields: ['*', 'author.*', 'cover_image.*'],
limit: 1,
}));
---
<article set:html={article.content} />
Webhook rebuild Astro
Astro étant statique, redéploiement nécessaire à chaque update. Webhook Directus → Vercel/Netlify Build Hook.
Performance et caching
CDN Cloudflare devant
Mettre Cloudflare en façade frontend + Directus. Cache assets Directus (images) avec Cache-Control 1 an. API responses cache via SWR Next.js ou Astro static.
Image transformations
// Auto resize/compress côté Directus
<img src="https://cms.../assets/IMG_ID?width=400&height=300&fit=cover&format=webp" />
Erreurs fréquentes
| Erreur | Cause | Solution |
|---|---|---|
| API 401 | Token non valide | Régénérer token |
| Relations vides | fields= manque populate | fields: ['*', 'relation.*'] |
| Images CORS | CORS Directus pas configuré | CORS_ENABLED=true + CORS_ORIGIN |
| ISR ne marche pas | revalidate manquant | export const revalidate = 60 |
| Build Astro lent | Trop de pages générées | Limiter ou pagination |
| Types TypeScript erreurs | Pas de Schema généré | npx directus-sdk-typegen |
Adaptation au contexte ouest-africain
Trois précisions. CDN Cloudflare gratuit : essentiel pour servir images Directus avec faible latence depuis Dakar/Abidjan. WebP + AVIF : Directus génère auto, gain 50% taille images, crucial mobile 4G. SSG vs SSR : Astro SSG pour blog + Next.js ISR pour e-commerce dynamique.
Tutoriels frères
FAQ
GraphQL ou REST ? REST plus simple. GraphQL pour relations complexes uniquement.
SDK obligatoire ? Non, fetch standard fonctionne aussi. SDK fournit types + helpers.
Real-time updates frontend ? WebSocket Directus + Next.js Suspense pour live data.
SEO sur Astro ? SSG = HTML statique, parfait SEO. Schema.org markup recommandé.
Coût Vercel + Directus ? Vercel gratuit jusqu’à 100 Go/mois bandwidth. Directus 4,51 €. Total < 5 €/mois.
Pour aller plus loin
- 🔝 Retour au pilier : Guide complet Directus 2026
- SDK : docs.directus.io/guides/sdk