---
url: /en/docs/fields/relation.md
description: Create relationships between entries in Sveltia CMS across collections.
---

# Relation Field

The Relation field type enables users to create relationships between entries in different collections within the CMS. There are two types of relations supported, depending on the target collection type:

* Entries in an [entry collection](/en/docs/collections/entries)
* List items in a specific file in a [file collection](/en/docs/collections/files)

The Content Editor comes with the [Backlinks sidebar panel](/en/docs/ui/content-editor#sidebar) that shows all entries that reference the current entry via Relation fields. This makes it easy to see how entries are connected and navigate between them, for example, to see all blog posts that are tagged with a specific tag.

## User Interface

### Editor

Radio buttons (single select) or checkboxes (multi select) for choosing related entries from another collection. If there are many entries, a dropdown with search functionality will be used instead. Use the `dropdown_threshold` option to customize when to switch to the dropdown UI.

For multi-select options with many entries, a tag input UI will be used instead of checkboxes to save space. Items can be reordered by dragging and dropping or using right/left arrow keys. Items can also be removed by clicking the ✕ icon on each item.

The options are listed in the following order:

* List items in a file, with the [`file`](#file) option: the order of the items in the list.
* Entries in an entry collection with the [`reorder`](/en/docs/collections/entries/operations#reordering-entries) option: the manual order of the entries. Entries without an order value, such as the ones just created with the [**Add**](#creating-related-entries) button, come last.
* Entries in a [single-file collection](/en/docs/collections/entries/single-file): the order of the entries in the array.
* Entries in any other entry collection: alphabetical order of the labels.

### Creating Related Entries

When the related collection is an entry collection, the field also offers an **Add** button labeled with the collection’s singular label, e.g. “Add Tag” or “Add Author”. It opens a dialog to create a related entry without leaving the entry being edited, so users don’t have to save their work, go to the other collection, create the entry there and come back — or pick a wrong entry just to be able to save.

The dialog is a single-pane editor with all the fields of the related collection. If the collection has [multiple locales](/en/docs/i18n), a locale switcher in the dialog header lets users fill in each of them. Clicking **Add** validates the new entry the same way a save does; if a required field is empty, the dialog stays open and the error is shown on the field. Once added, the new entry is selected in the Relation field right away, listed among the options like any other entry, and shown by its label in the Preview Pane.

The new entry is not saved on its own. It’s kept with the draft and committed **together with the entry being edited** when the user saves, in a single commit, so the two never go out of sync: a blog post and the tags created for it land in the repository at the same time. Until then, the entry only exists in the draft:

* If the user deselects the new entry before saving, it’s dropped rather than created for nothing.
* If the user adds two entries with the same title, the second one gets a distinct slug, e.g. `svelte-1`, the same way it would if they were created one after another.
* The dialog can be nested: a Relation field in the new entry has its own **Add** button, and the entries created there are saved along with everything else, as long as they are still referenced.
* Files attached to the new entry, such as an author’s avatar, are uploaded in the same commit.
* The pending entries are part of the [auto-saved draft](/en/docs/ui/content-editor#auto-saving-drafts), so they survive a page reload along with the rest of the changes.

The button is not offered in the following cases:

* The related collection is a [file collection](/en/docs/collections/files), with the [`file`](#file) option. The button creates a new entry, but such a field selects an item from a list within an existing file. Adding an item would mean editing that file from another entry, which could conflict with changes made to the file elsewhere, so the item is added by editing the file itself instead.
* The related collection has the [`create: false`](/en/docs/collections/entries/operations#disabling-creation-and-deletion) option.
* The related collection has reached its [`limit`](/en/docs/collections/entries/operations#limiting-entry-count), counting the entries pending in the draft. The button is then shown disabled.
* The Relation field is read-only.
* The entry being edited is saved through the [Editorial Workflow](/en/docs/workflows/editorial), or the related collection is under the workflow on its own. A pull request stands for a single entry in the workflow, so an entry created on the fly would either be invisible until the pull request is published, or skip the review the related collection asks for. Create the related entry in its own collection instead.

### Preview

A string or a list of strings representing the selected related entries, formatted according to the `display_fields` option.

## Data Type

A string or an array of strings, depending on whether the `multiple` option is set to `true` or `false`. Each string represents the value of the related entry as defined by the `value_field` option.

In some cases, it can also be a number or an array of numbers if the `value_field` of the related collection is of a numeric type, like an ID.

If the `required` option is set to `false` and no related entries are selected, the value will be `null` for single select or an empty array for multi select.

### Cascading Updates

Like a relational database that cascades an update of a referenced key, Sveltia CMS keeps Relation field values pointing at the right entry when the entry they reference is renamed. Renaming a related entry in the [Slug panel](/en/docs/ui/content-editor#slug-panel) rewrites every entry referencing it, in the same commit as the rename, so no references are left dangling.

This applies whenever the stored value is derived from the related entry’s identity, which covers the default `{{slug}}`, any template containing `{{slug}}`, such as `{{locale}}/{{slug}}`, and the canonical slug key. It does not apply to a `value_field` pointing at an ordinary content field, such as `{{title}}`, because such a value doesn’t change when the entry is renamed — but it does break if somebody edits that field. It’s one more reason to prefer the default `{{slug}}`, as noted under [`value_field`](#value-field).

### Cascading Deletions

Deletions are cascaded in the same way. When an entry is deleted, whether from the Content Editor or by [selecting one or more entries](/en/docs/ui/content-library#bulk-actions) in the entry list, every entry referencing it through a Relation field is rewritten in the same commit as the deletion: a single-select field is cleared, and the deleted entry is dropped from a multi-select field’s list. The confirmation dialog tells the user how many entries will be updated. Unlike a rename, this applies whatever the `value_field` is, because references are matched on the stored value rather than derived from the slug. With the [Editorial Workflow](/en/docs/workflows/editorial), the updates go into the same pull request as the deletion.

A reference is never removed at the cost of the referencing entry’s validity, though. If clearing it would break the field’s own [validation rules](#data-validation) — a `required` field left with nothing selected, or a multi-select field left with fewer than `min` items — the deletion is refused, and the dialog lists the entries and fields standing in the way so that the user can update them first. The check covers the whole selection: deleting two entries at once may be refused where deleting either on its own would go through. The [Backlinks sidebar panel](/en/docs/ui/content-editor#sidebar) shows what references an entry, so users can see what a deletion would touch before they start.

## Data Validation

* If the `required` option is set to `true`, at least one related entry must be selected.
* If the `multiple` option is enabled, the number of selected entries must be between the `min` and `max` limits, if specified.
* If the [`pattern`](/en/docs/fields#pattern) option is provided, the stored value of the selected entry, as defined by the `value_field` option, must match the regular expression. For multi select, the stored values joined with commas, e.g. `foo,bar,baz`, must match instead: as with Decap CMS, the pattern is tested against the whole selection rather than against each value, so use `^[a-z-]+(,[a-z-]+)*$` rather than `^[a-z-]+$` to accept lowercase slugs only. Numbers are tested as strings, and the pattern is not tested while nothing is selected.

## Options

In addition to the [common field options](/en/docs/fields#common-options), the Relation field supports the following options:

### Required Options

#### `widget`

* **Type**: `string`
* **Default**: `string`

Must be set to `relation`.

#### `collection`

* **Type**: `string`
* **Default**: `undefined`

The name of the collection to relate to. This collection must exist in the CMS configuration, and can be either an entry collection or a file collection. Use `_singletons` to relate to a [singleton](/en/docs/collections/singletons). If the target collection is a file collection or the singleton collection, the `file` option must also be specified.

### Optional Options

::: warning Breaking changes from Netlify/Decap CMS

Sveltia CMS does not support the deprecated camelCase `valueField`, `displayFields` and `searchFields` options. Use `value_field`, `display_fields` and `search_fields` instead.

The `options_length` option is also not supported in Sveltia CMS because the performance has been improved significantly.

:::

#### `file`

* **Type**: `string`
* **Default**: `undefined`

The name of a file within the target [file collection](/en/docs/collections/files), or of a singleton, to relate to. Required if the target collection is a file collection or the singleton collection.

#### `value_field`

* **Type**: `string`
* **Default**: `{{slug}}`

The field from the related collection to use as the value for the relation. This field’s value will be stored in the entry using the Relation field. It can be one of the following:

* `{{slug}}`: Use the slug of the related entry.
* A field name from the related collection, e.g., `id` or `title`.
* A template string that references fields in the related collection using the syntax `{{field_name}}`. For example, `{{fields.id}}` or `{{fields.title}}`.
* `translationKey`, or any other key configured with the `i18n.canonical_slug.key` option: Use the canonical slug of the related entry, which is shared across locales. See [below](#referencing-entries-across-locales).

The `{{locale}}` template tag can be used to include the current locale in the value field, e.g. `{{locale}}/{{slug}}`, which is useful for [i18n support](/en/docs/i18n).

In a [nested collection](/en/docs/collections/entries/nested), an entry’s slug is its path below the collection folder, so `{{slug}}` resolves to something like `company/about`. Where every entry is stored as an index file, the shared file name is left out of that path, exactly as it is in a [preview path](/en/docs/collections/entries/previews#preview-paths): an entry stored at `content/pages/company/about/_index.md` is referenced as `company/about`, not `company/about/_index`. The collection’s own index file is the exception, keeping its name so that a reference to it isn’t empty.

In a [single-file collection](/en/docs/collections/entries/single-file), an entry’s slug is its position in the array, which changes when the entries are reordered or one is deleted. The value field must therefore refer to a field, preferably one with a unique value like an ID; `{{slug}}`, including the default, is reported as invalid.

When using template strings, keep the following in mind:

* A field named `slug` must be prefixed with `fields.` like `{{fields.slug}}` to avoid ambiguity with the special `{{slug}}` variable.
* Nested fields can also be referenced using dot notation, e.g., `{{author.name}}`.
* To reference list items, use a wildcard `*` for the index, e.g., `{{tags.*}}` or `{{gallery.*.image}}`. This works for a list field with the `field` or `fields` option.

A plain field name or dot-notation path without the curly brackets, such as `title`, `name.first` or `cities.*.id`, is treated as if it were enclosed in `{{…}}`. The same applies to `display_fields` and `search_fields`. The exception is a bare `slug`, which refers to the field named `slug` (`{{fields.slug}}`), not the entry slug; use `{{slug}}` for the latter.

The value field must be unique across all entries in the related collection to avoid conflicts. For example, using `{{title}}` as the value field is not recommended unless you can guarantee that all titles are unique. That’s why the default is `{{slug}}`, which is unique by design.

#### `display_fields`

* **Type**: `array` of `strings`
* **Default**: `["title"]` if `value_field` is `{{slug}}`, otherwise the value of `value_field` option

The fields from the related collection to display in the Relation field UI when selecting related entries. This should be an array of field names. The values of these fields will be concatenated and shown as the label for each related entry.

String templates can be used to customize the display format. For example, to show both first and last names from separate fields, you can use either of the following:

::: code-group

```yaml [YAML]
display_fields: ['{{first_name}} {{last_name}}']
```

```toml [TOML]
display_fields = ["{{first_name}} {{last_name}}"]
```

```json [JSON]
{
  "display_fields": ["{{first_name}} {{last_name}}"]
}
```

```js [JavaScript]
{
  display_fields: ["{{first_name}} {{last_name}}"],
}
```

:::

::: code-group

```yaml [YAML]
display_fields: ['first_name', 'last_name']
```

```toml [TOML]
display_fields = ["first_name", "last_name"]
```

```json [JSON]
{
  "display_fields": ["first_name", "last_name"]
}
```

```js [JavaScript]
{
  display_fields: ["first_name", "last_name"],
}
```

:::

#### `search_fields`

* **Type**: `array` of `strings`
* **Default**: value of `display_fields` option

The fields from the related collection to search against when filtering related entries in the Relation field UI. This should be an array of field names, which can also be string templates, just like `display_fields`. By default, it uses the same fields as specified in the `display_fields` option.

#### `default`

* **Type**: `string`, `number`, `array of strings`, or `array of numbers`
* **Default**: `null` or `[]`

The default value for the field. Should be a string or number for single select, or an array of strings or numbers for multi select, depending on the `multiple` option. An array with `multiple` off, or a single value with `multiple` on, is reported as a config validation error on the login screen.

#### `dropdown_threshold`

* **Type**: `integer`
* **Default**: `5`

The number of related entries at which to switch from radio buttons/checkboxes to a dropdown with search functionality. If the number of entries in the target collection is greater than this threshold, a dropdown will be used.

#### `multiple`

* **Type**: `boolean`
* **Default**: `false`

Whether to allow selecting multiple related entries.

#### `min`

* **Type**: `integer`
* **Default**: `0`

The minimum number of related entries required. This enables validation to ensure that users select at least this many entries. Ignored if `multiple` is set to `false`.

#### `max`

* **Type**: `integer`
* **Default**: `Infinity`

The maximum number of related entries allowed. This enables validation to prevent users from selecting more than this many entries. Ignored if `multiple` is set to `false`.

#### `filters`

* **Type**: `array` of filter objects
* **Default**: `[]`

An array of filter objects to limit the related entries shown in the Relation field UI. Each filter object has the following properties:

* `field`: The field name in the **related** collection to filter on. Use `slug` to filter by entry slug or `fields.fieldName` to filter by a content field named `fieldName` (the `fields.` prefix is required to disambiguate from the entry slug when the field is literally named `slug`). A `slug` filter matches the same form the value takes, so in a nested collection it’s the entry’s path without the shared index file name. If the field holds multiple values, such as a [Select](/en/docs/fields/select) field with `multiple: true` or a [List](/en/docs/fields/list) field without subfields, an entry matches when any of its values is included in `values`.

* `values`: An array of strings or numbers representing the values to match. A value may be one of the following template tags, which are resolved from the **current** entry being edited. The tag has to be the whole value, not part of a longer string like `tag-{{slug}}`:

  * `{{slug}}`: Resolved to the current entry's slug.
  * `{{fields.fieldName}}`: Resolved to the value of a field named `fieldName` in the current entry. If the field holds multiple values, the template is expanded to all of them, so an entry matches when it shares any of them with the current entry.

  Unresolvable templates (e.g. `{{slug}}` for a new, unsaved entry, or `{{fields.fieldName}}` for a field with no values) are ignored, causing the filter to be skipped.

* `exclude` *(optional)*: If `true`, entries **matching** the filter are excluded instead of included. An entry whose field holds multiple values is excluded when any of them matches. Default: `false`.

Example — show only published entries in a specific category:

::: code-group

```yaml [YAML]
filters:
  - field: draft
    values: [false]
  - field: category
    values: ['news', 'updates']
```

```toml [TOML]
[[filters]]
field = "draft"
values = [false]

[[filters]]
field = "category"
values = ["news", "updates"]
```

```json [JSON]
{
  "filters": [
    {
      "field": "draft",
      "values": [false]
    },
    {
      "field": "category",
      "values": ["news", "updates"]
    }
  ]
}
```

```js [JavaScript]
{
  filters: [
    {
      field: 'draft',
      values: [false],
    },
    {
      field: 'category',
      values: ['news', 'updates'],
    },
  ],
}
```

:::

Example — exclude the current entry from a “Related Articles” Relation field (self-exclusion):

::: code-group

```yaml [YAML]
filters:
  - field: slug
    values: ['{{slug}}']
    exclude: true
```

```toml [TOML]
[[filters]]
field = "slug"
values = ["{{slug}}"]
exclude = true
```

```json [JSON]
{
  "filters": [
    {
      "field": "slug",
      "values": ["{{slug}}"],
      "exclude": true
    }
  ]
}
```

```js [JavaScript]
{
  filters: [
    {
      field: 'slug',
      values: ['{{slug}}'],
      exclude: true,
    },
  ],
}
```

:::

## Examples

### Selecting Entries from an Entry Collection

Assuming you have the following entry collection named `categories`:

::: code-group

```yaml{2} [YAML]
collections:
  - name: categories
    label: Categories
    folder: content/categories
    fields:
      - name: title
        label: Title
        widget: string
      - name: slug
        label: Slug
        widget: string
      - name: description
        label: Description
        widget: text
```

```toml{2} [TOML]
[[collections]]
name = "categories"
label = "Categories"
folder = "content/categories"
[[collections.fields]]
name = "title"
label = "Title"
widget = "string"
[[collections.fields]]
name = "slug"
label = "Slug"
widget = "string"
[[collections.fields]]
name = "description"
label = "Description"
widget = "text"
```

```json{4} [JSON]
{
  "collections": [
    {
      "name": "categories",
      "label": "Categories",
      "folder": "content/categories",
      "fields": [
        {
          "name": "title",
          "label": "Title",
          "widget": "string"
        },
        {
          "name": "slug",
          "label": "Slug",
          "widget": "string"
        },
        {
          "name": "description",
          "label": "Description",
          "widget": "text"
        }
      ]
    }
  ]
}
```

```js{4} [JavaScript]
{
  collections: [
    {
      name: 'categories',
      label: 'Categories',
      folder: 'content/categories',
      fields: [
        {
          name: 'title',
          label: 'Title',
          widget: 'string',
        },
        {
          name: 'slug',
          label: 'Slug',
          widget: 'string',
        },
        {
          name: 'description',
          label: 'Description',
          widget: 'text',
        },
      ],
    },
  ],
}
```

:::

You can create a Relation field in another collection to select a single category:

::: code-group

```yaml{5} [YAML]
fields:
  - name: category
    label: Category
    widget: relation
    collection: categories
    value_field: slug
    display_fields: [title]
    search_fields: [title, description]
```

```toml{5} [TOML]
[[fields]]
name = "category"
label = "Category"
widget = "relation"
collection = "categories"
value_field = "slug"
display_fields = ["title"]
search_fields = ["title", "description"]
```

```json{7} [JSON]
{
  "fields": [
    {
      "name": "category",
      "label": "Category",
      "widget": "relation",
      "collection": "categories",
      "value_field": "slug",
      "display_fields": ["title"],
      "search_fields": ["title", "description"]
    }
  ]
}
```

```js{7} [JavaScript]
{
  fields: [
    {
      name: 'category',
      label: 'Category',
      widget: 'relation',
      collection: 'categories',
      value_field: 'slug',
      display_fields: ['title'],
      search_fields: ['title', 'description'],
    },
  ],
}
```

:::

Output example when the selected category has a slug of `news`:

::: code-group

```yaml [YAML]
category: news
```

```toml [TOML]
category = "news"
```

```json [JSON]
{
  "category": "news"
}
```

:::

### Referencing a File in a File Collection, Multiple Select

Assuming you have the following `cities` file in a `data` file collection:

::: code-group

```yaml{2,5} [YAML]
collections:
  - name: data
    label: Data
    files:
      - name: locations
        label: Locations
        file: data/locations.yaml
        fields:
          - name: cities
            label: Cities
            widget: list
            fields:
              - name: name
                label: Name
                widget: string
              - name: country
                label: Country
                widget: string
```

```toml{2,5} [TOML]
[[collections]]
name = "data"
label = "Data"
[[collections.files]]
name = "locations"
label = "Locations"
file = "data/locations.yaml"
[[collections.files.fields]]
name = "cities"
label = "Cities"
widget = "list"
[[collections.files.fields.fields]]
name = "name"
label = "Name"
widget = "string"
[[collections.files.fields.fields]]
name = "country"
label = "Country"
widget = "string"
```

```json{4,8} [JSON]
{
  "collections": [
    {
      "name": "data",
      "label": "Data",
      "files": [
        {
          "name": "locations",
          "label": "Locations",
          "file": "data/locations.yaml",
          "fields": [
            {
              "name": "cities",
              "label": "Cities",
              "widget": "list",
              "fields": [
                {
                  "name": "name",
                  "label": "Name",
                  "widget": "string"
                },
                {
                  "name": "country",
                  "label": "Country",
                  "widget": "string"
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}
```

```js{4,8} [JavaScript]
{
  collections: [
    {
      name: 'data',
      label: 'Data',
      files: [
        {
          name: 'locations',
          label: 'Locations',
          file: 'data/locations.yaml',
          fields: [
            {
              name: 'cities',
              label: 'Cities',
              widget: 'list',
              fields: [
                {
                  name: 'name',
                  label: 'Name',
                  widget: 'string',
                },
                {
                  name: 'country',
                  label: 'Country',
                  widget: 'string',
                },
              ],
            },
          ],
        },
      ],
    },
  ],
}
```

:::

You can create a Relation field in another collection to select multiple cities from the `locations` file:

::: code-group

```yaml{5-6} [YAML]
fields:
  - name: favorite_cities
    label: Favorite Cities
    widget: relation
    collection: data
    file: locations
    multiple: true
    min: 1
    max: 3
    value_field: '{{cities.*.name}}'
    display_fields: ['{{cities.*.name}}, {{cities.*.country}}']
    search_fields: ['{{cities.*.name}}']
```

```toml{5-6} [TOML]
[[fields]]
name = "favorite_cities"
label = "Favorite Cities"
widget = "relation"
collection = "data"
file = "locations"
multiple = true
min = 1
max = 3
value_field = "{{cities.*.name}}"
display_fields = ["{{cities.*.name}}, {{cities.*.country}}"]
search_fields = ["{{cities.*.name}}"]
```

```json{7-8} [JSON]
{
  "fields": [
    {
      "name": "favorite_cities",
      "label": "Favorite Cities",
      "widget": "relation",
      "collection": "data",
      "file": "locations",
      "multiple": true,
      "min": 1,
      "max": 3,
      "value_field": "{{cities.*.name}}",
      "display_fields": ["{{cities.*.name}}, {{cities.*.country}}"],
      "search_fields": ["{{cities.*.name}}"]
    }
  ]
}
```

```js{7-8} [JavaScript]
{
  fields: [
    {
      name: 'favorite_cities',
      label: 'Favorite Cities',
      widget: 'relation',
      collection: 'data',
      file: 'locations',
      multiple: true,
      min: 1,
      max: 3,
      value_field: '{{cities.*.name}}',
      display_fields: ['{{cities.*.name}}, {{cities.*.country}}'],
      search_fields: ['{{cities.*.name}}'],
    },
  ],
}
```

:::

Note that a wildcard (`*`) is used in the `value_field`, `display_fields`, and `search_fields` options to reference list items within the `cities` field.

Output example when the selected favorite cities are “San Francisco”, “Tokyo”, and “Paris”:

::: code-group

```yaml [YAML]
favorite_cities:
  - San Francisco
  - Tokyo
  - Paris
```

```toml [TOML]
favorite_cities = ["San Francisco", "Tokyo", "Paris"]
```

```json [JSON]
{
  "favorite_cities": ["San Francisco", "Tokyo", "Paris"]
}
```

:::

### Referencing Entries Across Locales

When [entry slugs are localized](/en/docs/i18n/slugs#localizing-entry-slugs), each localized entry stores the default locale’s slug in an extra `translationKey` property. Unlike `{{slug}}`, that property holds the same value in every locale, so it can be used as the value field to reference an entry regardless of the locale being edited:

::: code-group

```yaml{7} [YAML]
fields:
  - name: parent
    label: Parent Page
    widget: relation
    i18n: true
    collection: pages
    value_field: translationKey
    display_fields: [title]
    search_fields: [title]
```

```toml{7} [TOML]
[[fields]]
name = "parent"
label = "Parent Page"
widget = "relation"
i18n = true
collection = "pages"
value_field = "translationKey"
display_fields = ["title"]
search_fields = ["title"]
```

```json{9} [JSON]
{
  "fields": [
    {
      "name": "parent",
      "label": "Parent Page",
      "widget": "relation",
      "i18n": true,
      "collection": "pages",
      "value_field": "translationKey",
      "display_fields": ["title"],
      "search_fields": ["title"]
    }
  ]
}
```

```js{9} [JavaScript]
{
  fields: [
    {
      name: 'parent',
      label: 'Parent Page',
      widget: 'relation',
      i18n: true,
      collection: 'pages',
      value_field: 'translationKey',
      display_fields: ['title'],
      search_fields: ['title'],
    },
  ],
}
```

:::

The `translationKey` property is not defined as a field, but it’s still a valid value field. If you have renamed the property with the [`i18n.canonical_slug.key`](/en/docs/i18n/slugs#localizing-entry-slugs) option, such as `ref` for Jekyll, use that key instead.
