Comment j'organise mon portfolio : Velite, MDX et structure hybride
- architecture
- mdx
- velite
- adr
Dans l'article sur Next.js 15, j'ai posé le framework. La question suivante était plus terre-à-terre : où mettre quoi — routes, composants, contenu MDX, assets — sans sur-architecturer un portfolio solo.
Voici les choix retenus pour l'organisation du code.
Le contexte
Avec Next.js 15, Tailwind, shadcn/ui et MDX, il me fallait :
- un blog en français extensible (traductions un jour, pas maintenant) ;
- une structure lisible dans 6 mois quand j'aurai oublié où j'ai rangé les choses ;
- un pipeline de contenu typé et validé au build, pas du parsing fragile au runtime.
Structure hybride par domaine
J'ai évité deux extrêmes :
- une structure plate (tout au même niveau → navigation difficile) ;
- une architecture feature-based complète (overkill pour la taille actuelle).
Le compromis :
/app → routes Next.js
/components → UI par domaine (blog, layout, cv…)
/content → MDX et assets co-localisés
/lib → helpers (blog, utils)
Les composants blog vivent dans /components/blog, pas dans un dossier générique /buttons. Si le blog grossit trop, migration vers /features/blog sans tout casser.
Un dossier par article MDX
Chaque article a son propre dossier :
/content/blog/mon-article/
index.mdx
cover.jpg
/images/
Pourquoi : déplacer ou supprimer un article = déplacer un dossier. Pas de correspondance manuelle entre article.mdx et /public/blog/article/images/.
La structure prépare aussi une évolution i18n : un jour, fr.mdx et en.mdx dans le même dossier, sans refonte des URLs d'emblée.
Velite comme pipeline de contenu
Velite compile le MDX au build time, génère des types TypeScript et valide le frontmatter via son schéma déclaratif (s.string(), s.isodate()…). Les pages consomment #site/content — pas de fs.readFile + regex maison.
Ce que ça m'apporte concrètement :
- Type safety sur
title,date,tags,slug,body; - erreurs de métadonnées bloquantes au build (pas en prod) ;
- assets hashés vers
/public/static/automatiquement.
Le schéma actuel est volontairement minimal. J'ajouterai cover ou draft quand le besoin sera réel.
Ce que j'ai écarté
| Alternative | Pourquoi non |
|---|---|
| MDX plats (sans dossiers) | Assets séparés → erreurs au rename |
| Contentlayer | Plus maintenu depuis 2024 |
| Parsing regex + eval() | Fragile et risqué |
| Compilation MDX runtime | Code custom sans gain vs Velite |
| next-intl dès le départ | Complexité i18n non justifiée sans contenu EN |
| Branche develop séparée | Aucune valeur pour un projet solo — previews Vercel suffisent |
Les trade-offs acceptés
- Étape Velite obligatoire avant
next build— quelques secondes en dev (mode watch) ; .velite/gitignored — regénéré à chaque build ;- Frontmatter YAML sans autocomplete éditeur — compensé par la validation Velite au build ;
- Français uniquement pour l'instant — migration i18n possible grâce à la structure dossiers.
Conclusion
L'architecture n'a pas vocation à impressionner sur un diagramme. Elle doit réduire la friction : écrire un article, ajouter une route, retrouver un composant — sans hésiter.
Prochaine brique visuelle : le design system turquoise — palette, typo Inter et tokens CSS.