---
url: /en/docs/collections/entries/single-file.md
description: >-
  Store all the entries of a Sveltia CMS entry collection in a single JSON file,
  as an array of objects that editors can add to, edit, delete and reorder.
---

# Single-File Collections

An entry collection normally stores each entry in a file of its own. With the `file` option instead of `folder`, all the entries are stored in one JSON file, as an array of objects. This suits sites that read their content from a data file, such as a vanilla JavaScript site fetching a list of team members, products or links, or a static site generator’s data file.

::: tip

Sveltia CMS can also edit such a file as a single entry, with a [top-level List field](/en/docs/fields/list#top-level-list) in a file collection. Use that instead if the list is short and edited as a whole, e.g. a navigation menu, or if the file isn’t in JSON format.

:::

## Creating a Single-File Collection

Here is an example configuration for a list of team members:

::: code-group

```yaml [YAML]{5}
collections:
  - name: members
    label: Team Members
    label_singular: Team Member
    file: /data/members.json
    identifier_field: name
    fields:
      - { name: id, label: ID }
      - { name: name, label: Name }
      - { name: role, label: Role, required: false }
      - { name: photo, label: Photo, widget: image, required: false }
```

```toml [TOML]{5}
[[collections]]
name = "members"
label = "Team Members"
label_singular = "Team Member"
file = "/data/members.json"
identifier_field = "name"

[[collections.fields]]
name = "id"
label = "ID"

[[collections.fields]]
name = "name"
label = "Name"

[[collections.fields]]
name = "role"
label = "Role"
required = false

[[collections.fields]]
name = "photo"
label = "Photo"
widget = "image"
required = false
```

```json [JSON]{7}
{
  "collections": [
    {
      "name": "members",
      "label": "Team Members",
      "label_singular": "Team Member",
      "file": "/data/members.json",
      "identifier_field": "name",
      "fields": [
        { "name": "id", "label": "ID" },
        { "name": "name", "label": "Name" },
        { "name": "role", "label": "Role", "required": false },
        { "name": "photo", "label": "Photo", "widget": "image", "required": false }
      ]
    }
  ]
}
```

```js [JavaScript]{7}
{
  collections: [
    {
      name: "members",
      label: "Team Members",
      label_singular: "Team Member",
      file: "/data/members.json",
      identifier_field: "name",
      fields: [
        { name: "id", label: "ID" },
        { name: "name", label: "Name" },
        { name: "role", label: "Role", required: false },
        { name: "photo", label: "Photo", widget: "image", required: false },
      ],
    },
  ],
}
```

:::

The file then looks like this, with one object for each entry:

```json
[
  { "id": "alice", "name": "Alice", "role": "Chair" },
  { "id": "bob", "name": "Bob", "role": "Treasurer" }
]
```

The `file` option is a path to a `.json` file, relative to the repository’s root directory. JSON is the only supported format, so the `format` option can only be `json`, if set. The `folder` and `file` options can’t be used together.

The file doesn’t have to exist yet: it’s created when the first entry is saved.

## How It Works

* Each object in the array is an entry. The entries are listed in the order of the array.
* A new entry is added to the end of the array.
* Deleting an entry removes its object from the array.
* The entries can always be [reordered](/en/docs/collections/entries/operations#reordering-entries) with the drag-and-drop UI, without the `reorder` option. The objects are moved within the array, and no `order` field is written.
* Saving an entry rewrites the whole file, but only the object of that entry changes. Items that aren’t objects, and properties that aren’t defined as fields, are kept as they are.

Other entry collection options, such as `create`, `delete`, `duplicate`, `limit`, `filter`, `summary`, `sortable_fields`, `view_filters`, `view_groups` and `media_folder`, work as usual. A relative `media_folder` is relative to the folder of the file. As all the entries share that folder and can use any image in it, images are not deleted along with an entry.

## Unsupported Options

The following entry collection options assume one file per entry, so they can’t be used with the `file` option, and the configuration is reported as invalid if they are:

* `extension`, `path`, `slug` and `slug_length`
* `nested` and `meta`
* `index_file`
* `reorder`, as the entries can always be reordered

Editorial Workflow is not supported either. The collection can’t use the `editorial_workflow` [publish mode](/en/docs/workflows/editorial), and Open Authoring can’t be enabled. If Editorial Workflow is enabled for the whole site, set the collection’s `publish_mode` option to `simple`. For the same reason, a Relation field in the collection can’t refer to a collection that uses Editorial Workflow, as renaming or deleting an entry there would update the references to it in a pull request.

## Internationalization

With [i18n](/en/docs/i18n) enabled for the collection, each object holds all the translations, like a file with the [`single_file` structure](/en/docs/i18n/structures#single-file) does, whatever structure is configured for the site:

```json
[
  {
    "en": { "name": "Alice", "role": "Chair" },
    "fr": { "name": "Alice", "role": "Direction" }
  }
]
```

If the [`single_file_default_root` structure](/en/docs/i18n/structures#single-file-default-root) is configured, the default locale’s fields are stored at the top level of each object instead. The `{{locale}}` placeholder can’t be used in the file path.

## Identifying Entries

An entry is identified by its position in the array, which serves as its slug: `0` for the first entry, `1` for the second, and so on. The position changes when the entries are reordered or one is deleted, so the slug can’t be used to refer to an entry from elsewhere:

* A [Relation field](/en/docs/fields/relation) referring to the collection must store a field value with the `value_field` option, preferably a field with a unique value like `id` in the example above. The default `{{slug}}` value is reported as invalid.
* The `preview_path` and `thumbnail` options can’t contain the `{{slug}}` tag. Use a field instead, e.g. `/team/{{id}}`.
* The URL of an entry in the CMS points to its position, so a bookmarked entry may open another one after a reorder.
* Unsaved changes are not backed up in the browser, as a backup could otherwise be restored to another entry.

The commit author and date of an entry are those of the file’s last commit, which may be about another entry, so the entries can’t be sorted by them.

## Editing at the Same Time

::: warning Risk of data loss

All the entries are stored in one file, and Sveltia CMS doesn’t lock entries while someone edits them. Keep the following in mind when several people edit the same collection.

:::

Before saving, Sveltia CMS checks the repository for changes made by someone else, then applies only the user’s change to the file as it is now. A colleague’s change to another entry is kept.

The save is refused if the entry being edited has been changed or deleted in the meantime, or another entry has moved to its position because entries were added, deleted or reordered. The user is then asked to cancel editing and open the entry again from the list to make the edits. Unlike an entry stored in a file of its own, the user can’t save over the other change, as the entry at the same position may be a different one. Deleting or reordering entries is refused the same way.

There is still a short window between the check and the commit itself:

* With GitHub, the commit is rejected if someone else has committed in between, and the user can save again.
* With Gitea/Forgejo, the commit is rejected if the file has changed in between.
* With GitLab, the other commit is overwritten, and the change made in it is lost. If several people edit a large file frequently, consider taking turns, or split the content into several collections.

As the file changes with every save, its commit history covers all the entries, and the History panel in the Content Editor’s sidebar lists every commit made to the file.
