Doks v1.9 is primarily a feature release that also includes security fixes, Netlify improvements, support for Hugo v0.156.0, and updated dependencies.

This guide will help you migrate from Doks v1.8 to Doks v1.9.

Clean dependencies

Delete the current lock file, .npmrc file, and dependencies installed to avoid conflicts.

npx shx rm -rf node_modules package-lock.json pnpm-lock.yaml yarn.lock bun.lock .npmrc

Update package.json

Replace the dependencies and devDependencies sections of your project’s package.json with the following dependencies, overrides, and devDependencies sections:

package.json
{
  "dependencies": {
    "@thulite/doks-core": "^1.9.3",
    "@tabler/icons": "^3.36.1",
    "@thulite/images": "^3.3.4",
    "@thulite/inline-svg": "^1.2.2",
    "@thulite/seo": "^2.4.3",
    "thulite": "^2.6.5"
  },
  "overrides": {
    "minimatch": "^10.2.2",
    "glob": "^13.0.6"
  },
  "devDependencies": {
    "@changesets/changelog-github": "^0.5.2",
    "@changesets/cli": "^2.29.8",
    "prettier": "^3.8.1",
    "vite": "^7.3.1"
  }
}

Install dependencies

Install the new dependencies.

Configure Doks

Update site configuration

Update config/_default/hugo.toml for the following changes:

hugo.toml
[outputs]
  home = ["html", "rss", "sitemap", "searchIndex", "llms"]
  page = ["html", "markdown"]
  section = ["html", "rss", "sitemap"]
  taxonomy = ["html", "rss", "sitemap"]
  term = ["html", "rss", "sitemap"]

[outputFormats.markdown]
  baseName = "index"
  isHTML = false
  isPlainText = true
  mediaType = "text/markdown"

[outputFormats.llms]
  baseName = "llms"
  isHTML = false
  isPlainText = true
  mediaType = "text/plain"

[caches]
  [caches.getresource]
    dir = ":cacheDir/:project"
    maxAge = -1 # "30m"

Update site parameters

Update config/_default/params.toml for the following changes:

params.toml
# Enable mathematical rendering on every page (unless you set the `math` parameter to `false` in front matter)
math = false # false (default) or true
mathEngine = "KaTeX" # "KaTeX" (default) or "MathJax"

# Doks (@thulite/doks-core)
[doks]
  # Navbar
  containerBreakpoint = "fluid" # "", "sm", "md", "lg", "xl", "xxl", or "fluid" (default)

  # Nav
  sectionSwitcher = false # true or false (default)
  sectionNav = ["docs"] # ["docs"] (default) or list of sections (e.g. ["docs", "guides"])

  # UX
  aiButtons = true # true (default) or false

# Inline SVG (@thulite/inline-svg)
[inline_svg]
  iconSetDir = "tabler-icons" # tabler-icons (default)
  iconSetVariant = "outline" # outline (default) or filled

# SEO (@thulite/seo)
[seo]
  [seo.description]
    summaryFallback = "" # "" (default)

Update module mounts

Update the layouts and assets sections in config/_default/module.toml:

Mounts
module.toml
# Module Configuration File
#
# This file configures Hugo module settings, particularly module mounts which
# define how content is organized within the project.
#
# Mounts specify file paths in your project that Hugo should use when building
# the site. They allow for custom directory structures and integrating content
# from different locations.

## content
[[mounts]]
  source = "content"
  target = "content"

## data
[[mounts]]
  source = "node_modules/@thulite/doks-core/data"
  target = "data"

[[mounts]]
  source = "data"
  target = "data"

## layouts
[[mounts]]
  source = "layouts"
  target = "layouts"

[[mounts]]
  files = ['! home.html']
  source = "node_modules/@thulite/doks-core/layouts"
  target = "layouts"

[[mounts]]
  source = "node_modules/@thulite/core/layouts"
  target = "layouts"

[[mounts]]
  source = "node_modules/@thulite/seo/layouts"
  target = "layouts"

[[mounts]]
  source = "node_modules/@thulite/images/layouts"
  target = "layouts"

[[mounts]]
  source = "node_modules/@thulite/inline-svg/layouts"
  target = "layouts"

## i18n
[[mounts]]
  source = "node_modules/@thulite/doks-core/i18n"
  target = "i18n"

[[mounts]]
  source = "i18n"
  target = "i18n"

## archetypes
[[mounts]]
  source = "node_modules/@thulite/doks-core/archetypes"
  target = "archetypes"

[[mounts]]
  source = "archetypes"
  target = "archetypes"

## assets
[[mounts]]
  source = "node_modules/@thulite/core/assets"
  target = "assets"

[[mounts]]
  source = "node_modules/@thulite/doks-core/assets"
  target = "assets"

[[mounts]]
  source = "node_modules/@tabler/icons/icons"
  target = "assets/svgs/tabler-icons"

[[mounts]]
  source = "node_modules/@thulite/images/assets"
  target = "assets"

[[mounts]]
  source = "hugo_stats.json"
  target = "assets/watching/hugo_stats.json"

[[mounts]]
  source = "assets"
  target = "assets"

## static
[[mounts]]
  source = "node_modules/@thulite/doks-core/static"
  target = "static"

[[mounts]]
  source = "static"
  target = "static"

Update PostCSS settings

Replace the (default) settings in config/postcss.config.js with:

PostCSS
postcss.config.js
import autoprefixer from 'autoprefixer';
import purgeCSSPlugin from '@fullhuman/postcss-purgecss';

const purgecss = purgeCSSPlugin({
    content: ['./hugo_stats.json'],
    defaultExtractor: (content) => {
        const els = JSON.parse(content).htmlElements;
        return [...(els.tags || []), ...(els.classes || []), ...(els.ids || [])];
    },
    dynamicAttributes: [
        'aria-expanded',
        'data-bs-popper',
        'data-bs-target',
        'data-bs-theme',
        'data-dark-mode',
        'data-global-alert',
        'data-pane', // tabs.js
        'data-popper-placement',
        'data-sizes',
        'data-toggle-tab', // tabs.js
        'id',
        'size',
        'type'
    ],
    safelist: [
        'active',
        'btn-clipboard', // clipboards.js
        'clipboard', // clipboards.js
        'disabled',
        'hidden',
        'modal-backdrop', // search-modal.js
        'selected', // search-modal.js
        'show',
        'img-fluid',
        'blur-up',
        'lazyload',
        'lazyloaded',
        'alert-link',
        'container-fw ',
        'container-lg',
        'container-fluid',
        'offcanvas-backdrop',
        'figcaption',
        'dt',
        'dd',
        'showing',
        'hiding',
        'page-item',
        'page-link',
        'not-content',
        'copy',
        'btn-copy',
    ]
});

export default {
  plugins: [
    autoprefixer(),
    ...(process.env.HUGO_ENVIRONMENT === "production" ? [purgecss] : []),
  ],
};

Update Netlify settings

If you’re using Netlify to deploy your site, update netlify.toml:

[build.environment]
  DART_SASS_VERSION = "1.97.3"
  GO_VERSION = "1.26.0"
  HUGO_VERSION = "0.156.0"
  NODE_VERSION = "24.13.1"
  NPM_VERSION = "11.8.0"
  TZ = "Europe/Amsterdam"

[build]
  publish = "public"
  command = """\
  git config core.quotepath false && \
  npm install && \
  hugo build --gc --minify --baseURL "${URL}"
  """

# Redirects and rewrites — https://docs.netlify.com/routing/redirects/#syntax-for-the-netlify-configuration-file
[[redirects]]
  from = "/*"
  to = "/404/"
  status = 404

WARN messages

Dart Sass

WARN  deprecated: css.Sass: libsass was deprecated in Hugo v0.153.0 and will be removed in a future release. Use dartsass instead. See https://gohugo.io/functions/css/sass/#dart-sass

Dart Sass support will be part of the next Doks release.

SEO descriptions

WARN  Description too short on page '/blog'. 0 characters is < 110
WARN  Description too short on page '/docs'. 0 characters is < 110
WARN  Description too short on page '/'. 0 characters is < 110

Update the descriptions in the front matter of your pages to the recommended SEO length of 110–160 characters.