Skip to content

Ghost Advanced Configuration — Custom routes.yaml, Redirects and Collections

DodaTech Updated 2026-06-28 7 min read

In this tutorial, you'll learn advanced Ghost configuration — creating custom routes.yaml files for granular URL control, configuring redirects for moved content, building dynamic collections with filters, and managing custom templates for different content sections.

What You'll Learn

  • The routes.yaml file structure and syntax
  • Creating custom routes for specific templates
  • Dynamic collections with tag filters and custom permalinks
  • Redirects configuration for URL changes
  • Custom templates for routes and collections
  • Advanced filtering with Ghost filter syntax
  • Taxonomies and custom URL patterns
  • Multiple RSS feeds for different collections
  • routes.yaml best practices and debugging

Why It Matters

By default, Ghost serves all posts at /slug/ and tags at /tag/slug/. That works for simple blogs, but as your site grows, you need more sophisticated URL structures — a news section at /news/, a tutorial collection at /guides/ with posts at /guides/post-slug/, a featured section at /picks/, and redirects for old URLs. routes.yaml gives you complete control over your site's URL architecture.

Real-World Use

A magazine site uses routes.yaml to create three sections: /news/ (daily articles, post URLs at /news/slug/), /features/ (long-form, post URLs at /features/slug/), and /opinion/ (editorials, post URLs at /opinion/slug/). Each section has its own RSS feed, its own template with different styling, and its own tag filter. The site also redirects /old-blog/ to /news/ to preserve SEO value from their previous URL structure.

Learning Path

flowchart LR
  A["Performance Optimization"] --> B["Advanced Configuration
You are here"]:::current B --> C["Database Management"] C --> D["Upgrading Ghost"] classDef current fill:#38bdf8,color:#0f172a,stroke-width:2px

The routes.yaml Structure

routes.yaml lives at content/settings/routes.yaml.

Three Sections

routes:
  # Individual URL → template mappings

collections:
  # Content collections with custom permalinks

taxonomies:
  # Override default tag/author URL patterns

Custom Routes

Routes map a single URL to a template, optionally with content filtering.

Static Routes

Serve a specific template at a specific URL:

routes:
  /about/:
    template: page-about
    data: page.about

  /contact/:
    template: page-contact
    data: page.contact

This renders the page-about.hbs template at /about/, populated with content from the Ghost page with slug "about."

Channel Routes

Create paginated content listings:

routes:
  /featured/:
    template: featured
    controller: channel
    filter: featured:true
    limit: 12

  /popular/:
    template: popular
    controller: channel
    order: count.posts desc
    limit: 20

Route Options

Option Description
template Handlebars template to render (without .hbs)
controller channel for listings; omit for single pages
filter Ghost filter syntax for content selection
limit Items per page (default 5, max 100)
order Sort order for content
data Specific page or post to populate the template

Collections

Collections create URL prefixes with custom permalinks for individual posts.

Basic Collections

collections:
  /news/:
    permalink: /news/{slug}/
    template: index
    filter: tags:[news]
    limit: 10

  /tutorials/:
    permalink: /tutorials/{slug}/
    template: tutorials
    filter: tags:[tutorial]
    limit: 6
collections:
  /blog/:
    permalink: /blog/{year}/{month}/{slug}/
    template: index
    filter: tags:-[internal]
    limit: 10

Advanced Collection

collections:
  /podcast/:
    permalink: /podcast/{slug}/
    template: podcast
    filter: tags:[podcast]
    order: published_at desc
    limit: 12
    data: page.podcast-landing

Collection Options

Option Description
permalink URL pattern for individual posts in the collection
template Template for the collection listing page
filter Content filter
limit Posts per page
order Sort order
data Optional page data for the collection landing

Taxonomies

Override the default URL patterns for tags and authors.

taxonomies:
  tag: /topic/{slug}/
  author: /writer/{slug}/

This changes:

  • /tag/<a href="/programming-languages/javascript/">JavaScript</a>/ to /topic/javascript/
  • /author/jane/ to /writer/jane/

Redirects

In routes.yaml

Add redirects directly in routes.yaml:

routes:
  /old-url/: /new-url/
  /legacy-post/: /blog/legacy-post/

Separate redirects.yaml

Create a content/settings/redirects.yaml file for larger redirect lists:

301:
  /old-about/: /about/
  /category/*: /blog/:splat/
  /2023/: /archive/2023/
302:
  /temporary-link/: /new-location/

Redirect Types

  • 301: Permanent redirect (passes SEO value)
  • 302: Temporary redirect (does not pass SEO value)

Custom Template Naming

Ghost looks for templates in this order:

  1. Exact match: {template}.hbs as specified in routes.yaml
  2. Fallback: index.hbs if the specified template does not exist
  3. Error: If no template is found, Ghost returns an error

Custom Templates for Pages

If you have a page with slug "about," create page-about.hbs and Ghost uses it automatically without routes.yaml.

Custom Templates for Routes

For a route /featured/ with template: featured, create featured.hbs in your theme root.

RSS Feeds for Collections

Each collection automatically generates an RSS feed:

/news/rss/
/tutorials/rss/
/podcast/rss/

This lets subscribers follow specific sections independently.

Example: Magazine Site

routes:
  /editors-picks/:
    template: picks
    controller: channel
    filter: featured:true
    limit: 10
  /about/:
    template: page-about
    data: page.about

collections:
  /news/:
    permalink: /news/{slug}/
    template: index
    filter: tags:[news]
    limit: 10
  /features/:
    permalink: /features/{slug}/
    template: features
    filter: tags:[feature]
    limit: 8
  /opinion/:
    permalink: /opinion/{slug}/
    template: index
    filter: tags:[opinion]
    limit: 10

taxonomies:
  tag: /topic/{slug}/

Common Mistakes

  1. Forgetting to restart Ghost after editing routes.yaml: Changes to routes.yaml do not take effect until Ghost is restarted. Run ghost restart after every edit. Some changes may require ghost reload instead.

  2. Creating conflicting routes: If you define /news/ as a collection and also have a post or tag with the slug "news," there will be a conflict. Ghost prioritizes routes.yaml definitions over content slugs.

  3. Using incorrect filter syntax: The filter parameter uses Ghost-specific syntax (e.g., tags:[news] not tag:news). Incorrect filters silently return empty collections. Test filters using the Content API first.

  4. Not providing templates for custom routes: If your routes.yaml references template: featured but there is no featured.hbs in your theme, Ghost falls back to index.hbs. If index.hbs is also missing, the route returns an error.

  5. Overcomplicating the URL structure: A simple /slug/ structure is often best for SEO. Deep nesting (/section/subsection/post-slug/) does not provide SEO benefits and makes URLs harder to share and remember.

Practice Questions

  1. What are the three sections of routes.yaml? Answer: routes (single URL → template mappings), collections (content groups with custom permalinks), and taxonomies (override default tag/author URL patterns).

  2. How do you create a custom RSS feed for a specific collection? Answer: Define a collection in routes.yaml. Ghost automatically generates an RSS feed at the collection URL + /rss/ (e.g., /news/rss/). Feeds are created for all collections and channel-type routes.

  3. What happens when a route in routes.yaml conflicts with a content slug? Answer: Ghost gives priority to routes.yaml definitions. If you define /news/ as a collection, any post or tag with the slug "news" will be inaccessible at that URL. Plan your routes.yaml to avoid conflicts with content slugs.

  4. Challenge: Design a complete routes.yaml for a multi-section publication. Include: a featured picks channel at /picks/, a news collection at /news/ with daily permalinks, a tutorials collection at /guides/ with guides at /guides/{slug}/, custom taxonomy URLs at /topic/{slug}/, and 301 redirects from old blog URLs to new sections.

FAQ

Can I have multiple routes.yaml files?

No. Ghost reads only content/settings/routes.yaml. All routing configuration must be in that single file. For complex configurations, use YAML anchors and aliases to keep the file organized.

How do I debug a custom route that shows no content?

First, verify the filter syntax by testing it against the Content API directly: GET /content/posts/?filter=tags:[news]. If the API returns posts, the filter is correct. Then check that the template file exists and Ghost was restarted.

Does routes.yaml affect the Ghost admin interface?

No. routes.yaml only affects the public site. The admin interface remains at /ghost/ and is unaffected by custom routing rules.

Can I use regex in routes.yaml?

No. Ghost does not support regex patterns in routes.yaml. All paths must be exact or use simple patterns. For complex URL rewriting, use Nginx rules before the request reaches Ghost.

How do I update routes.yaml without downtime?

Changes to routes.yaml require a Ghost restart, which causes a brief downtime (typically 1-5 seconds). To minimize impact, make changes during low-traffic periods, configure Nginx to show a maintenance page during restart, or use a load balancer.

Mini Project

Your task: Create a complete routes.yaml configuration for a production Ghost site.

  1. Design the URL structure for a publication with 3 sections: News, Features, Podcast.
  2. Create routes.yaml with collections for each section, custom permalinks, and template mappings.
  3. Create the corresponding Handlebars template files (news.hbs, features.hbs, podcast.hbs).
  4. Add custom taxonomy URLs.
  5. Create redirects for 5 old URLs to new locations.
  6. Test each URL works correctly.
  7. Document the routing configuration for future reference.

This exercise gives you complete control over your Ghost site's URL architecture.

What's Next

Now that routing is configured, learn about database management:

Continue to Lesson 36: Database Management — SQLite vs MySQL, backups, and maintenance.

Related lessons:

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro