---
url: /en/docs/data-output.md
description: >-
  Control data output formats in Sveltia CMS with customization options and best
  practices.
---

# Data Output

Content in Sveltia CMS is stored in static files, which can be in various formats such as Markdown, YAML, TOML, or JSON. The format used for storing content can be configured on a per-collection basis.

In most cases, you don’t need to worry about the details of data output, as Sveltia CMS and consuming tools, like your frameworks, static site generators (SSGs) or parser libraries, handle it seamlessly. However, understanding how data is output can help you avoid unexpected issues, especially when using strict type validations or manually editing data files.

## File Formats

### Standard Formats

Sveltia CMS supports the following data output formats for content files out of the box:

* Markdown with YAML, TOML or JSON front matter
* YAML
* TOML
* JSON
* Raw text files, such as plain text, JSON, XML, or CSV files

To customize the format for each collection, see the [Entry Collection File Formats](/en/docs/collections/entries/formats) and [File Collection](/en/docs/collections/files#file-format-and-extension) documentation.

### Custom Formats

Sveltia CMS allows you to define custom data output formats using the API. You can create your own format handlers to meet specific requirements for your project. For more information on how to create custom formats, please refer to the [Custom File Formats API reference](/en/docs/api/file-formats).

## Data Output Conventions

Here are some key aspects of data output in Sveltia CMS:

### General Conventions

* **Field Ordering**: Fields are always saved in the order they are defined in the configuration, with key-value pairs, making Git commits clean and consistent. Some [exceptions](#understanding-exceptions) apply.
* **Time Formatting**: A standard time is formatted as `HH:mm:ss` instead of `HH:mm` for better framework compatibility, including Hugo.
* **File Formatting**: Line breaks are LF (`\n`) across all formats. A newline is added at the end of the file to prevent unnecessary changes.
* **Text Processing**: Leading and trailing whitespaces in text-type field values are automatically removed when an entry is saved. No configuration option is required for this behavior.
* **Complete and Consistent Data Output**: Sveltia CMS saves proper values for all fields, such as an empty string, an empty array, or `null`, instead of omitting them. This differs from Netlify/Decap CMS, which often omits optional and empty fields.
  * `required: false` makes data input optional, but doesn't make data output optional.
  * To omit empty optional fields from data output, use `omit_empty_optional_fields: true` in the [output options](#controlling-data-output). This is useful if you have data type validations that expect `undefined`.

### Format-Specific Conventions

* **YAML String Folding**: YAML string folding (maximum line width) is disabled for improved framework compatibility.
* **Indentation**: Indentation is 2 spaces for YAML and JSON by default (configurable).
* **Quoting in YAML**: Strings in YAML can be unquoted, single-quoted, or double-quoted (configurable).
* **JSON and YAML Formatting Options**: Fully configurable in the [output options](#controlling-data-output).
* **TOML DateTime Values**: DateTime field values in ISO 8601 format are stored in native date/time format instead of quoted strings.

### Markdown Syntax

Due to the underlying [Lexical framework](https://lexical.dev/) used in Sveltia CMS, the following Markdown conventions are applied to the output of the [rich text editor](/en/docs/fields/richtext):

* **Indentation**: 4 spaces for nested lists and code blocks instead of 2 spaces.
* **Unordered List Markers**: Hyphens (`-`) are used for unordered list markers instead of asterisks (`*`).
* **Bold Text**: Double asterisks (`**`) are used for bold text instead of double underscores (`__`).
* **Italic Text**: Underscores (`_`) are used for italics instead of asterisks (`*`).
* **Horizontal Rules**: Three asterisks (`***`) are used for horizontal rules instead of three hyphens (`---`).
* **Line Breaks**: Soft line breaks (single line breaks) are used instead of hard line breaks (two or more spaces, escaped line breaks `\`, or HTML `<br>` tags). In your framework, you may need to [enable the appropriate option](/en/docs/how-tos#rendering-soft-line-breaks-as-hard-line-breaks-in-markdown) to render soft line breaks as hard line breaks.

## Controlling Data Output

Sveltia CMS supports some data output options, including JSON/YAML formatting preferences, at the root level of the configuration file. The default options are listed below:

::: code-group

```yaml [YAML]
output:
  omit_empty_optional_fields: false
  encode_file_path: false # true to URL-encode file paths for File/Image fields
  json:
    indent_style: space # or tab
    indent_size: 2
  yaml:
    quote: none # or single or double
    indent_size: 2
    indent_sequences: true # false for compact style
```

```toml [TOML]
[output]
omit_empty_optional_fields = false
encode_file_path = false # true to URL-encode file paths for File/Image fields
[output.json]
indent_style = "space" # or "tab"
indent_size = 2
[output.yaml]
quote = "none" # or "single" or "double"
indent_size = 2
indent_sequences = true # false for compact style
```

```json [JSON]
{
  "output": {
    "omit_empty_optional_fields": false,
    "encode_file_path": false,
    "json": {
      "indent_style": "space",
      "indent_size": 2
    },
    "yaml": {
      "quote": "none",
      "indent_size": 2,
      "indent_sequences": true
    }
  }
}
```

```js [JavaScript]
{
  output: {
    omit_empty_optional_fields: false,
    encode_file_path: false,
    json: {
      indent_style: 'space',
      indent_size: 2,
    },
    yaml: {
      quote: 'none',
      indent_size: 2,
      indent_sequences: true,
    },
  },
}
```

:::

For JSON, `indent_size` is the number of spaces or tabs per indent level; it defaults to `2` with `indent_style: space` and `1` with `indent_style: tab`. For YAML, `quote: none` leaves string values unquoted unless quotes are required, while `single` and `double` wrap them in single or double quotes.

## Understanding Exceptions

Content is generally saved as key-value pairs in a file, where the key is the field name and the value is the field value. However, there are some exceptions you should be aware of.

### The `body` Field

If the format is front matter, the `body` field is saved outside of the front matter block:

```yaml
---
title: My Post
date: 2025-01-01
---
This is the body of my post.
```

instead of

```yaml
---
title: My Post
date: 2025-01-01
body: This is the body of my post.
---
```

If there is only the `body` field, the front matter block is omitted altogether:

```yaml
This is the body of my post.
```

This behavior can be configured using the [`body_field` option](/en/docs/collections/entries/formats#body-field-for-front-matter-formats) for collections and collection files.

When i18n is enabled with the `single_file` structure, this behavior doesn’t apply at all. In this case, the `body` field is saved as part of key-value pairs under each locale in the front matter block:

```yaml
---
en:
  title: My Post
  date: 2025-01-01
  body: This is the body of my post.
fr:
  title: Mon article
  date: 2025-01-01
  body: C’est le corps de mon article.
---
```

### List Widget

There are two exceptional cases for the List widget:

#### `field` vs. `fields` Option

When the `fields` (plural) option is used, each item is saved as an object with key-value pairs. For example, the following configuration:

::: code-group

```yaml{4-5} [YAML]
- name: images
  label: Images
  widget: list
  fields:
    - { name: image, label: Image, widget: image }
```

```toml{5-8} [TOML]
[[fields]]
name = "images"
label = "Images"
widget = "list"
[[fields.fields]]
name = "image"
label = "Image"
widget = "image"
```

```json{7-9} [JSON]
{
  "fields": [
    {
      "name": "images",
      "label": "Images",
      "widget": "list",
      "fields": [
        { "name": "image", "label": "Image", "widget": "image" }
      ]
    }
  ]
}
```

```js{7-9} [JavaScript]
{
  fields: [
    {
      name: "images",
      label: "Images",
      widget: "list",
      fields: [
        { name: "image", label: "Image", widget: "image" },
      ],
    },
  ],
}
```

:::

will produce the output:

::: code-group

```yaml [YAML]
images:
  - image: https://example.com/image1.jpg
  - image: https://example.com/image2.jpg
```

```toml [TOML]
[[images]]
image = "https://example.com/image1.jpg"
[[images]]
image = "https://example.com/image2.jpg"
```

```json [JSON]
{
  "images": [
    { "image": "https://example.com/image1.jpg" },
    { "image": "https://example.com/image2.jpg" }
  ]
}
```

:::

On the other hand, when the `field` (singular) option is used, the `name` property is omitted from the output.

::: code-group

```yaml{4} [YAML]
- name: images
  label: Images
  widget: list
  field: { name: image, label: Image, widget: image }
```

```toml{5} [TOML]
[[fields]]
name = "images"
label = "Images"
widget = "list"
[fields.field]
name = "image"
label = "Image"
widget = "image"
```

```json{7} [JSON]
{
  "fields": [
    {
      "name": "images",
      "label": "Images",
      "widget": "list",
      "field": { "name": "image", "label": "Image", "widget": "image" }
    }
  ]
}
```

```js{7} [JavaScript]
{
  fields: [
    {
      name: "images",
      label: "Images",
      widget: "list",
      field: { name: "image", label: "Image", widget: "image" },
    },
  ],
}
```

:::

The output will be:

::: code-group

```yaml [YAML]
images:
  - https://example.com/image1.jpg
  - https://example.com/image2.jpg
```

```toml [TOML]
images = ["https://example.com/image1.jpg", "https://example.com/image2.jpg"]
```

```json [JSON]
{
  "images": ["https://example.com/image1.jpg", "https://example.com/image2.jpg"]
}
```

:::

#### `root` Option

When the [`root` option](/en/docs/fields/list#top-level-list) is set to `true`, the List field is saved as a top-level list without a field name:

::: code-group

```yaml [YAML]
- name: John Doe
  id: 12345
- name: Jane Smith
  id: 67890
```

```json [JSON]
[
  { "name": "John Doe", "id": 12345 },
  { "name": "Jane Smith", "id": 67890 }
]
```

:::

instead of

::: code-group

```yaml [YAML]
members:
  - name: John Doe
    id: 12345
  - name: Jane Smith
    id: 67890
```

```json [JSON]
{
  "members": [
    { "name": "John Doe", "id": 12345 },
    { "name": "Jane Smith", "id": 67890 }
  ]
}
```

:::

This `root` option doesn’t work with TOML format, as TOML doesn’t support top-level arrays.
