On this page

Every URL change is a risk. Google has indexed the old URL, backlinks point to it, and users may have bookmarked it. Wire handles redirects automatically for merges and differentiations, but topic restructures and manual moves require deliberate planning. This guide covers every scenario.

The Golden Rule

Every old URL must resolve to the correct final destination in one hop. No chains (A to B to C), no dead ends (404), no soft redirects (everything pointing to the homepage).

Wire generates 301 redirects as both _redirects (Netlify/Cloudflare format) and HTML fallback pages with <meta http-equiv="refresh"> and <link rel="canonical">. All redirects live in .wire/redirects.yml.

Moving Pages (Topic Restructure)

When you reorganize a flat site into topic directories, every page gets a new URL:

/alte-seite/          → /ki-technologie/alte-seite/
/andere-seite/        → /dokumente/andere-seite/

The Right Order

Deduplicate before restructuring. This is the most common mistake. Run the full audit and deduplicate cycle while pages are still flat:

python -m wire.chief data
python -m wire.chief audit
python -m wire.chief deduplicate

Why this order matters:

  1. Fewer redirects. If you merge A into B first, then move B to its topic, you need one redirect (A to B's new location). If you move both first, then merge, you get a redirect chain: A's old URL to A's new URL to B's new URL. Wire flattens chains at build time, but avoiding them is cleaner.

  2. GSC data stays valid. Wire's overlap detection uses GSC keyword data stored by (topic, slug) pairs. When you move a page to a new topic, Wire registers it as a new page with no search history. The old data becomes orphaned. Running deduplication first means Wire makes merge/differentiate decisions with full keyword data.

  3. Cross-topic merges work but create cross-topic redirects. Wire allows merging pages across topics - the donor gets a redirect to the keeper's topic. But this means content moves between silos, which may not match your intended topic structure. Deduplicating first keeps the decision cleaner.

Setting Up Redirects

Add redirects to .wire/redirects.yml before moving files. Wire's add_redirect() function handles this, or you can edit the YAML directly:

- from: /alte-seite/
  to: /ki-technologie/alte-seite/
  reason: "topic restructure"
  date: "2026-03-13"

For large restructures (500+ pages), generate the redirects programmatically. Every old URL needs exactly one entry pointing to the new location.

After moving files:

python -m wire.chief sanitize   # Fix broken internal links
python -m wire.build            # Verify build + generate redirects

After Restructure

Migrate your existing GSC data to the new URL structure, then re-register pages:

python -m wire.chief migrate-gsc   # Rekey GSC data using .wire/redirects.yml
python -m wire.chief data           # Re-register pages + fetch fresh data

migrate-gsc reads .wire/redirects.yml and updates Content rows in the GSC database to match the new topic/slug/path. All keyword and snapshot history is preserved. If the new page already has some data (from a recent fetch), the old data is merged in.

For new URLs where Google hasn't transferred signals yet, Wire's GSC fetch automatically tries the old URL (via redirects) as a fallback. This means the audit sees data immediately after a restructure, not after waiting 2-4 weeks for Google to re-index.

Merging Pages

Wire's deduplicate command handles merges automatically. When two pages cannibalize each other (overlap ratio >0.4, traffic skew >0.7), Wire:

  1. Selects the stronger page as keeper (higher composite score from impressions, position, clicks, keyword count)
  2. Absorbs the donor's unique content into the keeper
  3. Archives the donor (index.md becomes index.md.archived)
  4. Creates a redirect from donor URL to keeper URL
  5. Registers the redirect in .wire/redirects.yml

The merge guard prevents content loss: if the merged output is less than 80% of the keeper's original body, Wire writes to .preview only and does not archive the donor.

Manual Merges

If you know two pages should be merged but Wire's thresholds don't trigger it (not enough shared keywords yet, or pages are in different topics):

  1. Manually combine the content into the keeper page
  2. Archive the donor: rename index.md to index.md.archived
  3. Add the redirect:
from wire.tools import add_redirect
add_redirect("/old-donor-path/", "/keeper-path/", reason="manual merge")

Or edit .wire/redirects.yml directly.

Deleting Pages

Wire does not have a delete command. Deletion is a manual decision with SEO consequences. Before deleting:

  1. Check GSC data. Does the page get any impressions? Even 10 impressions/month means Google values it. Consider merging instead.
  2. Check inbound links. Run python -m wire.chief audit and look for pages that link to the one you want to delete. Update those links first.
  3. Add a redirect. Point the deleted URL to the most relevant surviving page, not the homepage (that is a soft 404 in Google's eyes).
# .wire/redirects.yml
- from: /deleted-page/
  to: /relevant-surviving-page/
  reason: "page removed, content covered by surviving page"
  date: "2026-03-13"

If no relevant page exists, let it 404. A clean 404 is better than a misleading redirect.

Redirect Chains

A redirect chain is when URL A redirects to URL B, which redirects to URL C. Chains happen when:

  • A page is moved (restructure), then its new location is merged into another page
  • A page is merged, then the keeper is later moved to a different topic
  • Manual redirects are added without checking existing redirect targets

Wire Flattens Chains Automatically

At build time, generate_redirects() detects chains and flattens them. If .wire/redirects.yml contains:

- from: /a/
  to: /b/
- from: /b/
  to: /c/

Wire generates the output as:

/a/ /c/ 301
/b/ /c/ 301

The build log warns about every chain it flattens:

WARNING: Redirect chain flattened: /a/ → /b/ → /c/ (now /a/ → /c/)

RULE-61: Redirect Chain Lint

The build linter (RULE-61) also detects chains in the HTML output as a safety net. If a redirect HTML page points to another redirect HTML page, the linter flags it. This catches chains from manual HTML redirect pages that bypass .wire/redirects.yml.

Prevention

The best way to avoid chains is to follow the right order:

  1. Deduplicate (merge/differentiate) while pages are flat
  2. Restructure into topics
  3. Add redirects from old flat URLs to new topic URLs

If you must restructure first:

  • Wire's chain flattening handles it at build time
  • But the .wire/redirects.yml file keeps the intermediate entries, making it harder to audit later

Multi-Language URL Changes

For multi-language sites, each language has its own URL space:

/de/alte-seite/    → /de/ki-technologie/alte-seite/
/en/old-page/      → /en/ai-technology/old-page/

Restructure each language independently. German topics do not need to match English topics. Add redirects per language. The hreflang system handles cross-language linking automatically if pages declare their alternates in frontmatter.

Monitoring After URL Changes

After any URL change, monitor these signals over 2-4 weeks:

  1. Build linter. RULE-33 (broken internal links) and RULE-61 (redirect chains) catch issues immediately at build time.
  2. GSC data. Run python -m wire.chief data weekly. Watch for the new URLs appearing in search results and the old URLs dropping off.
  3. Audit. Run python -m wire.chief audit to check for new orphan pages (pages with no inbound links after restructure) and new cannibalization pairs.

The transition period is 2-6 weeks depending on crawl frequency. During this time, audit results will show limited data for moved pages. This is expected. Do not make additional URL changes during this period - let Google settle.

Quick Reference

Action Command Redirect? Who creates it?
Merge (auto) wire.chief deduplicate Yes Wire automatic
Merge (manual) Edit files + add_redirect() Yes You
Move to topic Move files + edit .wire/redirects.yml Yes You
Delete Remove file + edit .wire/redirects.yml Recommended You
Rename slug Move directory + edit .wire/redirects.yml Yes You
Change domain Update site_url in wire.yml Server-level Your server config

All redirects end up in .wire/redirects.yml and are generated as 301s at build time. Wire flattens chains automatically. The linter catches anything that slips through.