Guide Hexo SEO

How to do SEO on a Hexo site — the Node.js static site generator. Hexo outputs pure HTML so content is crawlable on the premier récupérer, but sitemaps, robots.txt, meta descriptions, canonicals, données structurées, and stable permalinks tout depend on plugins and config.

Première publication : 26 juin 2026 · Dernière mise à jour : 3 août 2026 · Advanced
Langues

Hexo is a Node.js static site generator: hexo generate compiles Markdown into pure static HTML, so Googlebot reads votre complet content on the premier récupérer with aucun JavaScript rendering queue. That's the crawlability floor — but it's pas finished SEO. La plupart par défaut themes ship aucun sitemap, aucun robots.txt, aucun per-post meta description, aucun canonical, and aucun données structurées; vous ajouter ceux with _config.yml settings, front matter fields, theme edits, and plugins (hexo-generator-sitemap, hexo-generator-robotstxt, hexo-generator-feed, hexo-abbrlink). The big traps are a incorrect url: in _config.yml, the date-based par défaut permalink que breaks liens on rename, and auto-generated category/tag archives que créer thin contenu dupliqué. Pour Baidu-facing sites, the static output removes a réel exploration obstacle — though that's pas a guarantee of Baidu indexation or ranking.

TL;DR — Hexo (hexo generate) emits pure static HTML, so votre content is in the premier byte of la réponse — aucun Web Rendering Service, aucun Wave 2 delay. That’s the crawlability floor, pas finished SEO. Par défaut themes ship aucun sitemap, aucun robots.txt, aucun per-post meta description, aucun canonical, and aucun données structurées; vous ajouter les via _config.yml, front matter, theme template edits, and plugins (hexo-generator-sitemap, hexo-generator-robotstxt, hexo-generator-feed, hexo-abbrlink, hexo-indexnow). The three traps que en réalité bite: a incorrect url: in _config.yml breaks canonicals/sitemap/feed; the date-based par défaut permalink ties URLs to filenames so a rename breaks liens; and auto-generated category/tag archives créer thin contenu dupliqué. Pour Baidu-facing sites the static output is a réel advantage.

Hexo’s static output is the exploration advantage

hexo generate runs votre Markdown and theme templates via a construire step and writes a folder of finished HTML, CSS, and assets. The SEO-relevant fact is quand the HTML exists: at construire temps, une fois, pour everyone — pas per requête, and pas in le navigateur. Evidence for this claim The Hexo generate command builds static files into the configured public directory. Scope: Hexo generate command. Confidence: high · Verified: Hexo: Commands

Google describes a two-phase traiter pour JavaScript pages: Wave 1 récupère the raw HTML and indexes static content immédiatement; Wave 2 is a deferred headless-Chromium rendering queue que peut prendre seconds to days. Hexo output skips Wave 2 entirely — every page is raw HTML on the premier récupérer. Google’s propre guidance is blunt que ce is the recommended chemin: dynamic rendering was “a workaround and pas a long-term solution… utiliser rendu côté serveur, static rendering, or hydration as a solution,” and Hexo produces static rendering, un of the three explicitly recommended approaches.

Two plus wins fall out of ce:

  • Crawlable liens by par défaut. Hexo templates emit plain <a href> anchors in static HTML, so ils satisfy Google’s requirement que liens be réel, crawlable URLs — aucun JavaScript-generated navigation to design autour.
  • Cheap to explorer. Static fichiers served from a CDN have effectively zero server-processing cost per requête, so Googlebot peut explorer at its allowed rate sans tripping crawl-rate throttling. As Gary Illyes put it, “si vous are making expensive database calls, that’s going to cost le serveur a lot” — Hexo rend none.

The caveat: zero render-blocking pour robots d’exploration n’est pas the même as zero render-blocking pour utilisateurs. Theme JS/CSS encore affecte Core Web Vitals (plus ci-dessous).

Configurer _config.yml premier — url: is the big un

Définir ces global keys avant votre premier deploy:

url: https://yourdomain.com       # must match your live domain, with https://
permalink: :title/                # or :year/:month/:day/:title/ (the default)
title: Site Title
description: Global meta description fallback
author: Your Name
language: en
meta_generator: false             # removes the <meta name="generator" content="Hexo"> tag
  • url: is the unique la plupart consequential setting. It’s le site’s configuré base URL, qui themes and generators peut utiliser pour balise canonicals, feeds, sitemaps, and pagination. A incorrect valeur peut propagate into ceux outputs. Evidence for this claim Hexo's url configuration supplies the website URL used by themes and generators. Scope: Exact downstream fields depend on the installed theme and plugins. Confidence: high · Verified: Hexo: Configuration
  • permalink: — the par défaut :year/:month/:day/:title/ produces date-based URLs que regarder stale over temps and tie the slug to the filename. Cleaner options are /:title/ or /:category/:title/.
  • meta_generator: false strips Hexo’s generator fingerprint from <head>.
  • Deploying to a subdirectory? url: alone isn’t suffisant — définir root: to the subdirectory chemin aussi (e.g. root: /blog/). Hexo’s url_for helper builds root-relative liens, pendant que full_url_for prepends the complet url: valeur; obtenir root: incorrect on a subdirectory deploy and lien internes, feeds, and sitemap entries fin up pointing at the domain root au lieu de the réel chemin.
  • Config precedence: le site’s _config.yml sets the base url/root/permalink valeurs; a theme’s propre config (its bundled _config.yml, or a _config.<theme>.yml at the project root) layers on top pour afficher and template settings, but doesn’t override le site-level Structure d’URL — a theme can’t fix a incorrect url:.
  • Testing in safe mode? hexo server --safe (or hexo --safe) disables every plugin and script, so the output you’re viewing is manquant votre sitemap, robots.txt, and quelconque SEO plugin’s tags. Don’t utiliser a safe-mode preview to vérifier SEO output — run a normal hexo generate premier.

Front matter SEO contrôle (and what’s manquant)

Native Hexo front matter vous pouvez rely on:

---
title: "Article Title for the <title> tag"
date: 2024-01-15
updated: 2024-06-01
tags: [tag1, tag2]
categories: [Category]
permalink: /custom-url/           # overrides the global pattern for this post
published: true
sitemap: false                    # exclude this post from sitemap.xml
---

Ce que is pas in native front matter and nécessite theme prise en charge or a template edit:

  • description (the meta description) — la plupart themes don’t print it sans a patch.
  • keywords (per-post keyword meta) — and largely pointless anyway; Google has ignored <meta name="keywords"> since 2009. Treat keywords as an organizational aid, pas a ranking lever.
  • canonical (override l’URL canonique) — theme-dependent.

Garder the updated: field current quand vous revise a post — sitemap freshness dépend on it (suivant section).

Essential plugins

Sitemap — hexo-generator-sitemap (official):

npm install hexo-generator-sitemap --save
sitemap:
  path:
    - sitemap.xml
  tags: true
  categories: true

It reads lastmod from chaque post’s updated field (falling back to date) — qui matters parce que Bing warns que lastmod “devrait reflect the vrai dernier modification temps of lune page content, pas le sitemap fichier itself.” Après hexo generate, submit le résultating sitemap.xml dans la recherche Google Console and Bing Webmaster Outils. And heed Bing’s autre warning: “Ne faites pas submit a static sitemap and forget it. Nouveau pages won’t obtenir picked up” — pour Hexo que signifie re-deploying and re-submitting (or en utilisant IndexNow) après every nouveau post.

robots.txt — hexo-generator-robotstxt:

npm install hexo-generator-robotstxt --save
robotstxt:
  useragent: "*"
  allow:
    - /
  disallow:
    - /private/
  sitemap: https://yourdomain.com/sitemap.xml

Sans it, Hexo produces aucun robots.txt at tout — aucun sitemap pointer pour robots d’exploration.

RSS — hexo-generator-feed: relevant pour aggregators and Google News eligibility; John Mueller inclut an RSS feed on his propre static site.

IndexNow — hexo-indexnow: Bing recommends pairing sitemaps with IndexNow pour real-time, URL-level submission. Drop the generated clé fichier into source/ so it deploys as yourdomain.com/<key>.txt. Remarque ce is pour Bing, Yandex, and others — pas Google, qui doesn’t utiliser IndexNow pour general pages.

The par défaut permalink has two SEO problems: renaming the Markdown fichier changements l’URL (parce que the slug comes from the filename), and non-Latin titles (Chinese, emoji) produce garbled URLs. hexo-abbrlink decouples l’URL from the filename by writing a stable hash back into front matter:

npm install hexo-abbrlink --save
permalink: posts/:abbrlink/
abbrlink:
  alg: crc32    # crc16 or crc32
  rep: hex      # dec or hex

Vous obtenir something comme /posts/3a9c2b1d/ que survives fichier renames, category changements, and date edits. The underlying rule stands soit façon: une fois une URL is publié, don’t modifier it sans a 301 redirection — a rename sans un destroys popularité des liens and quelconque accumulated ranking signals.

Two plus permalink pitfalls worth knowing avant vous pick a pattern:

  • Don’t utiliser the :id token. Hexo documents post IDs as pas persistent à travers a database cache reset — si votre permalink pattern inclut :id, a cache rebuild peut silently modifier every post’s URL. Stick to :title, :abbrlink, or un autre stable token.
  • trailing_index and trailing_html are separate contrôle, pas un setting. Hexo’s pretty_urls config toggles les independently — un governs si a trailing index.html is stripped from generated liens, the autre si a trailing slash is ajouté. Si ces don’t match how votre host en réalité resolves URLs (some hosts redirection /post to /post/, others don’t), vous pouvez fin up with internal liens, canonicals, and sitemap entries disagreeing with l’URL le serveur en réalité sert.

Suivant theme SEO configuration

Suivant is the most-used Hexo theme, configuré in _config.next.yml:

canonical: true                 # builds canonical from url: + page path

webmaster_tools:
  google: VERIFICATION_STRING
  bing: VERIFICATION_STRING
  baidu: VERIFICATION_STRING

open_graph:
  enable: true
  twitter_card: summary_large_image

The Suivant meta-description gap: Suivant ne fait pas automatically inject a per-post <meta name="description"> from the front matter description:. Vous patch the theme’s head template to fall back from page.description to le site description. Ce is the unique la plupart courant Suivant SEO miss. (Suivant fait prise en charge canonical: true and built-in Ouvrir Graph / Twitter Cards, so ceux au moins fonctionner une fois enabled.)

Pour non-NexT themes, vous usually créer or edit a head partial to emit og:title, og:description, og:image, og:url, and twitter:card — prise en charge varies widely by theme.

Who owns chaque tag quand a theme and a plugin les deux emit it. A theme’s built-in Ouvrir Graph/canonical prise en charge and an all-in-one plugin comme hexo-seo (qui generates its propre breadcrumb, website, and article schema) peut les deux essayer to écrire the même tag. Turning les deux on produces duplicate or conflicting <meta> tags, canonicals, or JSON-LD blocks in the même <head>. Pick un couche as the owner pour chaque tag category — theme or plugin, pas les deux — and disable the corresponding fonctionnalité on the autre avant vous ship.

Category and tag pages: the duplicate-content trap

Hexo auto-generates an archive page pour every category and every tag, chaque filled with post excerpts que aussi apparaître on the posts themselves. At scale that’s hundreds of thin pages competing pour the même requêtes and diluting explorer attention. Votre options:

  1. sitemap: false per archive (impractical at scale).
  2. Theme-level noindex on the category/tag archive templates.
  3. Garder les indexé seulement si a category is a genuine, curated topic hub with réel valeur.
  4. Self-referencing canonical on chaque paginated archive page (page 2 canonicalizes to itself, pas page 1).

Un caveat on option 2: long-term noindex eventually rend Google arrêter suivant the liens on que page, so noindexing tag pages peut reduce exploration of posts que are seulement lié from ceux tags. Assurez-vous tel posts are reachable some autre façon.

Votre route inventory is bigger que source/. Category, tag, archive, and pagination pages don’t come from Markdown fichiers — Hexo’s generator API is ce que en réalité creates les, and themes or plugins peut register leur propre generators aussi. Que signifie the crawlable URL surface peut silently expand au-delà ce que you’d expect from browsing votre source/ folder. Après installing or updating a theme or plugin, run hexo generate and diff the route liste in public/ plutôt que assuming vous know every URL Hexo is producing.

Données structurées / JSON-LD

Hexo injects aucun données structurées by par défaut. Soit ajouter a BlogPosting JSON-LD block to votre theme’s post template (headline, datePublished, dateModified, author, publisher, url) or utiliser an all-in-one plugin comme hexo-seo que generates breadcrumb, website, and article schema pour vous.

Core Web Vitals

Static output is fast, but themes peut undo que. Suivant and nombreux themes bundle grand JS/CSS and icon-font libraries (Font Awesome is a frequent LCP/render-blocking culprit). Audit with Lighthouse, alors reach pour hexo-all-minifier (HTML/CSS/JS compression at construire temps), hexo-lazyload-image, and defer/async on third-party scripts comme analytics and ads.

Targeting Baidu (Chinese-audience sites)

Baidu’s robot d’exploration handles JavaScript poorly, so Hexo’s static HTML removes un obstacle to Baidu discovery. Ajouter baidu_site_verification in Suivant, generate a Baidu-format sitemap with hexo-generator-baidu-sitemap, and push URLs actively with hexo-submit-urls-to-search-engine. Un hosting remarque: GitHub Pages is blocked in mainland China — utiliser Gitee Pages, Cloudflare, or a Chinese CDN pour Baidu trafic.

Treat que as a crawlability advantage, pas a guarantee. Static HTML doesn’t by itself prove Baidu is discovering, indexation, or ranking votre pages — confirmer réel explorer activity and indexation status directement in Baidu Ziyuan (Baidu’s webmaster outils) plutôt que assuming static output alone secures visibility.

Deploying to GitHub Pages — the SEO gotchas

  • Définir url: to votre live adresse (custom domain with https://) avant the premier deploy.
  • Put a CNAME fichier in source/ pour custom domains so it isn’t reset on every hexo deploy.
  • Enforce HTTPS in repo Settings → Pages après DNS propagates.
  • Préférer a GitHub Actions workflow over hexo-deployer-git to éviter CNAME-reset problèmes.

Hexo vs. Hugo vs. Jekyll vs. Astro, pour le SEO

Tout four ship pure static HTML, so the indexability floor is identical — there’s aucun framework-level SEO disadvantage in Hexo. The differences are operational: Hugo (Go) builds far faster at grand scale and has a built-in sitemap; Jekyll is the GitHub Pages par défaut; Astro ships zero JS by par défaut via islands. Hexo’s edge is a rich npm plugin ecosystem and a grand Chinese-language community. Content quality, pas the generator, decides rankings — as Mueller said of switching generators, “Va votre site’s SEO suddenly explode? Aucun. Aussi Aucun.”

Pour the cluster overview and the autre generators, voir Static Site Generators; pour the broader rendering picture, voir JavaScript SEO.

Add an expert note

Pin an expert quote

New person? Create their unclaimed profile at /admin/experts/ → Pin a quote first.