Introduction : Pourquoi Astro est le choix idéal pour les PME françaises en 2026
Si votre site WordPress rame, coûte cher en hébergement et décroche dans Google, ce tutoriel est fait pour vous.
Astro est un framework SSG (Static Site Generator) qui génère des pages HTML statiques ultra-légères. Contrairement à Next.js qui envoie du JavaScript en permanence, ou à WordPress qui interroge une base de données à chaque visite, Astro livre du HTML pur au navigateur. Résultat : des temps de chargement divisés par deux à cinq, des scores Core Web Vitals au vert, et un SEO local qui remonte naturellement.
Le profil cible de ce guide : vous dirigez une PME, vous avez un site vitrine ou un blog existant, et vous n’avez pas d’équipe dev dédiée. À la fin de ce tutoriel, on aura migré vos contenus, configuré le déploiement automatique sur Coolify, et ajouté un formulaire de contact — sans backend.
Prérequis : Ce dont vous avez besoin avant de commencer
Avant de démarrer, voici ce qu’il faut avoir en place :
- Node.js 18+ installé en local — on recommande pnpm comme gestionnaire de paquets pour sa rapidité
- Un dépôt Git sur GitHub ou GitLab avec accès en écriture
- Notions de base en HTML/CSS — aucune connaissance de React ou Vue n’est requise
- Un compte Coolify (auto-hébergé) ou Netlify pour le déploiement continu
Étape 1 : Initialiser un projet Astro et comprendre sa structure
Créer le projet
La façon la plus simple de démarrer est d’utiliser la CLI officielle :
npm create astro@latest mon-site-pme# Choisir : "Empty" template → Yes to TypeScript → Yes to install dependenciescd mon-site-pmenpm run devLe serveur de développement démarre sur http://localhost:4321. On voit une page blanche — c’est normal, on part de zéro.
Comprendre l’arborescence
mon-site-pme/├── src/│ ├── pages/ ← Chaque fichier = une URL│ ├── components/ ← Composants réutilisables (.astro)│ ├── layouts/ ← Templates de page│ └── content/ ← Collections de contenus (blog, etc.)├── public/ ← Assets statiques (images, favicon)└── astro.config.mjs ← Configuration centraleConfigurer astro.config.mjs
On active le mode SSG et on déclare l’URL du site pour que le sitemap et les balises canonical fonctionnent correctement :
import { defineConfig } from 'astro/config';import sitemap from '@astrojs/sitemap';
export default defineConfig({ output: 'static', site: 'https://mon-site-pme.fr', integrations: [sitemap()],});L’Island Architecture en deux mots
Astro envoie du HTML statique par défaut. Si une partie de la page a besoin d’interactivité (un menu burger, un formulaire avec validation), on l’isole dans une “île” avec la directive client:load. Le reste de la page reste du HTML pur. C’est ce qui explique les gains de performance : on ne charge du JavaScript que là où c’est strictement nécessaire.
Étape 2 : Migrer vos contenus existants vers Astro
Exporter depuis WordPress
On utilise le plugin WP Markdown Exporter (gratuit) pour convertir vos articles en fichiers .md. Après export, on obtient une archive ZIP avec un fichier par article, frontmatter inclus.
---title: "Comment choisir un expert-comptable à Lyon"date: "2024-11-15"description: "Guide pratique pour les dirigeants de PME lyonnaises."---
Contenu de l'article...On place ces fichiers dans src/content/blog/ (pas dans src/pages/ directement — les Content Collections d’Astro offrent plus de flexibilité).
Configurer les Content Collections
import { defineCollection, z } from 'astro:content';
const blog = defineCollection({ type: 'content', schema: z.object({ title: z.string(), date: z.coerce.date(), description: z.string(), draft: z.boolean().default(false), }),});
export const collections = { blog };Créer le layout réutilisable
---const { title, description, date } = Astro.props;---<!DOCTYPE html><html lang="fr"> <head> <meta charset="UTF-8" /> <meta name="description" content={description} /> <title>{title} — Mon Site PME</title> </head> <body> <header><!-- Navigation --></header> <main> <h1>{title}</h1> <time>{date.toLocaleDateString('fr-FR')}</time> <slot /> </main> <footer><!-- Footer --></footer> </body></html>Gérer les images
Astro propose un composant <Image /> intégré qui convertit automatiquement en WebP et génère les attributs width/height pour éviter le CLS :
---import { Image } from 'astro:assets';import monImage from '../assets/photo-equipe.jpg';---<Image src={monImage} alt="L'équipe de la PME" width={800} height={450} />Préserver les URLs existantes
C’est le point le plus critique pour le SEO. Si vos articles WordPress étaient sur /blog/mon-article/, on crée exactement le même chemin dans Astro. Si une URL change, on configure les redirections dans astro.config.mjs :
export default defineConfig({ redirects: { '/ancienne-url': '/nouvelle-url', },});Étape 3 : Optimiser les performances et le SEO local avec Astro
Balises meta dynamiques
On crée un composant SEO.astro réutilisable dans tous les layouts :
---const { title, description, ogImage = '/og-default.jpg', canonicalURL = Astro.url,} = Astro.props;---<title>{title}</title><meta name="description" content={description} /><link rel="canonical" href={canonicalURL} /><meta property="og:title" content={title} /><meta property="og:description" content={description} /><meta property="og:image" content={ogImage} />Sitemap automatique
L’intégration @astrojs/sitemap (déjà ajoutée à l’étape 1) génère sitemap-index.xml automatiquement à chaque build. On n’a rien d’autre à faire que de le déclarer dans Google Search Console.
pnpm add @astrojs/sitemapPolices locales avec @fontsource
Google Fonts ajoute une requête réseau externe qui pénalise le LCP. On remplace ça par des polices auto-hébergées :
pnpm add @fontsource/inter---// Dans le layout principalimport '@fontsource/inter/400.css';import '@fontsource/inter/700.css';---Mesurer les gains
Voici des résultats typiques observés après migration d’un site WordPress vers Astro :
| Métrique | WordPress (avant) | Astro (après) |
|---|---|---|
| LCP | 4,2s | 0,9s |
| CLS | 0,18 | 0,01 |
| Score Lighthouse Performance | 52 | 97 |
| Taille de la page (HTML+JS) | 380 Ko | 28 Ko |
| Time to First Byte | 820ms | 45ms |
Étape 4 : Déployer le site Astro sur Coolify avec CI/CD automatisé
Connecter le dépôt à Coolify
Dans l’interface Coolify, on crée une nouvelle ressource :
- New Resource → Application
- Sélectionner le dépôt GitHub
mon-site-pme - Choisir le type Static Site (Coolify détecte Astro automatiquement)
Configurer le build
Build Command : npm run buildPublish Directory : distNode Version : 18Variables d’environnement
Si le site consomme des APIs externes (formulaire, analytics), on déclare les variables dans l’onglet Environment de Coolify :
PUBLIC_SITE_URL=https://mon-site-pme.frPUBLIC_FORMSPARK_ID=xxxxxxxxxxxxPUBLIC_ sont exposées côté client dans Astro. Les variables sans préfixe restent côté serveur (build uniquement). Activer le déploiement automatique
Dans les paramètres de l’application Coolify :
- Auto Deploy : activé
- Branch :
main - Copier le Webhook URL généré par Coolify
- Dans GitHub → Settings → Webhooks → coller l’URL
Désormais, chaque git push sur main déclenche un build et un déploiement automatique. Le tout prend environ 45 secondes pour un site de taille PME classique.
Vérifier le déploiement
Dans l’onglet Deployments de Coolify, on suit les logs en temps réel :
✓ Cloning repository...✓ Installing dependencies (pnpm install)✓ Building (npm run build) > astro build ✓ 47 pages built in 3.2s✓ Deploying to /dist✓ Site live at https://mon-site-pme.frOn teste ensuite avec le domaine personnalisé et on vérifie que le certificat SSL est bien actif (Coolify gère Let’s Encrypt automatiquement).
Étape 5 : Aller plus loin — Ajouter un formulaire de contact sans backend
Choisir sa solution de formulaire
Deux options sans serveur Node.js dédié :
| Solution | Prix | Intégration |
|---|---|---|
| Formspark | 9€/mois (1000 soumissions) | Attribut action HTML |
| Netlify Forms | Gratuit jusqu’à 100/mois | Attribut netlify HTML |
Créer le composant ContactForm.astro
---const FORMSPARK_ID = import.meta.env.PUBLIC_FORMSPARK_ID;---<form action={`https://submit-form.com/${FORMSPARK_ID}`} method="POST" class="contact-form"> <input type="hidden" name="_redirect" value="/merci" />
<label for="nom">Nom *</label> <input type="text" id="nom" name="nom" required minlength="2" maxlength="100" />
<label for="email">Email *</label> <input type="email" id="email" name="email" required />
<label for="message">Message *</label> <textarea id="message" name="message" required minlength="10" rows="5" ></textarea>
<button type="submit">Envoyer</button></form>La validation HTML5 native (required, type="email", minlength) couvre 95% des besoins sans une seule ligne de JavaScript.
Quand utiliser une île Astro ?
Si on veut une validation en temps réel (afficher les erreurs au fur et à mesure de la saisie), on passe le composant en île :
<!-- Dans la page contact.astro --><ContactFormInteractif client:load />Sinon, on garde le composant .astro pur — pas de client:load, pas de JavaScript envoyé.
Connecter les notifications à n8n
Formspark supporte les webhooks. On configure un webhook vers n8n pour déclencher une notification Slack ou un email à chaque soumission :
- Dans Formspark → Settings → Webhooks → ajouter l’URL du webhook n8n
- Dans n8n, créer un workflow : Webhook → Slack (ou Send Email)
Conclusion : Une migration rentable pour votre PME et les prochaines étapes
En suivant ce tutoriel, on est passé d’un site WordPress lent et coûteux à un site Astro statique avec des scores Lighthouse proches de 100, un SEO local renforcé, et un coût d’hébergement divisé par trois à cinq.
Les prochaines évolutions naturelles pour une PME : connecter un CMS headless comme Decap CMS ou Sanity pour permettre à vos équipes de publier du contenu sans toucher au code. C’est la puissance du JAMstack — le contenu est éditable, le site reste statique et performant.
Dans un prochain article, on verra comment automatiser la publication de nouveaux articles via n8n : rédiger dans Notion, valider, et déclencher un déploiement Astro automatiquement — zéro intervention technique.
Besoin d’aide pour migrer votre site ? Chez Kodixar, j’accompagne les PME françaises dans ce type de transition. Contactez-moi pour qu’on en discute.