In short: Ghost stores URL redirects in redirects.yaml. You download and upload it from Settings » Labs, same workflow as routes.yaml. Redirects forward old paths to new ones (or to external URLs); they complement—but do not replace—DNS/HTTPS configuration and dynamic routing for how Ghost builds URLs. For authoritative syntax details, see Ghost’s Implementing redirects tutorial.
What Ghost redirects are for
Visitors, newsletters, and search engines accumulate links to exact paths. When you rename a post, migrate from another CMS, or change permalink structure (often via routes.yaml), those links break unless you map old paths to new ones.
- 301 (permanent) — Tells clients and search engines the resource has moved for good; passes most ranking signals to the destination. Use for migrations and finalized URL changes.
- 302 (temporary) — Use for short-lived moves or A/B style tests where the old URL may return.
Redirects fix paths on your Ghost site (and can target external URLs). They do not replace server-level or DNS work for apex domains, www, or TLS.
Access and file format
- In Ghost Admin, open Settings » Labs.
- Download the current
redirects.yaml(or create a new file namedredirects.yamlif none exists yet). - Edit in a text editor (YAML; spaces for indentation, not tabs).
- Upload the file again.
Older Ghost installs may still have JSON redirects; YAML is what you should use for new rules. A brand-new publication starts with no redirects.
Structure of redirects.yaml
The file has two top-level keys: 301 and 302. Under each, list pairs of source: destination (path only for internal targets—no domain):
301:
/old-post-slug/: /new-post-slug/
/another-from/: /another-to/
302:
/temporary-source/: /temporary-destination/
Trailing slashes: Ghost enforces trailing slashes in many setups. Match the style your site actually uses when you write rules, and test both with and without a slash if something does not fire.
Removing all redirects: Uploading an empty file clears every redirect:
301:
302:
Use that only when you intend to wipe the list (Ghost’s documented behavior).
301 vs 302 — which to use
| Code | Typical use |
|---|---|
| 301 | Slug changes, migration from WordPress/Medium/Substack, consolidating duplicate URLs, moving /articles/ to /blog/ |
| 302 | Short maintenance moves, campaigns, or anything you expect to revert |
When in doubt after a migration, 301 is the usual choice so backlinks and SEO consolidate on the final URL.
Simple redirects examples
-
One post renamed
301: /old-slug/: /new-slug/ -
Tag or author URL renamed
If you changed taxonomy prefixes in routes.yaml or moved a tag’s slug:
301: /tag/old-label/: /tag/new-label/ -
External destination
Ghost supports redirecting to a full URL:
301: /legacy-page/: https://example.com/docs/new-location/ -
Multiple legacy URLs to one canonical path
301: /editing-a-post/: /editing/ /editing-posts/: /editing/
When not to use redirects.yaml
Ghost’s own guidance still applies:
- HTTP/HTTPS and www — Configure at your DNS or reverse proxy (e.g. Caddy, nginx), not in
redirects.yaml. - Trailing-slash normalization — Ghost already handles common slash behavior; you usually should not add rules only for that.
- Systematic permalink design — Prefer dynamic routing and
routes.yaml(see our Ghost routing guide) to define/blog/,/topic/, collections, and taxonomies. Use redirects to bridge old URLs after you change routing—not as the primary way to design structure.
Regex redirects (bulk and migrations)
Plain paths match one URL each. Regular expressions match many paths at once. Ghost uses ECMAScript (JavaScript) regex. In the destination, $1, $2, … insert captured groups from the pattern.
Warning
Bad regex can cause redirect loops, mass 404s, or accidental matches. Test in staging, use regex101 with ECMAScript flavor, and add one rule at a time when learning.
Strip a path prefix (e.g. /blog/slug/ → /slug/)
Old site served posts under /blog/post-slug/; Ghost now uses root permalinks /{slug}/:
301:
^\/blog\/([a-z0-9-]+)\/$: /$1
What it does: Captures the slug after /blog/ and sends the visitor to /{slug}/. Adjust [a-z0-9-]+ if your slugs allow other characters (Unicode, digits-only, etc.).
WordPress-style dated URLs → slug-only
Day and month in path (/2020/03/15/my-post/ → /my-post/):
301:
^\/[0-9]{4}\/[0-9]{2}\/[0-9]{2}\/(.*): /$1
Year and month only (/2020/03/my-post/ → /my-post/):
301:
^\/[0-9]{4}\/[0-9]{2}\/(.*): /$1
Important: The destination slug in Ghost must match the imported post slug ($1). If WordPress used different slugs than Ghost imports, you may need individual rules or a spreadsheet-driven set of redirects.
Category-style paths → Ghost tags
Many imports map “categories” to tags:
301:
^\/category\/(.*): /tag/$1
Ghost’s tutorial uses a similar pattern for /category/slug/ → /tag/slug/.
“Whole section” or old collection path
Redirects match URL paths, not Ghost collection names. If every old URL lived under /articles/ and new URLs live under /blog/ with the same slug:
301:
^\/articles\/(.*)$: /blog/$1
If old URLs were /articles/my-post/ and new posts are at root /my-post/:
301:
^\/articles\/(.*)$: /$1
Rule order: More specific rules should appear before broader regex if your tooling processes top-to-bottom; when in doubt, test. Avoid one giant regex until simpler rules are exhausted.
Platform snippets (from Ghost’s docs)
Squarespace blog prefix to root slug:
301:
^\/blog\/(\S+): /$1
Medium-style ID suffix strip (verify against your real URLs before production):
301:
^\/(?!p\/)(.*)(-[0-9a-f]{10,12}): /$1
Substack /p/ handling is nuanced (Ghost also uses /p/ for previews). See Ghost’s full Substack example before copying.
Redirects and routes.yaml together
Changing collections or permalinks in routes.yaml updates new URLs immediately. Existing inbound links still point at old paths. After you deploy new routing:
- List old patterns (export from the old CMS, analytics, or Search Console).
- Add 301 rules in
redirects.yamlfrom old paths to the new canonical paths. - Upload and test.
Example: you moved the post index from / to /blog/ and kept slugs the same—old /my-post/ might need to become /blog/my-post/ depending on your new permalink; express that explicitly in redirects.
For meta titles and descriptions on routed URLs, see routes metadata and SEO. For a marketing page at / plus posts under /blog/, see building a custom homepage.
Testing and troubleshooting
Quick checks
- Open an old URL in a private/incognito window (avoids stale browser cache).
- Use
curl -I https://yoursite.com/old-path/and confirm301(or302) and a sensibleLocation:header. - Spot-check high-traffic URLs from analytics or backlinks.
Common issues
- Wrong slash — Source or target missing
/at the end vs your live permalinks. - Regex too greedy —
(.*)matches more than you intended; narrow the pattern or anchor with^and$. - Conflicting rules — Two rules matching the same path; simplify and retest.
- CDN cache — Edge caches may briefly serve old responses after you change redirects.
Quick checklist
- Prefer 301 for permanent migrations.
- Edit
redirects.yamlin Labs; keep YAML valid. - Start with literal rules; add regex when you need bulk mapping.
- Test with curl or incognito before relying on search engines updating.
This guide is a practical companion to Ghost’s Implementing redirects tutorial. For URL structure itself, read Ghost dynamic routing and routes.yaml. Changing domains involves DNS and Ghost config as well—see updating your Ghost site URL. For collection filters that affect where posts appear (not redirects), see Ghost filter expressions.