Migrate a Next.js App Router project from next-themes to ssr-themes. Use when replacing next-themes providers and hooks, removing mounted theme guards, and choosing between a minimal client-bootstrap migration and a maximal SSR-aware migration. Use when this capability is needed.
Install
npx skillscat add tomevault-io/tomes/migrate-next-themes Install via the SkillsCat registry.
Migrate next-themes to ssr-themes
Migrate the current project from next-themes tossr-themes in place.
Scope
- Support Next.js App Router projects only.
- Do not attempt Pages Router migrations.
- Preserve the project name, package name, app copy,
styling, and theme names unless a file specifically
mentionsnext-themesand needs wording updates. - Prefer the smallest correct set of edits.
Arguments
$0is the requested migration mode.- Valid modes are
minimalandmaximal.
If $0 is missing or invalid, ask exactly one focused
question before editing:
"Do you want the minimal or maximal migration?
Recommended: minimal. Minimal keeps the migration
simple with themeScript() and ThemeProvider only.
Maximal also reads the cookie on the server and usesregisterTheme() plus initial so theme-aware SSR
markup is correct on first render."
Do not make edits until the user answers that question.
Preflight
Before editing:
- Confirm the repo uses Next.js App Router by finding
anapp/directory and the current layout/provider
wiring. - Find all
next-themesimports and alluseTheme()
call sites. - Identify any mounted guards that exist only because
next-themestheme state is hydration-unsafe. - Inspect the current provider config and preserve its
theme behavior where possible:themesattributedefaultThemeenableSystemenableColorScheme- custom theme names
- theme value mapping
nonceandscriptProps- forced-theme behavior
If the project is Pages Router only, stop and explain
that this skill supports App Router only.
Core migration rules
- Remove
next-themesfrom dependencies and addssr-themes. - Create a shared
app/theme.tsfile when the app does
not already have one. - Use
createTheme(...)for shared config. - Use
bindTheme(theme)fromssr-themes/react. - Keep
suppressHydrationWarningon<html>when the migration
is not maximal, because the SSR markup will not be theme-aware
until the client script runs. - Preserve existing bootstrap script attributes such as
nonceanddata-*when replacing the old
provider-managed script with an explicit Next<Script>. - If the old app uses a forced theme, carry the same
forcedvalue through every runtime touchpoint that
affects first paint:<ThemeProvider forced={...}>themeScript({forced: ...})registerTheme(initial, {forced: ...})when using
maximal mode
- Remove temporary mounted placeholders only when they
were added solely to avoidnext-themeshydration
mismatches. - Use the project's existing package manager and script
conventions. - Do not introduce the advanced cache-friendly
proxy.tsplus route-variant pattern unless the user
explicitly asks for it.
Decision flow
Read these references before editing:
Then load exactly one implementation guide based on the
chosen mode:
minimal:
references/app-router-minimal.mdmaximal:
references/app-router-maximal.md
After editing, run the checks in
references/verification.md.
What to migrate
Apply the conversion in this order:
- Dependency replacement.
- Shared theme config.
- Layout/provider wiring.
- Client hook usage.
- Mounted-guard cleanup.
- Copy updates that still mention
next-themes. - Verification.
Behavior expectations
For minimal migrations:
- Use
themeScript()andThemeProvideronly. - Do not read cookies on the server.
- Do not call
registerTheme(). - Do not pass
initialtoThemeProvider. - If the route forces a theme, still pass
forcedto
boththemeScript(...)andThemeProvider.
For maximal migrations:
- Read the cookie on the server with
parseThemeCookie(). - Apply SSR html props with
registerTheme(...). - Pass the parsed state to
<ThemeProvider initial={...}>. - If the route forces a theme, also pass
forcedtoregisterTheme(...),themeScript(...), andThemeProvider. - Maximal mode keeps SSR and hydration aligned when a
valid theme cookie exists. First-time visits without a
theme cookie still rely onthemeScript()for early
client application.
Finish
When done:
- Summarize which mode was used.
- List the main files changed.
- Mention any remaining manual follow-up, if any.
Source: 0xcadams/ssr-themes — distributed by TomeVault.