# Hexo User Guide

**Hexo** is a fast, simple, and powerful static-site framework powered by Node.js. You write your content in plain text (Markdown by default), and Hexo renders it into a complete static website — posts, pages, archives, categories, and tags — ready to deploy anywhere that serves files.

This guide is for the people who **build sites with Hexo**: bloggers, writers, documentation authors, and developers who want a fast, file-based publishing workflow. It covers installing Hexo, scaffolding a site, writing content, the full command-line interface, the tag plugins you can drop into your posts, configuration you will touch every day, and how to deploy.

> [!NOTE]
> Hexo itself is a framework. It does its job through **plugins** (renderers, generators, deployers) and **themes**. A freshly scaffolded Hexo site already wires up the essential plugins for you, so you can write your first post within minutes. Where a feature lives in a separate plugin, this guide says so explicitly.

---

## 1. Quick Start

Get from nothing to a running blog in five commands.

```bash
# 1. Install the Hexo command-line tool globally
npm install -g hexo-cli

# 2. Scaffold a new site into the folder "blog"
hexo init blog
cd blog

# 3. Install the site's dependencies (theme, markdown renderer, server)
npm install

# 4. Write a new post
hexo new "My First Post"

# 5. Generate the static files and preview locally
hexo generate
hexo server
```

```text
INFO  Validating config
INFO  Start processing
INFO  Hexo is running at http://localhost:4000 . Press Ctrl+C to stop.
```

Open `http://localhost:4000` in your browser to see your site.

> [!TIP]
> Most commands have short aliases. `hexo g` = `hexo generate`, `hexo s` = `hexo server`, `hexo d` = `hexo deploy`. Aliases are resolved by prefix, so any unambiguous abbreviation works (`hexo gen`, `hexo ser`).

> [!IMPORTANT]
> `hexo init` and `hexo server` are provided by the **hexo-cli** package and the **hexo-server** plugin respectively — not by the Hexo core. `npm install` inside a scaffolded site pulls them in. If `hexo server` reports an unknown command, run `npm install hexo-server --save` in your site folder.

---

## 2. Requirements

| Requirement | Detail |
|---|---|
| **Node.js** | `>=20.19.0` (declared in Hexo's `engines` field; older Node will refuse to install) |
| **npm** | Ships with Node.js; used to install Hexo, plugins, and themes |
| **Git** | Optional, but required if you deploy with the Git deployer |
| **A terminal** | All Hexo workflows are command-line driven |

Hexo runs on Windows, macOS, and Linux. Paths in this guide use forward slashes; Hexo normalizes backslashes internally on Windows.

> [!NOTE]
> Hexo (the `hexo` package) is version **8.1.2** as documented here. The command-line launcher is the separate `hexo-cli` package — keep both reasonably current.

---

## 3. Installation

### 3.1 Install the command-line tool

The `hexo` command is provided by **hexo-cli**. Install it globally so you can scaffold and manage sites from anywhere:

=== "npm"

    ```bash
    npm install -g hexo-cli
    ```

=== "yarn"

    ```bash
    yarn global add hexo-cli
    ```

=== "pnpm"

    ```bash
    pnpm add -g hexo-cli
    ```

Verify the install:

```bash
hexo version
```

```text
hexo-cli: 4.3.2
os: ...
node: ...
```

### 3.2 Per-project install (alternative)

If you prefer not to install anything globally, you can run Hexo through `npx` after scaffolding, or add `hexo-cli` as a local dev dependency and invoke it with `npx hexo <command>`. Every Hexo site already lists `hexo` as a dependency in its own `package.json`.

> [!TIP]
> A global `hexo-cli` plus a local `hexo` dependency is the recommended setup: the global launcher finds and runs the locally-installed Hexo version, so each site can pin its own Hexo release.

---

## 4. Scaffolding and Project Anatomy

### 4.1 Create a site

```bash
hexo init <folder>
cd <folder>
npm install
```

`hexo init` clones the default starter (which includes a `_config.yml`, a basic `landscape` theme reference, the `hexo-renderer-marked` Markdown renderer, and `hexo-server`), then `npm install` downloads them.

### 4.2 What's in a Hexo site

```text
.
├── _config.yml          # Site configuration (the file you edit most)
├── package.json         # Site dependencies (Hexo, theme, plugins)
├── scaffolds/           # Templates for `hexo new`
│   ├── draft.md
│   ├── page.md
│   └── post.md
├── source/              # Your content lives here
│   ├── _posts/          # Published posts (Markdown files)
│   ├── _drafts/         # Unpublished drafts (optional)
│   └── _data/           # Site-wide data files (optional)
├── themes/              # Installed themes (or installed via npm)
├── public/              # Generated output (created by `hexo generate`)
└── db.json              # Cache of processed source (created at runtime)
```

| Folder / file | What it is | You edit it? |
|---|---|---|
| `_config.yml` | The site config — title, URL, permalinks, theme, deployment | **Yes, often** |
| `source/_posts/` | Your blog posts, one Markdown file each | **Yes** |
| `source/_drafts/` | Drafts not yet published | Yes |
| `source/_data/` | YAML/JSON data available to themes as `site.data` | Sometimes |
| `source/` (other) | Static assets and standalone pages (copied or rendered) | Sometimes |
| `scaffolds/` | Front-matter templates used by `hexo new` | Occasionally |
| `themes/` | Theme files (layouts, styles) | If theming |
| `public/` | Generated HTML — **never edit by hand**, it is overwritten | No |
| `db.json` | Runtime cache — safe to delete (`hexo clean` removes it) | No |

> [!WARNING]
> Anything under `source/` whose path begins with `_` (like `_posts`, `_drafts`, `_data`) is treated specially and is **not** copied verbatim to `public/`. Files and folders starting with `_` or `.` elsewhere are skipped as "hidden" unless you add them to the `include` config.

---

## 5. Writing Content

Hexo content is plain text with a **front-matter** block at the top. Front-matter is a small YAML (or JSON) section between `---` delimiters that sets the post's metadata.

### 5.1 Create a post

```bash
hexo new "Hello World"
```

```text
INFO  Created: ~/blog/source/_posts/Hello-World.md
```

This creates `source/_posts/Hello-World.md` from the `scaffolds/post.md` template:

```markdown
---
title: Hello World
date: 2026-06-05 14:30:00
tags:
---

Write your post content here, in Markdown.
```

### 5.2 Front-matter reference

These keys are understood by Hexo for posts and pages. Any other key you add becomes a custom variable available to your theme.

| Key | Applies to | Meaning |
|---|---|---|
| `title` | post, page | The displayed title |
| `date` | post, page | Creation date/time (controls sort order and permalink tokens) |
| `updated` | post, page | Last-modified date (see `updated_option` in config) |
| `tags` | post | A list of tags (posts only — pages have no tags) |
| `categories` | post | A list (or nested list) of categories |
| `layout` | post, page | Which theme layout to render with (`post`, `page`, or a custom one) |
| `permalink` | post, page | Override the generated URL for this single item |
| `comments` | post, page | `true`/`false` to toggle comments (themes honor this) |
| `excerpt` | post | Explicit excerpt text |
| `photos` | post | A list of image URLs (used by gallery/photo post styles) |
| `published` | post | `false` keeps a post out of the build even from `_posts/` |

> [!NOTE]
> Singular aliases are accepted and normalized automatically: `tag` → `tags`, `category` → `categories`, `photo` → `photos`. Use whichever reads better; Hexo converts them.

#### Tags and categories

```yaml
---
title: A Categorized, Tagged Post
date: 2026-06-05 10:00:00
categories:
  - Tutorials
tags:
  - hexo
  - markdown
---
```

**Nested (hierarchical) categories** — wrap the hierarchy in a sub-list:

```yaml
categories:
  - [Programming, JavaScript]   # Programming → JavaScript
```

> [!TIP]
> A category named identically to an existing one is reused, not duplicated. Hierarchies are matched by parent: `[Programming, JavaScript]` and `[Cooking, JavaScript]` create two different "JavaScript" categories under different parents.

### 5.3 Create a page

Pages are standalone (About, Contact) and live at the top of `source/`, not in `_posts/`:

```bash
hexo new page "about"
```

```text
INFO  Created: ~/blog/source/about/index.md
```

This produces `source/about/index.md`, which publishes to `/about/`.

### 5.4 Drafts

Drafts let you work on a post without publishing it. Create one and it lands in `source/_drafts/`:

```bash
hexo new draft "Work In Progress"
```

```text
INFO  Created: ~/blog/source/_drafts/Work-In-Progress.md
```

Drafts are excluded from the build by default. To preview drafts while writing:

```bash
hexo server --draft        # or set render_drafts: true in _config.yml
```

When the draft is ready, **publish** it (moves the file from `_drafts/` to `_posts/`):

```bash
hexo publish "Work In Progress"
```

```text
INFO  Published: ~/blog/source/_posts/Work-In-Progress.md
```

### 5.5 Post assets (images alongside posts)

By default, images go in `source/images/` (or any folder under `source/`) and are referenced by path. If you prefer to keep each post's images next to the post, enable **post asset folders**:

```yaml
# _config.yml
post_asset_folder: true
```

Now `hexo new "My Post"` creates both `My-Post.md` and a `My-Post/` folder. Drop images into that folder and reference them with the `asset_img` tag (see §8).

---

## 6. The Command-Line Interface

Run any command from inside your site folder. Below are the commands provided by the Hexo core, followed by global options.

> [!NOTE]
> `hexo init`, `hexo version`, and `hexo help` come from **hexo-cli**. `hexo server` comes from the **hexo-server** plugin. The remaining commands below are built into Hexo core.

### 6.1 Command summary

| Command | Alias | Purpose |
|---|---|---|
| `hexo init [folder]` | — | Scaffold a new site (from hexo-cli) |
| `hexo new <title>` | `n` | Create a new post, page, or draft |
| `hexo generate` | `g` | Render the site into `public/` |
| `hexo server` | `s` | Serve the site locally with live reload (from hexo-server) |
| `hexo publish <filename>` | `p` | Move a draft into `_posts/` |
| `hexo deploy` | `d` | Deploy `public/` to a remote |
| `hexo render <file>` | — | Render one or more files with the renderer plugins |
| `hexo migrate <type>` | — | Import content from another system |
| `hexo clean` | — | Delete `db.json` and `public/` |
| `hexo list <type>` | — | List posts, pages, routes, tags, or categories |
| `hexo config [name] [value]` | — | View or change configuration |
| `hexo version` | `v` | Show version info (from hexo-cli) |
| `hexo help` | `h` | Show help (from hexo-cli) |

### 6.2 `hexo new` — create content

```bash
hexo new [layout] <title>
```

| Argument / option | Meaning |
|---|---|
| `layout` | `post` (default), `page`, `draft`, or any scaffold name |
| `title` | The post title — wrap in quotes if it contains spaces |
| `-p, --path` | Custom path for the new file |
| `-s, --slug` | Custom slug (controls the filename and URL) |
| `-r, --replace` | Overwrite an existing file with the same name |

```bash
hexo new post "Deep Dive into Static Sites"
hexo new page "contact"
hexo new draft "Half-Baked Idea"
hexo new "Quick Note" --slug quick-note
```

> [!TIP]
> Any extra front-matter you want pre-filled can be passed as flags. For example `hexo new "Post" --author Jane` adds `author: Jane` to the new file's front-matter (reserved option names like `--path`, `--slug`, `--replace`, `--config`, `--debug`, `--safe`, `--silent` are excluded).

### 6.3 `hexo generate` — build the site

```bash
hexo generate
```

| Option | Meaning |
|---|---|
| `-d, --deploy` | Deploy automatically after generating |
| `-f, --force` | Regenerate every file, ignoring the cache |
| `-w, --watch` | Watch for changes and regenerate incrementally |
| `-b, --bail` | Throw and stop on the first unhandled error during generation |
| `-c, --concurrency` | Max number of files generated in parallel (default: unlimited) |

```bash
hexo generate --watch                 # rebuild on every save
hexo generate --deploy                # build then deploy
hexo generate --concurrency 5         # cap parallelism on low-memory machines
```

> [!NOTE]
> Generation is **incremental and content-hashed**. Hexo computes a SHA-1 of each output route and skips writing files whose hash hasn't changed since the last build. Use `--force` to bypass this when you suspect stale output.

### 6.4 `hexo server` — local preview

```bash
hexo server
```

Serves the site at `http://localhost:4000` and watches your source for changes. Provided by the `hexo-server` plugin (installed with a scaffolded site).

| Common option | Meaning |
|---|---|
| `-p, --port` | Port to listen on (default 4000) |
| `-i, --ip` | Bind address |
| `-s, --static` | Serve only the already-generated `public/` (no watching) |
| `--draft` | Include drafts in the preview |

> [!TIP]
> You can enable an in-memory cache for the server so repeated requests skip re-rendering:
> ```yaml
> # _config.yml
> server:
>   cache: true
> ```

### 6.5 `hexo deploy` — publish your site

```bash
hexo deploy
```

| Option | Meaning |
|---|---|
| `-g, --generate` | Generate before deploying |
| `--setup` | Run deployer setup only, without deploying |

Deployment requires a `deploy` block in `_config.yml` and a deployer plugin. If `deploy` is unset, Hexo prints the list of available deployer plugins and exits. See §9.

### 6.6 `hexo clean` — reset the build

```bash
hexo clean
```

```text
INFO  Deleted database.
INFO  Deleted public folder.
```

Removes `db.json` (the cache) and `public/` (the output). Run this whenever a build looks stale, after changing themes, or before a fresh deploy.

### 6.7 `hexo list` — inspect your site

```bash
hexo list <type>
```

`type` is one of: `post`, `page`, `route`, `tag`, `category`.

```bash
hexo list post        # every post with date, title, path
hexo list category    # categories and their post counts
hexo list route       # every URL the site will generate
```

### 6.8 `hexo render` — render a single file

```bash
hexo render <file1> [file2] ...
```

| Option | Meaning |
|---|---|
| `--output` | Write the result to a file (otherwise printed to the terminal) |
| `--engine` | Force a specific render engine |
| `--pretty` | Pretty-print JSON output |

```bash
hexo render data.yml --output data.json --pretty
```

This runs a file through Hexo's renderer plugins — handy for converting YAML to JSON, or previewing how a Markdown file renders.

### 6.9 `hexo config` — view or edit config

```bash
hexo config                 # print the entire merged config
hexo config title           # print one value
hexo config title "My Blog" # set a value and write it back to _config.yml
hexo config server.cache true   # dotted keys reach nested settings
```

> [!NOTE]
> Values are type-cast: `true`/`false` become booleans, numbers become numbers, `null`/`undefined` become those literals, everything else stays a string.

### 6.10 `hexo migrate` — import from elsewhere

```bash
hexo migrate <type>
```

Imports content from another blogging system using a migrator plugin (for example `hexo-migrator-rss`, `hexo-migrator-wordpress`). Install the matching `hexo-migrator-*` package first; running `hexo migrate` with no type lists the installed migrators.

### 6.11 Global options

These apply to every command:

| Option | Meaning |
|---|---|
| `--config <path>` | Use a specific config file (or a comma-separated list to merge several) |
| `--debug` | Verbose logging plus a `debug.log` in the site root |
| `--safe` | Safe mode — load **no** plugins or scripts |
| `--silent` | Suppress terminal output |
| `--draft`, `--drafts` | Include drafts in the run |

```bash
hexo generate --config _config.yml,_config.prod.yml   # merge configs left→right
hexo server --safe                                    # diagnose a misbehaving plugin
```

> [!TIP]
> `--safe` is the first thing to try when a build breaks after installing a plugin. If the problem disappears in safe mode, a plugin or a `scripts/` file is the cause.

---

## 7. Configuration You'll Use Daily

Configuration lives in `_config.yml` at the site root. This section covers the settings you touch most; the **Admin Guide** carries the complete reference with every key and default.

### 7.1 Site identity

```yaml
title: My Blog
subtitle: ''
description: ''
keywords:
author: John Doe
language: en
timezone: ''
```

> [!WARNING]
> Leaving `timezone` empty makes Hexo use your machine's local timezone and prints a warning on every build. Set it explicitly (for example `timezone: America/New_York` or `timezone: UTC`) to get stable, reproducible dates. A future major version will default to UTC.

### 7.2 URL and permalinks

```yaml
url: https://example.com
root: /
permalink: :year/:month/:day/:title/
permalink_defaults:
pretty_urls:
  trailing_index: true   # keep index.html in URLs
  trailing_html: true    # keep .html in URLs
```

The `permalink` pattern controls post URLs. Available tokens:

| Token | Expands to |
|---|---|
| `:year` `:month` `:day` | 4-digit year, 2-digit month, 2-digit day of the post date |
| `:i_month` `:i_day` | Month/day without leading zeros |
| `:hour` `:minute` `:second` | Time components |
| `:title` | The post's slugified filename/title path |
| `:name` | The filename portion only |
| `:post_title` | Slugified post title |
| `:id` | Internal post ID |
| `:category` | The post's (last) category, or `default_category` if none |
| `:hash` | A short hash derived from slug + date |

```yaml
permalink: posts/:title/                 # /posts/my-post/
permalink: :year/:month/:title.html      # /2026/06/my-post.html
permalink: :category/:title/             # /tutorials/my-post/
```

> [!IMPORTANT]
> `url` must be a valid `http`/`https` URL and `root` must be non-empty, or Hexo refuses to build with an `Invalid config detected` error. If `root` is unset, Hexo derives it from the path portion of `url`.

### 7.3 Directories

```yaml
source_dir: source
public_dir: public
tag_dir: tags
archive_dir: archives
category_dir: categories
code_dir: downloads/code
i18n_dir: :lang
skip_render:
```

`skip_render` takes glob patterns for files that should be copied verbatim instead of rendered:

```yaml
skip_render:
  - 'README.md'
  - 'migration-guide/**'
```

### 7.4 Writing behavior

```yaml
new_post_name: :title.md
default_layout: post
titlecase: false           # auto-titlecase post titles
external_link:
  enable: true             # open external links in a new tab
  field: site
  exclude: ''
filename_case: 0           # 0=keep, 1=lowercase, 2=uppercase slugs
render_drafts: false
post_asset_folder: false
relative_link: false
future: true               # show posts dated in the future
```

### 7.5 Dates, pagination, categories, tags

```yaml
date_format: YYYY-MM-DD
time_format: HH:mm:ss
updated_option: mtime      # mtime | date | empty

per_page: 10
pagination_dir: page

default_category: uncategorized
category_map:
tag_map:
```

### 7.6 Theme and deployment

```yaml
theme: landscape

deploy:
  type: ''
```

Change `theme` to the folder name under `themes/` (or the suffix of an installed `hexo-theme-*` package). See §9 for `deploy`.

> [!TIP]
> You can keep a separate theme config in `_config.<theme>.yml` at your site root. Hexo merges it into the theme's own config, so you can customize a theme without editing files inside `themes/`.

---

## 8. Tag Plugins — Rich Content in Your Posts

**Tag plugins** are special `{% ... %}` snippets you put directly in your Markdown. They expand into HTML when the site is generated. Hexo ships the following built-in tags.

> [!NOTE]
> Tag-plugin syntax uses Nunjucks/Swig-style braces. If you ever need to show literal `{% %}` in your text (for example, in a tutorial), wrap it in a raw block: `{% raw %}...{% endraw %}`.

### 8.1 Images

```text
{% img [class names] /path/to/image [width] [height] [title text [alt text]] %}
```

```text
{% img /images/photo.png 600 400 "A sunset" "sunset over the bay" %}
{% img thumbnail /images/photo.png %}
```

Aliases: `img`, `image`.

### 8.2 Post asset images and links

When `post_asset_folder: true`, reference a post's own assets by slug:

```text
{% asset_img slug [width] [height] [title text [alt text]] %}
{% asset_link slug [title] [escape] %}
{% asset_path slug %}
```

```text
{% asset_img cover.jpg 800 600 "Cover" %}
{% asset_link report.pdf "Download the report" %}
```

Aliases for the image tag: `asset_img`, `asset_image`.

### 8.3 Links

```text
{% link text url [external] [title] %}
```

```text
{% link "Hexo docs" https://hexo.io true "Official documentation" %}
```

Aliases: `link`, `a`, `anchor`.

#### URL helpers as tags

```text
{% url_for text path [relative] %}
{% full_url_for text path %}
```

These produce an `<a>` linking to a site-relative or fully-qualified URL.

### 8.4 Linking to other posts

```text
{% post_link slug-or-title [display text] [escape] %}
{% post_path slug-or-title %}
```

```text
{% post_link hello-world %}
{% post_link hello-world "See my first post" %}
```

`post_link` produces a full `<a>` tag; `post_path` produces just the URL. You can append a fragment: `{% post_link my-post#section %}`.

> [!CAUTION]
> If the referenced post does not exist, `post_link` and `post_path` throw `Post not found`. Double-check the slug or title.

### 8.5 Code blocks

The `codeblock` tag (alias `code`) renders highlighted code with optional captions and line marking:

```text
{% codeblock [title] [lang:language] [url] [link_text] [options] %}
code snippet
{% endcodeblock %}
```

| Option | Meaning |
|---|---|
| `lang:` | Language for highlighting (e.g. `lang:python`) |
| `line_number:` | `true`/`false` — show line numbers |
| `first_line:` | First line number |
| `mark:` | Highlight specific lines: `mark:1,4-7,10` |
| `wrap:` | `true`/`false` — wrap in a table |
| `highlight:` | `false` to disable highlighting and emit plain escaped code |

```text
{% codeblock Example lang:javascript mark:2 %}
function hello() {
  console.log('highlighted line');
}
{% endcodeblock %}
```

### 8.6 Include external code

```text
{% include_code [title] [lang:language] path/to/file %}
```

Pulls a file from your `code_dir` (default `source/downloads/code/`) and renders it as a highlighted block with a "view raw" link. Aliases: `include_code`, `include-code`.

### 8.7 Quotes

```text
{% blockquote [author[, source]] [link] [source_link_title] %}
Quote text
{% endblockquote %}
```

```text
{% blockquote Albert Einstein %}
Imagination is more important than knowledge.
{% endblockquote %}
```

Aliases: `blockquote`, `quote`. A simpler styled variant:

```text
{% pullquote [class] %}
Pulled-out highlighted text.
{% endpullquote %}
```

### 8.8 Embeds

```text
{% iframe url [width] [height] %}
```

```text
{% iframe https://example.com/embed 100% 400 %}
```

### 8.9 Tag quick reference

| Tag (and aliases) | Block? | Purpose |
|---|---|---|
| `img` / `image` | no | Insert an image |
| `asset_img` / `asset_image` | no | Insert a post-asset image by slug |
| `asset_link` | no | Link to a post asset |
| `asset_path` | no | Output a post asset's URL |
| `link` / `a` / `anchor` | no | Insert a hyperlink |
| `url_for` | no | Link to a site-relative path |
| `full_url_for` | no | Link to a fully-qualified URL |
| `post_link` | no | Link to another post |
| `post_path` | no | Output another post's URL |
| `codeblock` / `code` | yes | Highlighted code block |
| `include_code` / `include-code` | no | Embed a file from `code_dir` |
| `blockquote` / `quote` | yes | Cited blockquote |
| `pullquote` | yes | Styled pull-quote |
| `iframe` | no | Embed an iframe |
| `raw` | yes | Output literal content unprocessed (from Nunjucks) |

---

## 9. Deploying Your Site

Hexo deploys via **deployer plugins**. Configure the `deploy` block in `_config.yml`, install the matching plugin, then run `hexo deploy`.

### 9.1 Deploy to GitHub Pages (Git deployer)

```bash
npm install hexo-deployer-git --save
```

```yaml
# _config.yml
deploy:
  type: git
  repo: https://github.com/<username>/<username>.github.io.git
  branch: gh-pages
```

```bash
hexo clean
hexo deploy --generate     # build then push
```

### 9.2 Multiple deploy targets

`deploy` can be a list — Hexo runs each target in order:

```yaml
deploy:
  - type: git
    repo: https://github.com/me/site.git
    branch: gh-pages
  - type: rsync
    host: example.com
    user: deploy
    root: /var/www/site
```

> [!NOTE]
> Each entry needs a `type` that names an installed deployer plugin. If a target's deployer isn't installed, Hexo logs `Deployer not found` and skips it. Running `hexo deploy` with an empty `deploy` block prints the deployer plugins you have installed.

### 9.3 Deploy checklist

- [ ] `url` and `root` in `_config.yml` match your hosting (custom domain or `/repo/` subpath)
- [ ] A deployer plugin is installed and configured
- [ ] `hexo clean` run before a release build
- [ ] `hexo generate` produces the expected files in `public/`
- [ ] `hexo deploy` (or `hexo deploy --generate`) completes without `Deployer not found`

> [!TIP]
> For static hosts that pull from a Git repo (Netlify, Vercel, Cloudflare Pages, GitHub Actions), you often skip `hexo deploy` entirely — point the host at your repo and let it run `hexo generate`, serving `public/`.

---

## 10. Extending Your Site with Plugins and Themes

### 10.1 Installing plugins

Hexo's capabilities come from plugins published on npm under the `hexo-` prefix. Install them into your site and they load automatically.

```bash
npm install hexo-renderer-marked --save     # Markdown rendering (default)
npm install hexo-generator-sitemap --save   # generate sitemap.xml
npm install hexo-generator-feed --save      # generate an RSS/Atom feed
```

> [!IMPORTANT]
> Hexo core does **not** ship a Markdown renderer or the index/archive/category/tag page generators. A scaffolded site includes `hexo-renderer-marked` for Markdown. For listing pages (the blog index, monthly archives, per-tag and per-category pages) install generator plugins such as `hexo-generator-index`, `hexo-generator-archive`, `hexo-generator-category`, and `hexo-generator-tag`. Most themes document which generators they expect.

Common plugin categories:

| Plugin type | Examples | What it adds |
|---|---|---|
| **Renderer** | `hexo-renderer-marked`, `hexo-renderer-pug`, `hexo-renderer-stylus` | Render Markdown/templates/styles |
| **Generator** | `hexo-generator-index`, `-archive`, `-category`, `-tag`, `-sitemap`, `-feed` | Build listing/index/feed pages |
| **Deployer** | `hexo-deployer-git`, `hexo-deployer-rsync` | Publish to a remote |
| **Tag plugin** | community packages | New `{% %}` tags |

> [!NOTE]
> Only packages named `hexo-*` (or scoped `@scope/hexo-*`) are auto-loaded, and `hexo-theme-*` packages are loaded as themes rather than plugins. Hexo skips `@types/*` packages.

### 10.2 Installing a theme

=== "Via npm"

    ```bash
    npm install hexo-theme-<name> --save
    ```
    ```yaml
    # _config.yml
    theme: <name>
    ```

=== "Via git clone"

    ```bash
    git clone https://github.com/<author>/<theme>.git themes/<name>
    ```
    ```yaml
    # _config.yml
    theme: <name>
    ```

A theme placed in `themes/<name>/` takes priority over an installed `hexo-theme-<name>` package of the same name.

### 10.3 Site scripts

Any `.js` file you drop in a `scripts/` folder at your site root (or in your theme's `scripts/` folder) is loaded as a lightweight plugin. This is the quick way to register a custom helper or tag without publishing a package. (Details and the plugin API are in the Admin Guide.)

---

## 11. Troubleshooting

### Error: `Invalid config detected: "url" should be a valid URL!`

**Cause:** `url` in `_config.yml` is missing or not a valid `http`/`https` address.
**Solution:** Set `url: https://your-domain.com` (with the scheme).
**Prevention:** Always set `url` and `root` before your first build.

### Error: `Post not found: post_link <slug>`

**Cause:** A `{% post_link %}` or `{% post_path %}` tag references a post that doesn't exist.
**Solution:** Use the post's slug (its filename without `.md`) or its exact title.
**Prevention:** Run `hexo list post` to see valid slugs and paths.

### Warning: `No timezone setting detected!`

**Cause:** `timezone` is empty, so Hexo falls back to the machine timezone.
**Solution:** Set `timezone:` explicitly (e.g. `UTC` or `America/New_York`).
**Prevention:** Pick a timezone when you first configure the site for reproducible dates.

### Markdown isn't being rendered (raw `#` and `*` appear)

**Cause:** No Markdown renderer plugin is installed.
**Solution:** `npm install hexo-renderer-marked --save`, then `hexo clean && hexo generate`.
**Prevention:** Keep the renderer that `hexo init` installs; don't remove it.

### The blog index / archive / tag pages are missing

**Cause:** Hexo core only generates post, page, and asset routes. Listing pages need generator plugins.
**Solution:** Install `hexo-generator-index`, `hexo-generator-archive`, `hexo-generator-category`, `hexo-generator-tag` as needed.
**Prevention:** Install the generators your theme expects (its README usually lists them).

### Changes don't show up after editing

**Cause:** Stale cache or output.
**Solution:** Run `hexo clean` then `hexo generate` (or `hexo generate --force`).
**Prevention:** Use `hexo server` (which watches) or `hexo generate --watch` while writing.

### Error: `Category` / `Tag` has already existed!

**Cause:** A duplicate category or tag insertion (typically from a buggy plugin or corrupt `db.json`).
**Solution:** Run `hexo clean` to rebuild the database from source.
**Prevention:** Don't hand-edit `db.json`.

### `hexo server` reports an unknown command

**Cause:** The `hexo-server` plugin isn't installed in this site.
**Solution:** `npm install hexo-server --save`.
**Prevention:** Run `npm install` after `hexo init` so all scaffold dependencies are present.

### A plugin broke my build

**Cause:** A faulty plugin or `scripts/` file.
**Solution:** Run with `--safe` to load no plugins and confirm; then remove or update the offending package.
**Prevention:** Add plugins one at a time and rebuild after each.

### A draft won't appear in preview

**Cause:** Drafts are hidden by default.
**Solution:** Run `hexo server --draft`, or set `render_drafts: true`, or `hexo publish <name>` to promote it.
**Prevention:** Use `hexo publish` when a draft is ready.

### Future-dated posts are missing

**Cause:** `future: false` hides posts dated after "now".
**Solution:** Set `future: true` (the default) or correct the post date.
**Prevention:** Check the `date` in front-matter.

---

## 12. Frequently Asked Questions

**Q: Do I write posts in Markdown or HTML?**
Markdown by default (rendered by `hexo-renderer-marked`). You can also write HTML, or install other renderers (Pug, AsciiDoc, etc.). Raw HTML inside Markdown is passed through.

**Q: How do I change my site's URL structure?**
Edit `permalink` in `_config.yml` using the tokens in §7.2. Run `hexo clean && hexo generate` afterward.

**Q: Where do images go?**
Either in any folder under `source/` (e.g. `source/images/`) referenced by path, or — with `post_asset_folder: true` — in a folder next to each post, referenced with `{% asset_img %}`.

**Q: How do I preview before publishing?**
`hexo server` builds and serves locally with live reload. Add `--draft` to include drafts.

**Q: What's the difference between a post and a page?**
Posts live in `source/_posts/`, are dated, support tags/categories, and appear in listings. Pages (e.g. About) live elsewhere under `source/` and are standalone.

**Q: How do I add comments, search, or analytics?**
These are theme features or plugins. Check your theme's documentation and `_config.<theme>.yml` for the relevant options.

**Q: Can I use one config for development and another for production?**
Yes — `hexo generate --config _config.yml,_config.prod.yml` merges multiple files left to right into a `_multiconfig.yml`.

**Q: How do I move my drafts and posts between machines?**
Everything under `source/`, plus `_config.yml`, `package.json`, `scaffolds/`, and your theme, is your site. Commit them to Git. `public/` and `db.json` are regenerated and don't need to be tracked.

**Q: Why is my build slow on large sites?**
Generation is incremental and cached, but the first build of a big site reads and renders everything. Use `--concurrency` to tune parallelism, and avoid `--force` unless you need a clean rebuild.

**Q: How do I completely reset?**
`hexo clean` removes `db.json` and `public/`. Your source is untouched. Then `hexo generate` rebuilds from scratch.

**Q: Is there a server runtime in production?**
No. Hexo produces a static `public/` folder. `hexo server` is only for local preview — in production you serve the static files from any web host or CDN.

---

_Generated June 2026 from hexojs/hexo at d7a10f4. AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it. Unofficial; not affiliated with or reviewed by the project._
