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
pathstringrequiredThe source path — where the customer lands. Must start with
/ and be relative to the destination shop’s domain.
"path": "/" & old_url_key & ".html"targetstringrequiredThe 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
} : nullReturning 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.
pathmust start with/. Without the leading slash the redirect is rejected.pathandtargetcan’t be equal — Shopify rejects self-loops. Use the conditionalnullpattern 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=emailmatches/oldregardless 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
pathvalues are folded automatically. original_idshould be a string. Source platforms often use integer IDs for redirect rules — wrap with$string()to satisfy the staging model.