Skip to Content

Redirect mapping

StagingRedirect is the simplest staging shape — two fields. Every output row creates a Shopify URL redirect.

Quick reference — minimum loadable redirect

{ "original_id": $string(redirect_id), "path": "/" & url_key & ".html", "target": "/products/" & handle }

The two fields

pathstringrequired

The source path — where the customer lands. Must start with / and be relative to the destination shop’s domain.

"path": "/" & old_url_key & ".html"
targetstringrequired

The destination path or full URL. Two flavors:

  • Relative path on the same shop: /products/the-new-handle
  • Absolute URL to anywhere: https://help.example.com/migrated
"target": "/products/" & $lowercase(handle)

Patterns

Source product URL → Shopify product handle

{ "original_id": $string(product_id), "path": "/" & url_key & ".html", "target": "/products/" & $lowercase(url_key) }

Source category URL → Shopify collection

{ "original_id": $string(category_id), "path": category_url_path, "target": "/collections/" & collection_handle }

Source CMS page → Shopify page

{ "original_id": $string(page_id), "path": "/" & identifier, "target": "/pages/" & identifier }

Drop identity redirects

If your source URL and Shopify URL happen to match, don’t create a self-loop:

$lowercase(url_key) != handle ? { "original_id": $string(product_id), "path": "/" & url_key, "target": "/products/" & handle } : null

Returning null from a mapping skips the row — no redirect created.

External redirects (discontinued products → manufacturer)

{ "original_id": $string(product_id), "path": "/discontinued/" & old_slug, "target": "https://manufacturer.example.com/" & $lowercase(name) }

Bulk redirects from a sitemap dump

If you’ve extracted the source’s sitemap into a flat list of URLs, use source_url_path from the product/collection/article migrations as the source side:

{ "original_id": $string(product_id), "path": source_url_path, "target": "/products/" & handle }

This is the cleanest pattern — every product/collection/article already carries its source_url_path from extract; the redirect mapping just turns those into redirect rows.

Gotchas

Run product / collection / article loads first. The target paths typically reference Shopify handles created by those loads. Loading redirects against missing targets produces 404 chains.

  • path must start with /. Without the leading slash the redirect is rejected.
  • path and target can’t be equal — Shopify rejects self-loops. Use the conditional null pattern to skip identity redirects.
  • Wildcards aren’t supported. Each redirect is one specific path. To handle a pattern, expand it in the mapping (one row per matched path).
  • Query strings are stripped. A redirect for /old?ref=email matches /old regardless of query string. Don’t try to encode query-string variations as separate redirects.
  • Volume. Shopify allows up to ~100,000 URL redirects per shop. For larger catalogs, prioritize high-traffic URLs (use the source platform’s analytics to rank).
  • Case sensitivity. Shopify normalizes paths to lowercase before matching. Mixed-case path values are folded automatically.
  • original_id should be a string. Source platforms often use integer IDs for redirect rules — wrap with $string() to satisfy the staging model.
Last updated on