When you rename a page, restructure your URLs, or move to StaticOwl from another
platform, you don't want old links to break. StaticOwl lets you define per-site
redirects that are served as real HTTP 301/302 responses at the CDN edge —
not client-side <meta refresh> hacks — so search engines transfer ranking and
browsers cache the move.
This guide covers what redirects are, how to create them (dashboard, API, and MCP), how they become real edge redirects, and how they behave on preview subdomains versus your custom domain.
Quick start
A redirect maps a from path on your site to a to destination:
| from | to | code | meaning |
|---|---|---|---|
/old-pricing |
/pricing |
301 | permanent move (SEO-preserving) |
/promo |
/black-friday |
302 | temporary move |
/docs |
/help |
301 | section rename |
/blog/old |
https://… |
301 | off-site (absolute URL allowed) |
Create one in the dashboard under Site → Redirects, or via the API/MCP (below).
Within a minute or two of saving, https://<your-site>/old-pricing returns:
HTTP/2 301
location: https://<your-site>/pricing
301 vs 302 — which to use
- 301 Moved Permanently — the URL has changed for good. Browsers and search engines cache it and transfer SEO signal from the old URL to the new one. Use this for renames, restructures, and platform migrations. This is the default.
- 302 Found — a temporary move. Nothing is cached long-term and SEO signal stays on the original URL. Use this for time-boxed campaigns or A/B routing.
If you're unsure, use 301. Only reach for 302 when the old URL will come back.
Creating redirects
Dashboard
Site → Redirects → Add redirect. Enter the from path (must start with /),
the to destination (a path on the same site or an absolute https://… URL),
and pick 301 or 302. Save. The redirect is live at the edge shortly after.
API
# Create / update (upsert) a redirect
curl -X POST https://app.staticowl.com/api/redirects \
-H "Authorization: Bearer $STATICOWL_API_KEY" \
-H "X-Site-Id: site:mysite" \
-H "Content-Type: application/json" \
-d '{"from":"/old-pricing","to":"/pricing","code":301}'
# List all redirects for the site
curl https://app.staticowl.com/api/redirects \
-H "Authorization: Bearer $STATICOWL_API_KEY" -H "X-Site-Id: site:mysite"
# Delete a redirect (removes the edge rule too)
curl -X DELETE "https://app.staticowl.com/api/redirects/<id>" \
-H "Authorization: Bearer $STATICOWL_API_KEY" -H "X-Site-Id: site:mysite"
Notes:
fromandtoare normalized (a leading slash is added, a trailing slash is trimmed except on root)./old-pricing/and/old-pricingare the same rule.fromandtomust differ.codeaccepts301or302; anything else is treated as301.- Creating with the same
fromagain overwrites the existing rule (upsert).
MCP (AI agents)
The same operations are available to agents over MCP:
redirects_create— create/update a redirect (from,to,code)redirects_list— list the site's redirectsredirects_delete— remove one (byid, found viaredirects_list)
Agents need a write role (admin, editor, or publisher) on the site. Bulk
re-sync (below) is currently an HTTP-only operation.
How redirects become real edge 301s
Plain static hosting (S3 behind a CDN) can't emit a real 301 on its own — an S3 object either exists or 404s. StaticOwl bridges that gap with a small edge function backed by a lookup table:
- When you save a redirect, StaticOwl writes it into a CloudFront
KeyValueStore keyed by
<host>|<path>with the value<status>|<location>. - A viewer-request CloudFront Function runs on every request. Before serving
anything it looks up
<host>|<path>in that store. On a hit it returns the 301/302 immediately; on a miss the request proceeds normally. - Deleting a redirect removes its keys, so the edge stops redirecting within a minute or two.
This all happens automatically — you just create and delete redirects. The rules
are also compiled into a _redirects file in your published output for portability
to other hosts, but the live behavior on StaticOwl comes from the edge function.
Propagation timing
Edge functions and the lookup table propagate to CloudFront's global edge within roughly 1–2 minutes of a change. If you test immediately after saving and see the old behavior, wait a moment and retry.
Preview subdomains vs. custom domains
Every site has preview hosts — <slug>-<env>.preview.staticowl.com, one per
environment (e.g. -dev, -prod). Redirects work on all of a site's hosts:
- Preview hosts — redirects fire immediately on the shared preview distribution. No setup needed.
- Custom domain — once your site has a custom domain configured (Pro/Business plans) and it has been cut over to its CloudFront distribution, redirects fire there too. The redirect table is keyed on the custom-domain host automatically the moment the domain is set, so a rule you create applies to both the preview hosts and the live domain.
At custom-domain cutover: the same edge redirect function must be attached to the domain's CloudFront distribution as a viewer-request function (StaticOwl handles this during provisioning). After that, no per-redirect action is needed — every rule you create or delete syncs to the live domain on its own.
Bulk import & re-sync
If you migrated many URLs at once (e.g. from WordPress) or created redirects before edge sync existed, push them all to the edge in one shot:
curl -X POST https://app.staticowl.com/api/redirects/_resync \
-H "Authorization: Bearer $STATICOWL_API_KEY" -H "X-Site-Id: site:mysite"
_resync walks every enabled redirect for the site and (re)writes its edge keys.
It's safe to run any time — it's idempotent and only ever brings the edge in line
with your current redirect list.
Gotchas & tips
- Redirects beat pages. A redirect on
/xfires before any page at/xwould render. If a redirect seems to "hide" a page, check your redirect list. - Loops. Don't point
/a → /band/b → /a. The edge won't detect the loop for you; the browser will just bounce until it gives up. - Absolute URLs in
toare allowed (off-site moves). Same-site destinations should be root-relative paths (/pricing, nothttps://…/pricing). - Query strings & hashes aren't matched — a redirect keys on the path only.
locationis returned exactly as you stored it. - Case-sensitive paths.
/Pricingand/pricingare distinct keys. - Deletes take a minute to drain from the edge, same as creates.
See also
- Publishing & environments — how preview and production hosts, custom domains, and builds fit together.
- Zero to deployed — the 5-minute quickstart.
- Deploy targets — S3, GitHub, and CDN options.