Redirect mapping
StagingRedirect is the simplest staging shape — two fields. Every
output row creates a Shopify URL redirect.
You usually don’t need to map this by hand. Graftport can create redirects for you from the address changes between your old store and Shopify. See 301 redirects. Map the redirect resource only when you need redirects that aren’t derived from product or collection address changes.
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.