Published July 17, 2026

Migrate to WingTip

Move an existing documentation repository to static output you can inspect, audit, and host anywhere.

Automated migration

If the source project uses a docs.json or mint.json configuration, run the importer:

pip install wingtip
wingtip migrate ./existing-docs --output ./wingtip-docs

The importer is strictly read-only — the source project is never modified. It writes a new WingTip project containing:

The importer is validated against real public hosted-docs repositories ranging from 46 to over 5,000 pages.

Then preview and iterate:

cd ./wingtip-docs && wingtip --serve

Broad MDX component compatibility and OpenAPI reference generation remain roadmap work; the report lists every affected page. The rest of this guide covers manual migration for repositories without a recognized configuration format.

What works today

WingTip currently supports:

What requires manual work

Plan for manual review when the source repository uses:

WingTip never silently discards unsupported content — the importer leaves unsupported markup in place and lists it in migration-report.md. Use the checklist below and request a migration review when compatibility is uncertain.

Migration process

1. Work on a branch

Keep the current documentation deployment unchanged while validating WingTip.

git switch -c wingtip-migration

2. Install WingTip

pip install "wingtip[serve]"

3. Prepare the source layout

Retain or create this minimal structure:

your-project/
├── README.md
├── docs/
│   ├── getting-started.md
│   ├── authentication.md
│   └── api.md
├── config.json
├── theme.json
└── favicon.png

Nested directories under docs/ are supported directly — nested paths are preserved in generated URLs, so existing structures can move as-is. Record every old and new URL before changing any filenames.

4. Add production metadata

Create config.json with the final public URL and project identity:

{
  "base_url": "https://docs.example.com",
  "project_name": "Acme Docs",
  "description": "Documentation for Acme developers.",
  "repo_url": "https://github.com/acme/docs",
  "github": {
    "repo": "acme/docs",
    "branch": "main"
  }
}

A local favicon.png is optional. WingTip does not insert its own branding when your project does not provide one.

5. Build and preview

wingtip --serve

Compare every source page with the preview. Pay particular attention to links, images, code examples, frontmatter, canonical URLs, noindex directives, and custom components.

6. Audit the output

When working from this repository, run the post-build auditor:

python audit_site.py --output docs/site --source .

The auditor checks required artifacts, missing local files, unexpected dependency CDNs, conditional PWA icons, and branding leaks.

7. Preserve URLs

Create a URL inventory before switching production traffic:

Existing URL WingTip URL Action
/getting-started /getting-started.html Redirect or preserve at the host
/guides/auth /authentication.html Add a permanent redirect

WingTip does not yet generate platform redirects. Configure permanent redirects at your static host and verify that each destination returns the intended page.

8. Validate before cutover

Confirm that:

Serving your migrated site

WingTip emits ordinary static files, so both common documentation topologies work. Pick one, set base_url to match, rebuild, and deploy docs/site/.

Topology A — dedicated docs domain (docs.example.com)

Set "base_url": "https://docs.example.com" and serve docs/site/ as the web root.

GitHub Pages / Netlify / Vercel / Cloudflare Pages: point the project at the docs/site output directory (or publish it from CI) and attach the custom domain in the host’s dashboard. No further configuration.

nginx:

server {
  server_name docs.example.com;
  root /var/www/docs-site;      # contents of docs/site/
  index index.html;
  error_page 404 /404.html;
}

Caddy:

docs.example.com {
  root * /var/www/docs-site
  file_server
  handle_errors {
    rewrite * /404.html
    file_server
  }
}

Topology B — subpath on the main domain (example.com/docs)

Set "base_url": "https://example.com/docs" — generated URLs, canonicals, feeds, and the service worker all carry the /docs prefix — then map that prefix to the static files on your main site’s proxy.

nginx (in the main site’s server block):

location /docs/ {
  alias /var/www/docs-site/;    # contents of docs/site/
  index index.html;
  try_files $uri $uri/ /docs/404.html;
}

Caddy:

example.com {
  handle_path /docs/* {
    root * /var/www/docs-site
    file_server
  }
  # ... your main site ...
}

Vercel (vercel.json on the main site):

{ "rewrites": [{ "source": "/docs/:path*", "destination": "https://your-docs-deployment.example/:path*" }] }

Netlify (_redirects on the main site):

/docs/* https://your-docs-deployment.example/:splat 200

The subpath topology is the one search engineers usually prefer: documentation authority accrues to the main domain rather than a subdomain. Both are fully supported — the demo site itself runs at a subpath (/WingTip-Static-Site-Generator/ on GitHub Pages), so every generated URL scheme is exercised there.

Request a migration review

If the repository is public, submit a migration review request. You will receive a structured compatibility assessment covering content, navigation, URLs, assets, metadata, and unsupported constructs.

Do not post private repositories, credentials, customer data, internal URLs, or proprietary content in a public issue. For a private project, provide a sanitized reproduction that preserves the relevant file structure and component patterns.

Migration guarantee

The current promise is transparency, not automatic parity: supported content should build reproducibly, and unsupported content should be identified before a production cutover. The planned importer will formalize this as both human-readable and JSON migration reports.