Workflow · Migrations
Migrate an existing site to Nift.
nift init --migration creates a normal Nift project plus an agent-ready migration playbook. Nift provides the rails; the agent (or you) understands the source framework. Parity comes before cleanup.
Which mode should I use?
| Intent | Implementation | Design | Behaviour/content/routes |
|---|---|---|---|
| Migration | Preserve intent where practical | Preserve | Strict parity; differences need approval |
| Rewrite (experimental) | Replace freely | Preserve | Strict product/design/behaviour parity |
| Redesign (experimental) | Replace freely | Replace deliberately | Protect explicit requirements/content/capabilities; approve route decisions |
Maximum faithful parity: migration. Same product and design with new implementation: rewrite. New design direction based on existing requirements and content: redesign. These intents are independent of authored, rendered or hybrid source models.
nift init --migration Then give the working copy to a coding agent - or ask the agent to run that command itself - and follow the generated playbook.Run it yourself, or let your agent run it
Either workflow is valid:
# You run it, then hand the project to an agent:
cd <migration-project>
nift init --migration
Or give the agent the repository and let it initialize in its own environment:
> Run `nift init --migration` in this project.
> Read MIGRATION.md, HANDOVER.md and the Nift section of AGENTS.md, then migrate the site to Nift.
> Preserve route, content and behavioural parity, work through the migration checkpoints,
> keep HANDOVER.md current, and stop/report if the migration appears to require a change
> to Nift itself. Interactive islands and client frameworks
Nift can own site generation while pages load independently prepared React, Vue, Svelte or Solid islands, Web Components, vanilla JavaScript controllers, or other browser-side bundles. Framework islands are valid Nift architecture; migration does not require deleting interactive framework code. Nift does not directly compile these frameworks: keep their external bundle preparation in the production pipeline.
Faithful human-and-agent migrations may retain existing islands for the safest parity path. Agent-primary migrations may prefer vanilla HTML/CSS/JS where practical, while framework islands remain available for complex shared state or interactions where they are the cleaner choice. Choose by parity, maintainability, accessibility, bundle/runtime cost, source model and compatibility risk, and record significant decisions in migration evidence and STATUS.
What Nift creates
MIGRATION.md- the migration playbook, baseline/freeze rules and parity gates.HANDOVER.md- current progress, decisions, blockers and the exact next action.README.md- a concise operational entry point (status, upstream reference, source model, build/validation commands, document locations).AGENTS.md- project-local instructions for coding agents; Nift safely manages only its own marked section.investigation/STATUS.md- resumable checkpoint ledger, architecture decisions and the parity/performance/revalidation/benchmark gates.investigation/BASELINE.md- upstream reference, source model, complete production pipeline and frozen reference.investigation/EXTERNAL-INPUTS.md- external/generated inputs a Git SHA alone does not capture.investigation/KNOWN-DIVERGENCES.md- divergence ledger (inherited upstream vs migration regression).investigation/PARITY-CONTRACT.md- what parity means for this migration.investigation/- evidence, reproductions, route inventories, benchmarks and compatibility work.
How the migration works
- Baseline - reproduce the source revision and build before changing anything.
- Inventory - content, routes, layouts, components, shortcodes, assets, data, frontmatter, redirects.
- Parity fixtures - route/generated-file inventories and a known-divergence ledger.
- Compatibility proof - validate representative routes and interactions, including island/bundle architecture, before broad translation.
- Migrate - shared shells/templates first, then authored content with reconciled counts.
- Verify - route/file/content and browser/behaviour parity, plus incremental-vs-full equivalence.
- Performance campaign - profile the complete production pipeline, improve general bottlenecks and record justified deferrals.
- Revalidate - rerun the complete parity contract after optimization.
- Final benchmarks - measure the optimized, parity-certified production pipeline, including required compatibility and bundle stages.
- Clean checkout - a fresh clone must build without hidden local state.
- Handover - exact revisions, known divergences, remaining work and a maintenance recommendation.
Existing MIGRATION.md/HANDOVER.md files are never silently overwritten: the default policy stops with a list of conflicts, and --migration-existing=keep, append, or replace make the behaviour explicit. A pre-existing README.md is kept (not a conflict), so the default run never clobbers your project readme.
Parity-first migration
Preserve route, content and behavioural parity unless divergence is explicitly approved, and maintain an explicit known-divergence list. A faithful migration may initially retain architectural baggage from the source generator; do not clean up too early, and prefer faithful compatibility over speculative rewrites.
Route preservation
Route preservation is a first-class migration invariant. Compare the authoritative route set, detect missing and extra routes, preserve redirect behaviour, and account for generated/index routes.
Foreign compatibility stages
Migration does not require Nift to reproduce every source generator’s semantics natively. External renderers and adapters are legitimate when parity requires them - for example Goldmark, Chroma, an MDX rendering stage, or source-specific shortcode adapters - without being bundled by Nift.
Dependency correctness
Imported includes, assets, data, shared templates, and generated dependencies must become correct Nift dependencies where appropriate.
Incremental correctness
Verify single-page edits, shared-template edits, asset/data changes, and targeted builds, plus incremental-vs-full equivalence. A migration that only passes a full clean build is insufficient evidence.
Verification
Use route checks, file-set checks, content checks, browser checks, and keyboard/runtime checks where relevant. No migration is complete while unexplained differences remain.
Performance campaign before final benchmarks
After the complete corpus and behaviour pass parity, profile the full production-equivalent pipeline and locate actual time/RSS hotspots: compatibility stages, repeated parsing/conversion/evaluation, transformations, client bundles, indexes, dependencies, filesystem work and external tools. Make general, maintainable, semantics-preserving improvements, recheck relevant parity after each meaningful change, then rerun the complete parity contract before final benchmarks.
Record profiles, changes, before/after evidence, tradeoffs and deliberately deferred bottlenecks. Do not special-case benchmark inputs, change the corpus, weaken parity, hide required stages or time a cheaper workflow. Defer disproportionate architectural rewrites rather than destabilizing a complete migration.
Benchmarking
Measure fairly on the same machine with the same corpus: the source build, Nift full/warm/targeted builds where relevant, and peak RSS. Separate and report compatibility-stage renderer cost honestly.
Clean clone
A migration is not finished until a fresh checkout builds and passes parity checks without hidden local state or absolute developer-machine paths.
Handover
MIGRATION.md holds methodology and parity requirements; HANDOVER.md holds current operational state and the exact next action; README.md is a concise entry point; AGENTS.md merges Nift’s managed migration block into project instructions; and investigation/ holds the resumable status ledger, baseline, external-input inventory, divergence ledger and parity contract.
When Nift itself seems to need a change
If a migration exposes a gap that looks like Nift core, stop and isolate the requirement with a narrow reproduction. Do not casually modify Nift core from inside the site migration; report the requirement separately.
What comes after migration
A faithful migration achieves source parity first. Once the constraints are understood, a later native-Nift evolution can simplify the architecture - but keep a compatibility stage until parity is proven and the simplification is explicitly authorized.
The canonical MIGRATION.md
nift init --migration writes this file to the project root, byte-for-byte:
The canonical MIGRATION.md
# MIGRATION.md
A migration workbook for converting an existing site to Nift.
This project was created with `nift init --migration`: a normal Nift project
with an agent-ready migration playbook. It is **not** an automatic converter.
Nift provides the rails; the human or coding agent understands the source
framework. Parity comes before cleanup.
Read this file first. Then read `investigation/STATUS.md` for where the
migration actually is, and `HANDOVER.md` for the current operational state.
`AGENTS.md` (created or augmented by init) points agents here.
## Choose the transformation intent
Migration is a faithful port: preserve the product, visual design, routes,
content and behaviour, and implementation intent where practical. Differences
are regressions unless explicitly approved.
For the same product/design with a freely replaced implementation, use the
experimental v4.8 `nift init --rewrite` and `REWRITE.md`. For deliberately new
UX/design under an explicit requirements/content/capability contract, use
experimental `nift init --redesign` and `REDESIGN.md`. Do not silently switch
intent. Authored/rendered/hybrid source models are independent choices.
## Operating contract
These rules are the migration contract. Do not violate them without explicit
authorization.
- Preserve route, content and behavioural parity unless divergence is
explicitly approved.
- Do not modify Nift itself to solve source-project compatibility problems
without stopping and reporting the requirement first.
- Commit at meaningful migration checkpoints.
- Maintain the known-divergence ledger (`investigation/KNOWN-DIVERGENCES.md`).
- Do not classify the migration as complete while unexplained differences
remain.
- Prefer faithful compatibility stages over speculative rewrites.
- Do not optimize or redesign before the faithful baseline is established.
- Do not destroy the upstream/reference implementation while it is still
needed for comparison.
- Record exact source, toolchain and external-input revisions.
- Keep `HANDOVER.md` and `investigation/STATUS.md` current after meaningful
checkpoints.
## Scaffold is not migration
Initialization has already created a normal Nift project (starter `content/`,
`templates/`, output directory, `AGENTS.md` managed block, `MIGRATION.md`,
`HANDOVER.md`, `README.md` and `investigation/`). That is **scaffold creation**,
not migration implementation.
The initial Nift scaffold is **placeholder material**. Do not include it in
parity counts, route inventories, file counts or benchmark claims. Replace or
retire it during architecture proof once the migrated publication structure is
established.
Do not begin translating or modifying upstream site content until the upstream
source, the complete production build and the parity baseline have been
established and frozen. An initialized project is allowed to exist before that
baseline work; that does not relax the rule against migrating before the
baseline is reproducible.
## Workflow
### Phase 1 - Understand the source project and freeze the baseline
Establish and record in `investigation/BASELINE.md`:
- source framework/generator and version;
- upstream repository and exact source revision/commit;
- **source model** (see below);
- source build command (and development command where relevant);
- the **complete production-equivalent pipeline** (see below);
- deployment architecture;
- authored content inventory;
- templates/layouts inventory;
- components/shortcodes/render hooks inventory;
- static asset inventory;
- generated/index/listing pages;
- redirects;
- data files and schemas/taxonomies/frontmatter conventions;
- special rendering behaviour;
- the authoritative route set;
- upstream build time and peak memory.
Complete the external/generated-input inventory
(`investigation/EXTERNAL-INPUTS.md`): a pinned Git SHA does **not**
necessarily define the complete production input set.
Invariant: **DO NOT START MIGRATION UNTIL THE COMPLETE SOURCE BASELINE CAN BE
REPRODUCED AND FROZEN.**
#### Source model
Record which maintained-source model this migration uses, in
`investigation/BASELINE.md`:
- `authored` - human + agent oriented; preserve Markdown/MDX/frontmatter
structured authored sources where appropriate;
- `rendered` - agent-primary; maintain rendered HTML/CSS/JS with explicit
metadata/navigation where that is the chosen architecture;
- `hybrid` - describe explicitly.
Publication/behaviour parity does **not** require different maintained-source
architectures to preserve identical source semantics. An authored-source
migration and an agent-primary rendered-source migration can both be valid.
#### Interactive islands and client frameworks
A Nift migration does not require static HTML only or removing React, Vue,
Svelte, Solid, Web Components or other client-side framework code. Nift owns
site generation and the build layer; generated pages may load and mount
independently prepared browser-side islands or bundles. Nift does not itself
compile those frameworks: preserve or configure the appropriate external
bundle preparation as part of the production pipeline.
Valid choices include React, Vue, Svelte and Solid islands, Web Components,
vanilla JavaScript controllers, and other browser-side bundles required by the
source application. The presence of framework islands does not make the site
"not Nift".
Use the smallest architecture that preserves required behaviour. Faithful
human + agent migrations may retain existing islands where that is the safest
and most maintainable parity path. Agent-primary migrations may prefer vanilla
HTML/CSS/JS where practical, while framework islands remain available for
complex/shared client state or interactions where they are the cleaner solution.
Choose based on behavioural parity, maintainability, accessibility, runtime and
bundle cost, shared client state, the selected source model, and compatibility
risk. Record significant retained or introduced islands, their preparation and
mounting paths, and the reasons for the choice in architecture evidence and
`investigation/STATUS.md` before broad implementation.
#### Complete production pipeline
A successful upstream build does **not** necessarily mean the complete
production publication was reproduced. Identify and record the full set of
production steps before freezing the reference, for example: build, search
indexing, post-processing, API/reference generation, download/export
generation, asset processing, deployment transforms, and registry-generated
data. Some pipelines require multi-stage execution (for example a build, then
a search-index generation, then a build that consumes the search-derived
output). Freeze the **reference publication** under an immutable path, kept
visually and semantically distinct from the Nift migration output so the
migration can never silently compare its output against itself.
#### Upstream nondeterminism classification
Classify the frozen reference:
- `byte deterministic`;
- `semantic deterministic`;
- `nondeterministic but bounded/understood`;
- `unresolved`.
Do not demand byte identity where upstream itself cannot reproduce
byte-identical output. Instead: reproduce upstream, characterize its
nondeterminism, freeze the accepted reference, document the classification,
and compare Nift against that accepted reference using the appropriate parity
rule.
### Phase 2 - Define the parity contract and fixtures
Record the migration-specific parity contract in
`investigation/PARITY-CONTRACT.md` (what "parity" means here: route parity,
generated-file parity, content parity, browser/visual parity where relevant,
runtime/interactive behaviour, keyboard/accessibility behaviour where
relevant, redirects, search/indexing, downloads/exports, allowed divergences,
byte-versus-semantic equality).
Build appropriate reference evidence before broad migration. Use proportional
fixtures; do not mandate browser testing where it is irrelevant. Candidate
fixtures:
- route inventory;
- generated-file inventory;
- representative browser captures;
- content checks;
- navigation checks;
- keyboard/runtime behaviour where relevant;
- mobile/desktop viewport coverage;
- the known-divergence ledger (`investigation/KNOWN-DIVERGENCES.md`).
Maintain progress in `investigation/STATUS.md`, which is the resumable
checkpoint ledger for the migration.
### Phase 3 - Establish the initial Nift structure and compatibility proof
Set up:
- project initialization;
- tracking;
- source/output layout;
- templates;
- dependencies;
- schemas/taxonomies where appropriate;
- migration checkpoint structure.
Prove the chosen architecture with representative routes and interactions,
including retained or introduced islands and compatibility stages, before broad
content translation. Do not prematurely redesign the source architecture. Treat
the starter scaffold as placeholder and replace it here.
### Phase 4 - Migrate shared shells/templates first
Identify and recover the largest common structure first:
- common page shells;
- shared heads;
- headers/footers/navigation;
- layouts;
- repeated structural components.
### Phase 5 - Migrate authored content
Reconcile explicit corpus accounting (excluding placeholder scaffold):
- expected authored inputs;
- converted inputs;
- remaining inputs;
- generated/listing layouts;
- route counts.
Counts must be reconciled rather than guessed.
### Phase 6 - Source-specific compatibility
**MIGRATION SUPPORT DOES NOT MEAN NIFT MUST NATIVELY REIMPLEMENT EVERY SOURCE
GENERATOR'S SEMANTICS.** Faithful compatibility stages are legitimate. For
example, a Hugo source may require Goldmark or Chroma, MDX may use an
external/package rendering stage, and special shortcodes may need adapters.
Rule: **Prefer faithful compatibility over semantic rewrites unless the
migration goal explicitly permits behavioural changes.** And: **DO NOT MODIFY
NIFT CORE TO SOLVE A SOURCE-PROJECT COMPATIBILITY GAP WITHOUT STOPPING AND
REPORTING THE REQUIREMENT FIRST.**
### Phase 7 - Route/content/rendered parity
Require:
- an authoritative route-set comparison;
- missing and extra route detection;
- generated-file-set comparison where meaningful;
- content/render parity checks;
- browser, interactive behaviour and keyboard/accessibility checks where relevant;
- explicit divergence classification in
`investigation/KNOWN-DIVERGENCES.md`.
No migration is complete while unexplained differences remain. Record whether
each difference is inherited upstream behaviour or a migration regression.
### Phase 8 - Incremental correctness
Verify, as appropriate for the project:
- single-page edits;
- shared-template edits;
- asset changes;
- data changes;
- dependencies;
- targeted builds;
- incremental-vs-full equivalence.
A migration that only passes a full clean build is insufficient evidence.
### Phase 9 - Performance campaign
A parity-complete migration is not automatically performance-final. Once the
complete corpus, behavioural parity and incremental correctness are proved,
perform a focused performance campaign before recording final benchmarks:
complete migration -> prove parity -> profile -> optimize general bottlenecks
-> re-prove parity -> benchmark the finished migration
Profile before optimizing. Measure the complete production-equivalent workflow
and locate actual time and memory/RSS hotspots. Depending on the project, inspect:
- Nift build/evaluation overhead, templates and shared rendering paths;
- compatibility adapters and Markdown/MDX or other transformation stages;
- client-bundle preparation and generated indexes/search data;
- repeated parsing, conversion or evaluation;
- dependency discovery, filesystem work and external process/tool invocation;
- large object/map/collection operations, avoidable repeated work and RSS hotspots.
Prioritize general, semantics-preserving improvements supported by profiles,
useful to production builds and maintainable after handover. Rerun relevant
correctness/parity gates after every meaningful optimization. This phase does
not authorize changes to Nift core without the existing stop-and-report review.
Do not add benchmark-specific special cases, change the workload/content corpus,
weaken parity, remove or hide required production stages, exclude compatibility
costs still needed in production, or time a cheaper workflow than users run.
Record profiles/hotspots, changes made, useful before/after measurements,
deliberately deferred bottlenecks and any tradeoffs in migration evidence and
`investigation/STATUS.md`. If remaining cost requires a disproportionate
architectural rewrite, document and defer it rather than destabilizing the
migration. A measured decision to defer can complete the campaign; an
uninvestigated first parity pass cannot.
### Phase 10 - Final parity revalidation
Rerun the complete parity contract after the performance campaign, including
browser/behaviour checks and incremental/full equivalence where applicable.
Resolve or explicitly classify divergences. Record the tested revision and
commands in `investigation/STATUS.md` before proceeding to final benchmarks.
### Phase 11 - Final benchmark campaign
Benchmark the optimized, parity-certified final migration, not the first
implementation that happened to reach parity. Keep exploratory campaign
measurements separate from final benchmark results.
Measure the **complete production-equivalent pipeline**, not only `nift
build`. Where practical, take five serialized samples and report median with
range, and distinguish:
- warm full;
- fresh / application-cold;
- changed-input.
Record proportionally:
- source baseline build time;
- Nift clean/full build time;
- warm/full and targeted/single-page builds where useful;
- peak RSS (per-process/phase, which is not aggregate simultaneous pipeline
RSS);
- environment/hardware;
- measurement methodology.
Disclose explicitly: whether prepared dependencies/binaries are inside or
outside the timed interval, that OS caches are uncontrolled unless
deliberately controlled, that search/indexing/post-processing costs stay
visible, and that a production build is not a dev-server hot reload. Do not
cherry-pick. Do not hide compatibility-stage cost. If an external renderer
exists, measure and report its cost separately where useful.
### Phase 12 - Clean-checkout verification
Before completion verify on a fresh checkout:
- fresh clone;
- dependency acquisition;
- build from scratch;
- route/content checks;
- no reliance on untracked local state;
- no absolute developer-machine paths.
### Phase 13 - Handover / final report
Produce a final report containing at least:
- source revision and source model;
- migration revision;
- external-input inventory summary;
- route counts;
- content counts;
- known divergences;
- compatibility stages;
- build measurements;
- memory measurements;
- clean-checkout result;
- remaining work;
- maintenance recommendation.
## Rerun behaviour
Running `nift init --migration` inside an already-initialized Nift project
refuses rather than destructively recreating the project. Existing generated
guidance (README, `investigation/`) is preserved by default; canonical
`MIGRATION.md`/`HANDOVER.md` follow the `--migration-existing` policy
(`error` default, `keep`, `append`, `replace`). A future `--refresh-guidance`
mode is a possible roadmap item, not current behaviour.
## Document roles
- `MIGRATION.md` - methodology, baseline, migration plan, parity
requirements, checkpoints, migration-specific evidence/state.
- `HANDOVER.md` - current operational state, completed work, current blocker,
exact commands, important decisions, exact next action.
- `README.md` - concise operational entry point (status, upstream reference,
source model, build command, validation command, document locations).
- `AGENTS.md` - project instructions (Nift's migration block is managed and
safe to augment).
- `investigation/STATUS.md` - resumable checkpoint ledger (where the migration
is, gates, next checkpoint).
- `investigation/BASELINE.md` - upstream reference, source model, complete
production pipeline, frozen reference.
- `investigation/EXTERNAL-INPUTS.md` - external/generated build inputs that a
Git SHA alone does not capture.
- `investigation/KNOWN-DIVERGENCES.md` - divergence ledger (inherited upstream
versus migration regression).
- `investigation/PARITY-CONTRACT.md` - migration-specific parity definition.
- `investigation/` - baseline evidence, reproductions, audit notes, route
inventories, browser-matrix metadata, benchmark data, compatibility findings.
## What comes after migration
A faithful migration achieves source parity first. Once the constraints are
understood, a subsequent native-Nift evolution may simplify the architecture -
but do not strip away a compatibility stage until parity is proven and the
simplification is explicitly authorized.
You do not have to migrate everything at once
If you are keeping an existing site and want a lighter first step, you can also add Nift without a full migration. Keep the site’s HTML, CSS, JavaScript, assets and runtime architecture, and use Nift to extract repeated structure - shared heads, headers/footers/navigation, and repeated structural components - into templates and a fast tracked build layer.
index.html
about.html
services.html
work.html
contact.html
Every page repeats:
<!doctype html>
<head>...</head>
header / navigation
footer
CSS / JS references Extract the repetition, use @content/@input/@path to compose it, and keep the parts that are already working. This incremental-adoption path does not require a rewrite and does not translate the site into a different component model.