Guide Qwik SEO

«How Qwik's resumability puts content in the HTML by default and drives near-zero INP and TBT — plus the QwikCity patterns for meta tags, canonical URLs, JSON-LD, sitemaps, and i18n that make a Qwik site rank.» _(Traduction)_ (Résumé en français du champ description : le texte source est conservé pour relecture francophone.)

Première publication : 26 juin 2026 · Dernière mise à jour : 3 août 2026 · Avancé
1 indice probant sur cette page

«Qwik is a JavaScript framework whose core trick is resumability: the server serializes app state, listeners, and the component tree into the HTML, so the browser resumes without hydrating (a ~1 KB Qwikloader script still runs — it's not literally zero JS). For SEO that's a double win on routes that are actually server-rendered — content is in the HTML by default (crawlers see it immediately, no render-wave delay) and INP/TBT trend toward zero because no hydration blocks the main thread on load; confirm both with field data rather than assuming them. QwikCity, the meta-framework, lets you mix SSR and SSG per route, plus routeLoader$() for server-side data and a head export for title/meta/OG/canonical/JSON-LD — all server-rendered. Basic SEO works out of the box; the main discipline is using routeLoader$() for dynamic metadata, not client-side effects. The catch is a smaller ecosystem than React/Vue, and — as of this writing — Qwik is on its v2 line, currently in beta.» _(Traduction)_ (Résumé en français du champ tldr : le texte source est conservé pour relecture francophone.)

TL;DR — Qwik’s core innovation est resumability: à SSR temps il serializes event listeners (as HTML attributs), le component tree (dans HTML comments), et app state (dans a qwik/json script) dans le HTML, donc le navigateur resumes au lieu de hydrating — a ~1 KB Qwikloader script encore exécute, donc c’est pas literally zero JS. c’est categorically différent depuis React/Vue/Angular/SolidJS, qui tout hydrate. On routes que sont en réalité serveur-rendu, le SEO payoff est twofold: contenu est dans le HTML par par défaut (aucun rendre-wave delay pour robots d’exploration) et INP/TBT trend toward zero parce que aucun hydration bloque le principal thread on charger — vérifier les deux avec champ données plutôt que assuming les. QwikCity est le meta-framework — SSR et SSG peut être mixed per route, pas choisi une fois pour le entier project. Metadata lives dans le head export (titre, meta, OG, canonical, JSON-LD), fed par routeLoader$() pour serveur-side données. Sitemaps sont automatic dans SSG (pour routes en réalité construit) et a dynamic route dans SSR. Qwik est currently on son v2 line (beta) as de ce writing. Le honest caveat: le ecosystem est newer et plus petit que React’s.

Resumability: le core idea (et pourquoi SEO cares)

Qwik était construit par Miško Hevery — le creator de Angular — à builder.io, et son entier raison à exist est à kill hydration. (As de ce writing, Qwik est on son v2 line, currently dans beta — vérifier le API surface contre votre installed version avant copying code depuis quelconque source, notamment ce un.) Hydration est ce que chaque mainstream framework fait après SSR: il downloads le component code et re-executes il dans le navigateur à attach event handlers et rebuild internal state. As Hevery puts il, “Hydration est quand an application est downloaded et executed twice, une fois as HTML et à nouveau as JavaScript.” Que deuxième execution est pure overhead — lune page semble ready mais n’est pas interactive, et le principal thread est bloqué.

Qwik à la place serializes three choses into the HTML at SSR temps:

  • Event listeners — encoded as HTML attributs (e.g. on:click="./chunk.js#symbol"). A tiny inline script (le Qwikloader, ~1 KB) attaches un mondial listener, lit le encoded chunk/symbol on an event, et downloads seulement que handler code on demand.
  • Component tree structure — encoded dans HTML comments, donc Qwik peut rebuild le hierarchy sans executing component code.
  • Application state — serialized dans a <script type="qwik/json"> bloquer, donc quelconque component peut resume sans son parent étant présent.

Quand lune page charge, Qwik ne fait pas re-exécuter votre components. Preuve à l’appui de cette affirmation Qwik resumability restores listeners and application state without rerunning component initialization on page startup. Portée : Qwik resumability model. Niveau de confiance : élevé · Vérifié : Qwik: Resumable As le docs put il, “Resumability est a façon pour a framework à recover son state sans re-executing le application components on le client.” Le résultat, dans le docs’ words: “Qwik apps fonctionner instantly sans quelconque delay parce que ils ne pas besoin hydration, regardless de leur size or complexity.”

Ce is pas Islands Architecture (Astro). Islands encore hydrate chaque island individually. Qwik hydrates nothing — there’s aucun per-island hydration cost parce que there’s aucun hydration at tout.

Ce que robots d’exploration en réalité recevoir

Parce que Qwik pre-renders tout serveur-side et jamais re-renders on le client, le HTML Googlebot récupère déjà contient votre complet contenu — texte, liens, titres, le lot — pour a route c’est en réalité rendu on le serveur. Rendu est a per-route décision dans QwikCity (SSR, SSG, or a mix); a route left dans client-seulement mode, or contenu récupéré depuis a client-side effect au lieu de routeLoader$(), ne fait pas obtenir ce avantage simplement parce que le project utilise Qwik. Google processes JavaScript dans deux waves (HTML premier, alors a deferred rendre réussir que peut lag hours à days). A heavily client-rendu app risques contenu seulement showing up dans que deuxième wave. A correctement serveur-rendu Qwik route sidesteps que risque: il y a aucun rendre-queue delay parce que le contenu était jamais waiting on client JS dans le premier placer. Treat “Qwik pages behave comme static HTML pour robots d’exploration” as le architecture’s intent, alors confirmer il on votre deployed URLs avec view-source — le safest posture pour JavaScript SEO est verifying la réponse, pas trusting le framework étiquette.

Bing fonctionne le même façon — a deux-wave model que prefers serveur-rendu HTML pour efficiency. Qwik’s HTML-premier sortie avantages les deux moteurs pour le même raison.

«## Core Web Vitals: a structural advantage » (Traduction) (Résumé en français de la section vingt-six, sous-partie un : le texte source est conservé pour vérification lors de la relecture francophone.)

«Google uses field data (CrUX) for the Page Experience signal, and INP replaced FID as a Core Web Vital in March 2024. Here’s where Qwik’s architecture pays off directly: with the Qwikloader as the only script running on load — the docs note sites “can boot with about 1kb of JS (regardless of application complexity)” — there’s almost nothing to block the main thread. Total Blocking Time trends toward zero and INP stays low because there’s no hydration pass competing with the user’s first interactions. A bigger Qwik app doesn’t mean a bigger startup bill; the JavaScript is fetched lazily, per interaction, not as one boot bundle. » (Traduction) (Résumé en français de la section vingt-sept, sous-partie un : le texte source est conservé pour vérification lors de la relecture francophone.)

c’est le difference depuis le established frameworks. Suivant.js, Nuxt, et Angular SSR tout put contenu dans le HTML aussi — ils sont pas mauvais pour le SEO — mais ils carry a hydration coût que scales avec le app. Qwik supprime que coût par design.

c’est le architectural expectation, pas a mesuré résultat. Il ne fait pas guarantee a spécifique INP, TBT, or CrUX score pour votre site — tiers scripts, analytics balises, et per-route données-fetching coût peut tout eat dans le advantage. Confirmer il avec champ données (CrUX, Search Console’s Core Web Vitals rapport) on votre propre deployed URLs avant making a performances claim à a client or stakeholder; voir le Comment Mesurer tab pour le spécifique KPIs et cadence.

Meta balises et le document head

In QwikCity, page metadata lives in a head export from chaque route fichier. Pour static metadata it’s a constant: Preuve à l’appui de cette affirmation Qwik City route modules can export a DocumentHead value or function for route metadata. Portée : Qwik City route metadata. Niveau de confiance : élevé · Vérifié : Qwik City: Head

export const head: DocumentHead = {
  title: 'Qwik SEO Guide',
  meta: [
    { name: 'description', content: 'How Qwik resumability helps SEO.' },
    { property: 'og:title', content: 'Qwik SEO Guide' },
    { property: 'og:description', content: 'Resumability, meta tags, sitemaps.' },
  ],
  links: [
    { rel: 'canonical', href: 'https://example.com/qwik-seo/' },
  ],
};

Tout de ce est rendu serveur-side dans <head>, donc c’est dans le HTML le robot d’exploration voit. Le canonical modèle — links: [{ rel: 'canonical', href: '...' }] — est facile à miss mais est le correct placer pour il.

Pour dynamic metadata (blog posts, produits), le SEO-critical modèle est routeLoader$(). Il exécute serveur-side avant le HTML réponse, et le head export peut être a function ce receives le resolved loader valeur:

export const usePost = routeLoader$(async ({ params }) => {
  return await getPost(params.slug); // runs on the server
});

export const head: DocumentHead = ({ resolveValue }) => {
  const post = resolveValue(usePost);
  return {
    title: post.title,
    meta: [{ name: 'description', content: post.excerpt }],
    links: [{ rel: 'canonical', href: `https://example.com/blog/${post.slug}/` }],
  };
};

Ce est QwikCity’s equivalent de getServerSideProps. Le discipline que matters pour le SEO: récupérer metadata données avec routeLoader$(), pas dans a client-side effect (useSignal()/useResource$() que exécuter dans le navigateur). Si vous définir le titre depuis a client effect, il ne va pas être dans le premier-wave HTML.

Données structurées (JSON-LD)

JSON-LD goes dans le head export’s scripts array, rendu inline dans <head> serveur-side et entièrement crawlable:

export const head: DocumentHead = ({ resolveValue }) => {
  const post = resolveValue(usePost);
  return {
    title: post.title,
    scripts: [
      {
        props: { type: 'application/ld+json' },
        script: JSON.stringify({
          '@context': 'https://schema.org',
          '@type': 'Article',
          headline: post.title,
          datePublished: post.date,
        }),
      },
    ],
  };
};

«Because it’s serialized into the HTML response, there’s no rendering delay before the markup is available to crawlers. One setup detail that’s easy to miss: the scripts field only produces output if your project’s router-head component actually renders head.scripts (typically via dangerouslySetInnerHTML) — it’s not automatic just because you populated the array. If a starter template’s router-head.tsx doesn’t already loop over head.scripts, add that before trusting the JSON-LD shows up in the response. » (Traduction) (Résumé en français de la section quarante, sous-partie un : le texte source est conservé pour vérification lors de la relecture francophone.)

«## Sitemaps and robots.txt » (Traduction) (Résumé en français de la section quarante et un, sous-partie un : le texte source est conservé pour vérification lors de la relecture francophone.)

«- SSG builds: the sitemapOutFile config option auto-generates sitemap.xml during the static build — but it only includes routes that were actually built. A route excluded from the static build (dynamic params you didn’t pre-render, a page gated behind a condition) won’t be in the sitemap even though it exists. » (Traduction) (Résumé en français de la section quarante-deux, sous-partie un : le texte source est conservé pour vérification lors de la relecture francophone.) «- SSR sites: there’s no automatic sitemap — add a route at src/routes/sitemap.xml/index.ts with a RequestHandler that builds and returns the XML dynamically. » (Traduction) (Résumé en français de la section quarante-deux, sous-partie deux : le texte source est conservé pour vérification lors de la relecture francophone.) «- robots.txt: drop it in /public/ so it’s served at the root. » (Traduction) (Résumé en français de la section quarante-deux, sous-partie trois : le texte source est conservé pour vérification lors de la relecture francophone.) «- Canonical and sitemap URLs both depend on origin. QwikCity builds absolute URLs from the configured origin/base (or a forwarded-header origin in SSR middleware). A wrong or leaked preview/staging origin in that configuration produces wrong canonicals and sitemap entries in production — check the actual output, not just the config file, after any adapter or deployment change.

Preuve à l’appui de cette affirmation The SSG origin and base configuration affect absolute canonical and sitemap URLs; preview or deployment origins can leak into production output if adapter configuration is wrong. Portée : production build, server adapter, origin reconstruction and caching Niveau de confiance : élevé · Vérifié : Deployments

» (Traduction) (Résumé en français de la section quarante-deux, sous-partie quatre : le texte source est conservé pour vérification lors de la relecture francophone.)

«## International SEO » (Traduction) (Résumé en français de la section quarante-trois, sous-partie un : le texte source est conservé pour vérification lors de la relecture francophone.)

Two mechanisms, utilisé ensemble:

  • rewriteRoutes dans QwikCity config maps localized URL paths à votre routes sans duplicating components (e.g. /it/documentazione/ → /docs/). Ce donne vous clean, localized URLs — le foundation pour an international Structure d’URL.
  • Qwik Speak (a séparé library) handles contenu traduction.
  • hreflang balises go dans le head export’s links array, pointing chaque locale à son alternates. Voir international SEO et hreflang pour le cross-moteur règles.

SSR vs. SSG pour le SEO

Les deux put contenu dans le HTML, donc les deux sont robot-sûr — et QwikCity lets vous mix modes per route, pas simplement une fois pour le entier project. Choisir per route par contenu shape:

  • SSG (static adapter) produces pure HTML fichiers, aucun serveur nécessaire — ideal pour contenu que ne fait pas modifier per requête. Automatic sitemap (pour routes que étaient en réalité construit), cheapest hosting, fastest TTFB depuis a CDN. Le tradeoff est freshness: contenu seulement mises à jour on le suivant construire, et a route que fails à construire simplement n’est pas là.
  • SSR renders per requête — nécessaire pour personalized or frequently modification données. Exécuter il à le edge (Cloudflare, Vercel, Netlify) pour faible TTFB, et définir Cache-Control headers on SSR réponses donc le CDN peut servir repeats sans re-rendu. Le tradeoff est que a échec à requête temps (a lent or errored routeLoader$()) affecte le actif réponse, donc ajouter erreur handling pour le données récupérer plutôt que letting il surface as a broken page.

«Neither mode is “more SEO-safe” than the other by default — pick per route based on how often the content changes and what happens if the data source is briefly unavailable, then verify the deployed response either way. » (Traduction) (Résumé en français de la section quarante-neuf, sous-partie un : le texte source est conservé pour vérification lors de la relecture francophone.)

Ce que to watch out pour

«- Not everything serializes. Class instances, promises, and streams can’t be put into the HTML state. Code that touches them has to run client-only — keep it out of anything that needs to be in the server HTML (especially metadata). If you deliberately exclude a value with noSerialize(), remember it comes back as undefined after the app resumes on the client — don’t reach for it on anything the page still needs to read post-resume, including metadata paths. » (Traduction) (Résumé en français de la section cinquante et un, sous-partie un : le texte source est conservé pour vérification lors de la relecture francophone.) «- useVisibleTask$() is a real escape hatch, use it sparingly. It runs eagerly on the client after initial render — the one hook that deliberately works against resumability. It doesn’t block rendering or hurt the initial HTML, but it does mean client JS is running that Qwik would otherwise have deferred. Fine for genuinely client-only work (a chart library, a map); wrong choice for anything that should be feeding server-rendered metadata. » (Traduction) (Résumé en français de la section cinquante et un, sous-partie deux : le texte source est conservé pour vérification lors de la relecture francophone.) «- Verify meta tags are in the source, not injected by JS. View-source (not just DevTools’ rendered DOM) should show your title, canonical, and JSON-LD. If they only appear in the rendered DOM, you set them from a client effect instead of the head export / routeLoader$(). » (Traduction) (Résumé en français de la section cinquante et un, sous-partie trois : le texte source est conservé pour vérification lors de la relecture francophone.) «- routeLoader$() vs. useResource$()/useSignal(). Loaders run on the server and feed the head; the others can run in the browser. For anything that must be in metadata or first-wave HTML, use the loader. » (Traduction) (Résumé en français de la section cinquante et un, sous-partie quatre : le texte source est conservé pour vérification lors de la relecture francophone.) «- Smaller ecosystem. Qwik has far fewer CMS connectors and SEO plugins than Next.js, and a smaller community to draw on. The framework is capable; you’ll just write more glue yourself. builder.io’s own site runs on Qwik, so it’s used in production — but go in eyes-open about the maturity gap. » (Traduction) (Résumé en français de la section cinquante et un, sous-partie cinq : le texte source est conservé pour vérification lors de la relecture francophone.)

Où ce sits

Qwik est un de deux frameworks dans le JavaScript frameworks story — le autre étant SolidJS. Le clé distinction à garder straight: Qwik resumes; SolidJS (et React, Vue, Angular) hydrate. Les deux encore sortie contenu-rich HTML via leur meta-frameworks, donc exploration est fine soit façon; le resumability angle est ce que rend Qwik’s INP/TBT profile structurally le meilleur de le groupe. Pour le metric side, voir Core Web Vitals; pour le foundations, le JavaScript SEO hub.

Ajouter une note d’expert

Épingler une citation d’expert

Nouvelle personne ? Créez son profil non revendiqué à /admin/experts/ → Épingler une citation d’expert d’abord.