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 and File Collection 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.
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 apply.
- Time Formatting: A standard time is formatted as
HH:mm:ssinstead ofHH:mmfor better framework compatibility. - 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 you save an entry. 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: falsemakes data input optional, but doesn't make data output optional.- To omit empty optional fields from data output, use
omit_empty_optional_fields: truein the output options. This is useful if you have data type validations that expectundefined.
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.
- 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 used in Sveltia CMS, the following Markdown conventions are applied to the output of the rich text editor:
- 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 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:
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[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{
"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
}
}
}{
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,
},
},
}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:
---
title: My Post
date: 2025-01-01
---
This is the body of my post.instead of
---
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:
This is the body of my post.However, this doesn’t apply when i18n is enabled with the single_file structure. In this case, the body field is saved as part of key-value pairs under each locale in the front matter block:
---
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:
- name: images
label: Images
widget: list
fields:
- { name: image, label: Image, widget: image }[[fields]]
name = "images"
label = "Images"
widget = "list"
[[fields.fields]]
name = "image"
label = "Image"
widget = "image"{
"fields": [
{
"name": "images",
"label": "Images",
"widget": "list",
"fields": [
{ "name": "image", "label": "Image", "widget": "image" }
]
}
]
}{
fields: [
{
name: "images",
label: "Images",
widget: "list",
fields: [
{ name: "image", label: "Image", widget: "image" },
],
},
],
}will produce the output:
images:
- image: https://example.com/image1.jpg
- image: https://example.com/image2.jpg[[images]]
image = "https://example.com/image1.jpg"
[[images]]
image = "https://example.com/image2.jpg"{
"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.
- name: images
label: Images
widget: list
field: { name: image, label: Image, widget: image }[[fields]]
name = "images"
label = "Images"
widget = "list"
[fields.field]
name = "image"
label = "Image"
widget = "image"{
"fields": [
{
"name": "images",
"label": "Images",
"widget": "list",
"field": { "name": "image", "label": "Image", "widget": "image" }
}
]
}{
fields: [
{
name: "images",
label: "Images",
widget: "list",
field: { name: "image", label: "Image", widget: "image" },
},
],
}The output will be:
images:
- https://example.com/image1.jpg
- https://example.com/image2.jpgimages = ["https://example.com/image1.jpg", "https://example.com/image2.jpg"]{
"images": ["https://example.com/image1.jpg", "https://example.com/image2.jpg"]
}root Option
When the root option is set to true, the List field is saved as a top-level list without a field name:
- name: John Doe
id: 12345
- name: Jane Smith
id: 67890[
{ "name": "John Doe", "id": 12345 },
{ "name": "Jane Smith", "id": 67890 }
]instead of
members:
- name: John Doe
id: 12345
- name: Jane Smith
id: 67890{
"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.