---
name: migrate-v4-to-v5
description: >-
Step-by-step procedure to migrate a project from clean-jsdoc-theme v4 to v5.
Use when a user wants to upgrade, migrate, or port their JSDoc config from
clean-jsdoc-theme v4 to v5 — moving options out of opts.theme_opts, renaming
options (base_url→basePath, title→siteName, sections→sectionOrder, custom
CSS/JS), handling removed options, reshaping the menu, and verifying the build.
---
# Migrate clean-jsdoc-theme v4 → v5
This skill walks a project from **clean-jsdoc-theme v4 to v5**. v5 is a ground-up
rewrite: it server-renders every page, emits a companion `.md` per page, ships
built-in search, a source viewer, and an `opts.docs` prose pipeline. The config
surface changed significantly — this is the procedure to port it safely.
> **Skill revision:** `2026-06-25`. The canonical, exhaustive reference is the
> repo's [`MIGRATION.md`](https://github.com/ankitskvmdam/clean-jsdoc-theme/blob/master/MIGRATION.md)
> and the machine-readable [`migration-map.json`](https://github.com/ankitskvmdam/clean-jsdoc-theme/blob/master/migration-map.json).
> If you can fetch them, prefer their current contents over anything cached here.
> For broader theme knowledge, pair this with the umbrella `clean-jsdoc-theme`
> skill. See [§7 Staying current](#7-staying-current).
## The one thing to know
**v4 nested theme options under `opts.theme_opts.*`. v5 reads them directly from
`opts.*` — there is no `theme_opts` block in v5.** Most options were also renamed
or removed. So migration is: lift options out of `theme_opts`, rename the few that
carry over, drop the rest, then optionally adopt v5's new features.
## 0. Before you start — compatibility
- **JSDoc** `>=4` (v4 allowed 3.x). **Node** `>=20`.
- The `plugins/markdown` plugin is **no longer required** by the theme (v5 renders
Markdown itself) — but it's harmless to keep, and you likely want it for other
reasons. (Note: the umbrella skill says JSDoc *needs* it; that's for fresh v5
setups where comment Markdown must be pre-rendered — verify against the user's
pipeline. Keeping it is safe.)
- Check the user really wants to move: to **stay on v4**, pin
`"clean-jsdoc-theme": "^4"`. v5 is now the npm `latest` (GA), so `@latest` pulls
it and an unpinned range will move to v5 on the next install.
## 1. Migration procedure
Work through these in order. Make the edits, don't just describe them — then build
and verify (§5).
Locate the JSDoc config (usually `jsdoc.json` or a `conf.json`; sometimes inline
in `package.json`). Confirm it's v4 by the presence of an `opts.theme_opts` block
and/or `"clean-jsdoc-theme": "^4"` in `package.json`. Note every key under
`theme_opts` — that's your migration work-list.
```sh
npm i -D clean-jsdoc-theme@latest # v5 is the current `latest`
```
Keep `template` pointing at `node_modules/clean-jsdoc-theme` (in v5 you may point
at `node_modules/clean-jsdoc-theme/dist`; the package `main` resolves either way).
Move every `opts.theme_opts.*` key up to `opts.*`, applying the rename/removal
table in [§2](#2-option-mapping). Then **delete the now-empty `theme_opts`
block**. Renames that carry over:
- `base_url` → `basePath`
- `title` → `siteName`
- `sections` → `sectionOrder`
- `create_style` → `customCss`, `include_css` / `add_style_path` → `customCssFile`
- `add_scripts` → `customJs`, `include_js` / `add_script_path` → `customJsFile`
v4 entry `{ title, link, target, class, id }` → v5 entry
`{ id?, title?, link (or href)?, icon? }`. Drop `target` and `class`; add `icon`
(`lucide:` or `simpleicons:`) if you like. In v5, `id` also selects
built-ins (`{ id: "home" }`, `{ id: "source" }`), and a `menu` **takes precedence
over `sectionOrder`** and owns the whole top region of the sidebar.
Delete options with no v5 equivalent and tell the user what replaced them
([§3](#3-removed-features)): `default_theme`, `homepageTitle`,
`includeFilesListInHomepage`, `search`, `static_dir`,
`exclude_inherited`, `displayModuleHeader`, `sort`.
(`footer`, `meta`, `codepen`, `favicon`, and `shouldRemoveScrollbarStyle` are
**not** removed in v5 — map them, see [§2](#2-option-mapping);
`shouldRemoveScrollbarStyle` → `scrollbar: "native"`.) Most are now automatic
(search is always on; light/dark is a runtime toggle) or moved to JSDoc's own
config (`static_dir`).
Migration doesn't require these, but they're the reason to be on v5 — offer them
(see the umbrella skill for syntax): `docs` + `docGroups` (a prose-guides
directory beside the API), `fonts`, `siteName` logo sets, `copyPage` / `aiPrompt`
(LLM actions), `@category` / `@order` for sidebar structure, `@iframe` embeds +
`@playground` runnable examples (CodePen/JSFiddle/CodeSandbox — the generalized
successor to v4's `codepen`), `favicon`, and the source viewer
(`templates.default.outputSourceFiles`).
## 2. Option mapping
`opts.theme_opts.` → `opts.`. Status: `renamed | changed | removed`.
| v4 (`theme_opts.*`) | v5 (`opts.*`) | Status | Note |
| --- | --- | --- | --- |
| `default_theme` | — | removed | Light/dark token sets + runtime toggle; no picker. |
| `base_url` | `basePath` | renamed | Site root prefixed onto links. Default `/`. |
| `favicon` | `favicon` | kept | A file path; theme copies it + emits `` (needed for SVG). |
| `homepageTitle` | — | removed | Home `` derives from README/`docs/index.md` + `siteName`. |
| `title` | `siteName` | changed | String **or** logo set `{ default, dark, light, alt }`. |
| `includeFilesListInHomepage` | — | removed | The Source Files section lists files instead. |
| `menu` | `menu` | changed | Reshaped (see step 4); `target`/`class` dropped, `icon` added. |
| `sections` | `sectionOrder` | renamed | Filter + order sidebar sections. |
| `meta` | `meta` | changed | Supported again — array of attribute maps → `` tags in `` (same shape as v4). |
| `search` | — | removed | Always-on fuzzy search. |
| `codepen` | `playground` | changed | v4 prefilled a CodePen from `@example`; v5 generalizes it to `opts.playground` + the `@playground` tag (CodePen/JSFiddle/CodeSandbox). For an existing pen by URL, use `@iframe`. |
| `static_dir` | — | removed | Use JSDoc's own static-file config. |
| `create_style` | `customCss` | renamed | Inline CSS, injected after the theme stylesheet. |
| `include_css` | `customCssFile` | renamed | CSS file(s); copied to a content-hashed `_assets/` link. |
| `add_style_path` | `customCssFile` | changed | Was an external ``; now read + emitted as a cached asset. |
| `add_scripts` | `customJs` | renamed | Inline JS, runs last (before ``). |
| `include_js` | `customJsFile` | renamed | JS file(s); copied to a content-hashed `_assets/` reference. |
| `add_script_path` | `customJsFile` | changed | Was an external `