Migration
Pre-v0.11.0 projects used a flat-shape refrakt.config.json with site fields at the top level. v0.11.0 introduced a nested form (site or sites) that supports multi-site repos and centralizes plugins/plan/site configuration.
The flat shape continues to work indefinitely. You don't have to migrate. The unified loader normalizes flat configs to sites.default internally, mirroring the top-level fields for backwards compatibility. Existing single-site projects keep building without changes.
When to migrate
You should migrate when one of these is true:
- You want to add a second site to your repo (multi-site requires the
sitesform). - You want to declare an explicit
pluginsarray. - You want a
plansection alongside your site config. - You prefer the cleaner nested shape for new projects.
The migrate command
refrakt config migrate rewrites the config file in place. By default it's a dry run — it prints a diff and exits without writing.
# Preview the changes
npx refrakt config migrate
# Write the changes
npx refrakt config migrate --apply
The migrate command rewrites the flat shape into the singular site form — here's what a typical flat → nested migration looks like:
{ "contentDir": "./content", "theme": "@refrakt-md/lumina", "target": "svelte", "packages": ["@refrakt-md/marketing"] }
{ "site": { "contentDir": "./content", "theme": "@refrakt-md/lumina", "target": "svelte", "packages": ["@refrakt-md/marketing"] }}
JSON indent style is sniffed from the original file before re-serializing, so tab-indented configs stay tab-indented.
Targets
--to <shape> selects the migration target:
| Target | Effect | Example |
|---|---|---|
nested (default) | Flat → singular site. | refrakt config migrate --apply |
multi-site | Singular site → sites.<name>. Requires --name <name>. | refrakt config migrate --to multi-site --name main --apply |
Two-step path: flat → singular → multi-site
If your config is in flat shape and you want to end up multi-site, run the command twice:
# Step 1: flat → singular
npx refrakt config migrate --apply
# Step 2: singular → multi-site
npx refrakt config migrate --to multi-site --name main --apply
--to multi-site refuses to run on flat-shape configs (it can't know what site name you'd want), which is why the two-step path is necessary.
Auto-populating plugins
On flat → nested migration, refrakt config migrate auto-populates the top-level plugins field from discoverPlugins() if absent. This gives you a working plugin list immediately without remembering which packages contribute commands. Discovery failures are non-blocking.
Idempotency
Running migrate on an already-migrated config is a no-op:
$ npx refrakt config migrate
No changes needed — refrakt.config.json is already in the requested shape.
Safe to re-run in CI or after partial edits.
Conflict refusal
If your config somehow ends up with both site and sites declared, the migrate command refuses to run:
Error: refrakt.config.json declares both "site" and "sites". Resolve the conflict before migrating.
Pick one and remove the other before re-running.
After migration
Once you've migrated, update your build entry points to use the new shape:
- SvelteKit: pass
site: 'default'(or your custom name) in therefrakt({...})plugin options invite.config.ts. Single-site projects can omit it. - Astro / Nuxt / Next / Eleventy: same pattern — accept a
siteoption that picks an entry from the config'ssitesmap. refrakt.config.jsonlocation: the configPath defaults to./refrakt.config.jsonnext to the build's working directory. Multi-app monorepos can passconfigPath: '../refrakt.config.json'to point at a shared root config.
See Sites for the full per-adapter wiring.