Skip to content

Preview Paths and Redirects

The preview_path option tells Sveltia CMS where an entry lives on your site, which enables site previews, deploy previews and automatic redirects when an entry’s slug changes.

Preview Paths

The preview_path option allows you to define a custom URL path for previewing entries on your live site. This option accepts a string with template tags that will be replaced with entry-specific values when generating the preview URL. The CMS provides links to preview the entries based on this URL structure.

The path is appended to your site’s own address, or to the address of a build made for the entry when your repository is connected to a CI/CD provider. See Deploy Previews for how those are found.

The slug template tags can be used in the preview_path option, with the following exceptions:

  • {{slug}}: the entire slug of the entry, not just the slugified entry identifier.
  • {{year}}, {{month}}, {{day}}, {{hour}}, {{minute}}, {{second}}: these tags are based on the entry’s DateTime field. The CMS looks for the first DateTime field in the collection to extract the date and time information. Use the preview_path_date_field option to specify a different date field. If no DateTime field is found, the preview_path option will be ignored, and a configuration warning is shown so the missing link doesn’t go unexplained. A field that exists but is left empty on an entry has the same effect on that entry.
  • {{dirname}}: the directory name of the entry file relative to the collection folder. This is useful when using the path option to create subfolders.
  • {{filename}}: the filename of the entry without the extension. This is useful when you want to use the exact filename in the preview URL.
  • {{extension}}: the file extension of the entry. This is useful when you want to include the file type in the preview URL.
  • {{locale}}: the locale code of the entry when using i18n support. This is useful when you want to include the locale in the preview URL.

Just like the slug and path options, any field name defined in the collection’s fields option can also be used as a template tag in preview_path. If a field’s name matches one of the predefined tags listed above or in the slug template tags, such as slug, year or uuid, you need to prefix it with fields., like {{fields.slug}}, to avoid confusion with the tag itself.

You can use string transformations with these template tags.

The example below shows how to configure a blog posts collection with a custom preview URL structure.

yaml
collections:
  - name: posts
    label: Blog Posts
    folder: /content/posts
    preview_path: '/blog/{{year}}/{{month}}/{{slug}}'
    preview_path_date_field: created_at
    fields:
      - { name: title, label: Title }
      - { name: created_at, label: Created At, widget: datetime }
      - { name: body, label: Body, widget: richtext }
toml
[[collections]]
name = "posts"
label = "Blog Posts"
folder = "/content/posts"
preview_path = "/blog/{{year}}/{{month}}/{{slug}}"
preview_path_date_field = "created_at"
[[collections.fields]]
name = "title"
label = "Title"
[[collections.fields]]
name = "created_at"
label = "Created At"
widget = "datetime"
[[collections.fields]]
name = "body"
label = "Body"
widget = "richtext"
json
{
  "collections": [
    {
      "name": "posts",
      "label": "Blog Posts",
      "folder": "/content/posts",
      "preview_path": "/blog/{{year}}/{{month}}/{{slug}}",
      "preview_path_date_field": "created_at",
      "fields": [
        { "name": "title", "label": "Title" },
        { "name": "created_at", "label": "Created At", "widget": "datetime" },
        { "name": "body", "label": "Body", "widget": "richtext" }
      ]
    }
  ]
}
js
{
  collections: [
    {
      name: "posts",
      label: "Blog Posts",
      folder: "/content/posts",
      preview_path: "/blog/{{year}}/{{month}}/{{slug}}",
      preview_path_date_field: "created_at",
      fields: [
        { name: "title", label: "Title" },
        { name: "created_at", label: "Created At", widget: "datetime" },
        { name: "body", label: "Body", widget: "richtext" },
      ],
    },
  ],
}

With the above configuration, a blog post created on June 15, 2025, with the title “My First Post” will have a preview URL of /blog/2025/06/my-first-post.

Setting the preview_path option does two more things:

  • It lets the CMS keep links working when an entry is renamed. See Redirects below.
  • It’s what Deploy Previews need in order to point at an entry. Without it there’s nothing to append to the site or preview address, so no preview link is shown.

Redirects

Changing an entry’s slug usually changes its URL, which breaks existing links to it, including internal links, external links and search engine results. To prevent this, Sveltia CMS can record the entry’s previous path in its data, so your framework can redirect visitors from the old URL to the new one.

This requires the preview_path option, because that option is what tells the CMS where an entry lives on your live site. Once it’s set, saving an entry with a modified slug adds the previous path to the entry’s aliases property:

  • If the property doesn’t exist yet, it’s created as a list with a single item.
  • If the property already exists as a list, the previous path is appended to it, so redirects accumulate as an entry is renamed over time.

Entry slugs can be changed with the Slug Editor, which can be accessed via the 3-dot menu in the Content Editor.

With the preview_path configuration shown above, renaming a June 2025 blog post from my-first-post to hello-world results in the following front matter:

yaml
---
aliases:
  - /blog/2025/06/my-first-post
title: Hello World
created_at: 2025-06-15T09:00:00.000Z
---

The aliases property is supported out of the box by Hugo and Zola, which generate the redirects for you. Other frameworks may expect a different property name or require a plugin.

Customizing the Redirect Property

You can store the previous paths in a property other than aliases using the aliases_field option. For example, Jekyll sites using the jekyll-redirect-from plugin expect a redirect_from property:

yaml
collections:
  - name: posts
    label: Blog Posts
    folder: /content/posts
    preview_path: '/blog/{{year}}/{{month}}/{{slug}}'
    aliases_field: redirect_from
toml
[[collections]]
name = "posts"
label = "Blog Posts"
folder = "/content/posts"
preview_path = "/blog/{{year}}/{{month}}/{{slug}}"
aliases_field = "redirect_from"
json
{
  "collections": [
    {
      "name": "posts",
      "label": "Blog Posts",
      "folder": "/content/posts",
      "preview_path": "/blog/{{year}}/{{month}}/{{slug}}",
      "aliases_field": "redirect_from"
    }
  ]
}
js
{
  collections: [
    {
      name: "posts",
      label: "Blog Posts",
      folder: "/content/posts",
      preview_path: "/blog/{{year}}/{{month}}/{{slug}}",
      aliases_field: "redirect_from",
    },
  ],
}

Disabling Redirects

If your framework doesn’t support redirects defined in entry data, set the aliases_field option to false. The CMS will then leave the property untouched when an entry is renamed, and no redirects will be generated.

yaml
collections:
  - name: posts
    label: Blog Posts
    folder: /content/posts
    preview_path: '/blog/{{year}}/{{month}}/{{slug}}'
    aliases_field: false
toml
[[collections]]
name = "posts"
label = "Blog Posts"
folder = "/content/posts"
preview_path = "/blog/{{year}}/{{month}}/{{slug}}"
aliases_field = false
json
{
  "collections": [
    {
      "name": "posts",
      "label": "Blog Posts",
      "folder": "/content/posts",
      "preview_path": "/blog/{{year}}/{{month}}/{{slug}}",
      "aliases_field": false
    }
  ]
}
js
{
  collections: [
    {
      name: "posts",
      label: "Blog Posts",
      folder: "/content/posts",
      preview_path: "/blog/{{year}}/{{month}}/{{slug}}",
      aliases_field: false,
    },
  ],
}

The same applies if you define a field with the same name as the redirect property in the fields option. The CMS assumes that you want to manage the redirects yourself in the Content Editor, so it won’t write to the property on its own. This is the way to go if you’d rather curate the list by hand while still being able to see and edit it in the CMS.