Sveltia CMS is a Git-based lightweight headless CMS under active development as a modern, powerful, quick replacement for Netlify CMS and Decap CMS. In some simple cases, migration is as easy as a single line of code change, although we are still working on improving compatibility.
The free, open source alternative to Netlify/Decap CMS is now in public beta, turbocharged with great UX, performance, i18n support and so many more enhancements.
Sveltia CMS was born in November 2022, when the progress of Netlify CMS was stalled for more than six months. @kyoshino’s clients wanted to replace their Netlify CMS instances without much effort, mainly to get better internationalization (i18n) support.
To achieve radical improvements in UX, performance, i18n and other areas, it was ultimately decided to build an alternative from the ground up, while ensuring an easy migration path from the other. After proving the concept with a rapid Svelte prototype, development was accelerated to address their primary use cases. The new product has since been named Sveltia CMS and released as open source software to encourage wider adoption.
We loved the concept of Netlify CMS — turning a Git repository into a database with a single page app served from a CDN plus a plain YAML config file — and we wanted to revive it, modernize it, and take it to the next level.
Due to its unfortunate abandonment in early 2022, Netlify CMS spawned 3 successors:
Sveltia CMS is the only project that doesn’t inherit the complexity, technical debt and numerous bugs of Netlify CMS, which was launched back in 2015. We are confident that our decision to rebuild the application from scratch was the right one, as proven by the hundreds of improvements we have already made.
While Sveltia CMS is specifically designed to replace legacy Netlify CMS instances, it also aims to serve as a substitute for the other Netlify CMS successors. We hope that, especially with the robust i18n support, our product will eventually become an attractive choice for anyone looking for a free headless CMS.
Sveltia CMS is currently in beta and version 1.0 is expected to ship in early 2025, in time for the 10th anniversary of Netlify CMS development. Check our release notes for updates. See also our roadmap.
While we fix reported bugs as quickly as possible, usually within 24 hours, our overall progress may be slower than you think. The thing is, it’s not just a personal project of @kyoshino, but also involves different kinds of activities that require considerable effort:
We hope Netlify/Decap CMS users will be pleased and surprised by the hundreds of small and large improvements we have made. Here’s what makes Sveltia CMS different. Look how serious we are!
search
configuration option is therefore ignored). It also avoids the slowness and potential API rate limit violations caused by hundreds of requests with Relation widgets.[^14]publish_mode
,[^75] and an unused logo_url
.[^49]Ctrl+S
(Windows/Linux) or Command+S
(macOS) key to save your time.pnpm audit
, and frequent releases, unlike Netlify/Decap CMS where a number of high severity vulnerabilities are unpatched.[^33]unsafe-eval
and unsafe-inline
keywords are not needed in the script-src
CSP directive.[^34]same-origin
referrer policy is automatically set with a <meta>
tag./admin
) depending on the configuration. In such cases, the config file is loaded from a root-relative URL (/admin/config.yml
) instead of a regular relative URL (./config.yml
= /config.yml
) that results in a 404 Not Found error.[^107]use_graphql
option to enable it for GitHub and GitLab.main
, master
or whatever) if not specified in the configuration file, preventing data loading errors due to a hardcoded fallback to master
.[^95][^27]Sveltia CMS has been built with a multilingual architecture from the very beginning. You can expect best-in-class internationalization (i18n) support, as it’s required by clients of maintainer @kyoshino, who himself was a long-time Japanese localizer for Mozilla and currently lives in one of the most multicultural cities in the world where 150+ languages are spoken.
{{locale}}
template tag in the file
path option, e.g. content/pages/about.{{locale}}.json
or content/pages/{{locale}}/about.json
. For backward compatibility, the global structure
option only applies to folder collections, and the default i18n structure for file collections remains single file.i18n: duplicate
field configuration so that changes made with these widgets are duplicated between locales.[^7][^68] The i18n
configuration can normally be used for the subfields.required
field option accepts an array of locale codes in addition to a boolean, making the field required for a subset of locales when i18n support is enabled. For example, if only English is required, you could write required: [en]
. An empty array is equivalent to required: false
.multiple_folders
i18n structure.[^21]{{locale}}
template tag can be used in the preview_path
collection option to provide site preview links for each language.[^63]translationKey
.[^81]clean_accents
option is enabled for entry slugs, certain characters, such as German umlauts, will be transliterated.[^99]widget: hidden
along with default: '{{locale}}'
.[^101]DE
as German, NL
as Dutch, ZH
as Chinese, and so on.single_file
structure is used and a required field is not filled in any of the locales.[^55]icon
: Choose a custom icon for each collection.[^3]divider
: Add dividers to the collection list.thumbnail
: Specify the field name for a thumbnail displayed on the entry list, like thumbnail: featuredImage
.[^130]heroImage.src
.images.*.src
.[thumbnail, cover]
.filter
option for folder collections:value
works as expected.[^93]value
accepts null
to match an undefined field value.value
accepts an array to provide multiple possible values.[^151]pattern
can be used instead of value
to provide a regular expression, just like the view_filters
collection option.[^153]summary
:slug
collection option[^29]summary
field option for the List and Object widgets{{title | upper | truncate(20)}}
.date
transformation supports the time zone argument. The only available value is utc
, which converts a date to UTC. This is useful if the specified DateTime field is local, but you want to force UTC in the entry slug, e.g. {{date | date('YYYYMMDD-HHmm', 'utc')}}
. (Discussion)path
option for a folder collection, e.g. {{fields.state.name}}/{{slug}}
.[^62]description
collection option.[^79] Bold, italic, strikethrough, code and links are allowed.folder
can be an empty string (or .
or /
) if you want to store entries in the root folder. This supports a typical VitePress setup.body
field, an entry slug will be generated from a header in the body
, if exists. This supports a typical VitePress setup.sanitize_replacement
(default: hyphen) rather than being removed.[^52]slug_length
collection option to avoid deployment errors with Netlify or other platforms.[^25]path
doesn’t affect the entry slugs stored with the Relation widget.[^137]_index.md
files, including localized ones like _index.en.md
, are ignored in folder collections unless the path
option is configured to end with _index
and the extension
is md
.[^120] You can still manage these files as part of a file collection if necessary.title
field.[^152] In that case, an entry summary will be generated from a header in the Markdown body
field, if exists, or from the entry slug, so the summary will never be an empty.[^161] This supports a typical VitePress setup.summary
, such as title
, the entry list displays an updated summary after you save the entry.[^159]create: true
option on a file collection because it’s useless.[^89]delete: true
option on a file collection because the preconfigured files should not be deleted.pattern
option.[^82] For example, if you want to allow 280 characters or less in a multiline text field, you could write /^.{0,280}$/s
(but you can now use the maxlength
option instead.)preview: false
.[^126]null
, instead of nothing (undefined
), regardless of the required
field option.[^45][^46][^44][^157]required: false
makes data input optional, but doesn’t make data output optional.omit_empty_optional_fields: true
in the data output options. This is useful if you have data type validations that expect undefined
.[^156]yaml_quote
collection option added in v0.5.10 is now deprecated and will be removed in v1.0.0. yaml_quote: true
is equivalent to quote: double
in the new YAML format options.false
by default, without raising a confusing validation error.[^45]false
by default, rather than nothing.[^46]rgb()
function notation.picker_utc
option is true
.[^150]default
value supports the following template tags:{{locale}}
: The current locale code.[^101]{{datetime}}
: The current date/time in ISO 8601 format.[^102]{{uuid}}
, {{uuid_short}}
and {{uuid_shorter}}
: A random UUID or its shorter version, just like the slug template tags.[^12]default
value is saved when you create a file collection item, not just a folder collection item.[^78]root
option.[^148]min
and max
options can be used separately. You don’t need to specify both to use either option.[^145]add_to_top
option is not true
, so you don’t have to scroll up each time to add new items.default
value.[^162]fields
in a variable type object.[^163] In that case only the typeKey
(default: type
) is saved in the output.modes
option.[^58] If you want to use the plain text editor by default, add modes: [raw, rich_text]
to the field configuration.image
component can be inserted with a single click.image
component allows users to add, edit or remove a link on an image.[^171]code-block
component is implemented just like a blockquote. You can simply convert a normal paragraph into a code block instead of adding a component.value_type
option is int
(default) or float
, the required
option is false
, and the value is not entered, the field will be saved as null
instead of an empty string.[^157] If value_type
is anything else, the data type will remain a string.types
option) just like the List widget.required: false
) can be manually added or removed with a checkbox.[^88] If unadded or removed, the required subfields won’t trigger validation errors,[^16] and the field will be saved as null
.options_length
option, which defaults to 20, is therefore ignored.[^76]slug
can be used for value_field
to show all available options instead of just one in some situations.[^91]{{cities.*.name}}
can also be used for value_field
.[^94]display_fields
is displayed in the Preview pane instead of value_field
.search_fields
option is not required in Sveltia CMS, as it defaults to display_fields
(and value_field
).0
.[^56]label
is displayed in the Preview pane instead of value
.type
option that accepts url
or email
as a value, which will validate the value as a URL or email.prefix
and suffix
string options, which automatically prepend and/or append the developer-defined value to the user-input value.before_input
and after_input
string options, which allow developers to display custom labels before and/or after the input UI.[^28] Markdown is supported in the value.prefix
and suffix
, respectively, which have different meaning in Sveltia CMS.public_folder
contains {{slug}}
and you’ve edited a slug field (e.g. title
) of a new entry after uploading an asset, the updated slug will be used in the saved asset path.[^140] Other dynamic template tags such as {{filename}}
will also be populated as expected.[^141]summary
is displayed correctly when it refers to a Relation field[^36] or a simple List field.summary
template tags support transformations, e.g. {{fields.date | date('YYYY-MM-DD')}}
.dropdown_threshold
option for the relation
and select
widgets.minlength
and maxlength
options, which allow developers to specify the minimum and maximum number of characters required for input without having to write a custom regular expression with the pattern
option. A character counter is available when one of the options is given, and a user-friendly validation error is displayed if the condition is not met.compute
widget allows to reference the value of other fields in the same collection, similar to the summary
property for the List and Object widgets.[^104] Use the value
property to define the value template, e.g. posts-{{fields.slug}}
(example).value
property also supports a value of {{index}}
, which can hold the index of a list item (example).keyvalue
widget allows users to add arbitrary key-value string pairs to a field.[^123]uuid
widget with the following properties:[^12]prefix
: A string to be prepended to the value. Default: an empty string.use_b32_encoding
: Whether to encode the value with Base32. Default: false
.read_only
: Whether to make the field read-only. Default: true
./
as expected.[^48]media_folder
can be an empty string (or .
or /
) if you want to store assets in the root folder.logo_url
property is displayed on the global application header and the browser tab (favicon).[^134] A smaller logo is also correctly positioned on the authentication page.[^135]CMS.registerCustomFormat()
supports async parser/formatter functions.[^149]locale
configuration option is ignored and CMS.registerLocale()
is not required.label
and label_singular
are not converted to lowercase, which is especially problematic in German, where all nouns are capitalized.[^98]We are trying to make Sveltia CMS compatible with Netlify/Decap CMS where possible, so that more users can seamlessly switch to our modern alternative. It’s ready to be used as a drop-in replacement for Netlify/Decap CMS in some casual use case scenarios with a single line of code update.
However, 100% feature parity is not planned, and some features are still missing or will not be added due to performance, deprecation and other factors. Look at the compatibility info below to see if you can migrate now or in the near future.
time_format: false
option instead.window.CMS
object will not be implemented. This includes custom backends and custom media libraries, if any. We may support these features in the future, but our implementation would likely be incompatible with Netlify/Decap CMS.These limitations are expected to be resolved before the 1.0 release scheduled for early 2025:
Feature | Status in Sveltia CMS |
---|---|
Backends | The Test backend needed for our demo site is not yet added. We’ll see if Azure DevOps can also be supported. |
Configuration | Comprehensive config validation is not yet implemented. |
Localization | The application UI is only available in English and Japanese at this time. |
Media Libraries | Cloudinary and Uploadcare are not yet supported. |
Widgets | Custom widgets are not yet supported. See the table below for other limitations. |
Customization | Custom previews and event subscriptions are not yet supported. |
Widget | Status in Sveltia CMS |
---|---|
Code | Coming soon. |
DateTime | The date_format and time_format options with Moment.js tokens are not yet supported. Note that Decap CMS 3.1.1 replaced Moment.js with Day.js, and Decap CMS 3.3.0 made other changes to the widget behaviour; we’ll follow these changes where it makes sense. |
File / Image | Field-specific media folders (beta) and media library options are not yet supported other than media_library.config.max_file_size for the default media library. |
Map | Coming soon. |
Markdown | Custom components are not yet supported. There is no language selector yet in the built-in code-block component. |
Due to the complexity, the following features are planned for after the 1.0 release. Netlify/Decap CMS has a number of open issues with these advanced features and we want to implement them the right way.
We plan to provide partial compatibility with Static CMS, a now-defunct fork of Netlify CMS. This README will be updated with more details as our development progresses.
default
option for sortable fields is implemented in Sveltia CMS.media_folder
s, these folders will be displayed in the Asset Library and Select File/Image dialog. Display of subfolders within a configured folder will be implemented soon. We don’t plan to support the folder_support
and display_in_navigation
options for media_library
; subfolders will be displayed with no configuration. (#301)logo_link
global option will not be supported. Use display_url
or site_url
instead.yaml
global option will not be supported, as Sveltia CMS doesn’t expose the yaml
library options directly for forward compatibility reasons. However, we do have some data output options, including YAML indentation and quotes.enforce_required_non_default
i18n option will not be supported. Sveitia CMS enforces required fields in all locales by default. However, the save_all_locales
i18n option allows users to disable non-default locales if needed. Developers can also specify a subset of locales with the required
field option, e.g. required: [en]
.prefix
and suffix
options for the Boolean, Number and String widgets are implemented as before_input
and after_input
in Sveltia CMS. Our prefix
and suffix
options for the String widget are literally a prefix and suffix to the value.multiple
option for the File and Image widgets will be implemented in Sveltia CMS soon. (#10)CMS.registerIcon()
will not be supported, as Sveltia CMS includes the Material Symbols font for custom collection icons that doesn’t require manual registration.localhost
or 127.0.0.1
URLs. If you’re running a remote server yourself and the content is served over HTTP, get a TLS certificate from Let’s Encrypt.Currently, Sveltia CMS is primarily intended for existing Netlify/Decap CMS users. If you don’t have it yet, follow their documentation to add it to your site and create a configuration file first. Make sure you choose the GitHub or GitLab backend (and ignore the Choosing a Backend page). Then migrate to Sveltia CMS as described below.
As the product evolves, we’ll implement a built-in configuration editor and provide comprehensive documentation to make it easier for everyone to get started with Sveltia CMS.
Here are some starter kits for popular frameworks created by community members. More to follow!
Alternatively, you can probably use one of the Netlify/Decap CMS templates and make a quick migration to Sveltia CMS.
Have a look at the compatibility info above first. If you’re already using Netlify/Decap CMS with the GitHub or GitLab backend and don’t have any unsupported features like custom widgets or nested collections, migrating to Sveltia CMS is super easy — it works as a drop-in replacement. Edit /admin/index.html
to replace the CMS <script>
tag, and push the change to your repository. Your new <script>
tag is:
<script src="https://unpkg.com/@sveltia/cms/dist/sveltia-cms.js"></script>
From Netlify CMS:
-<script src="https://unpkg.com/netlify-cms@^2.0.0/dist/netlify-cms.js"></script>
+<script src="https://unpkg.com/@sveltia/cms/dist/sveltia-cms.js"></script>
From Decap CMS:
-<script src="https://unpkg.com/decap-cms@^3.0.0/dist/decap-cms.js"></script>
+<script src="https://unpkg.com/@sveltia/cms/dist/sveltia-cms.js"></script>
That’s it! You can open https://[hostname]/admin/
as before to start editing. There is even no authentication process if you’ve already been signed in with GitHub or GitLab on Netlify/Decap CMS because Sveltia CMS uses your auth token stored in the browser. Simple enough!
That said, we strongly recommend testing your new Sveltia CMS instance first on your local machine. See below for how.
Sveltia CMS does not support the Git Gateway backend due to performance limitations. If you don’t care about user management with Netlify Identity, you can use the GitHub or GitLab backend instead. Make sure you install an OAuth client on GitHub or GitLab in addition to updating your configuration file. As noted in the document, Netlify is still able to facilitate the auth flow.
To allow multiple users to edit content, simply invite people to your GitHub repository with the write role assigned.
Once you have migrated from the Git Gateway and Netlify Identity combo, you can remove the Netlify Identity widget script tag from your HTML:
-<script src="https://identity.netlify.com/v1/netlify-identity-widget.js"></script>
If you want to stay with Netlify Identity, unfortunately you can’t migrate to Sveltia CMS right now. We plan to develop an alternative to Git Gateway and Netlify Identity Widget in the future.
For advanced users, we have also made the bundle available as an npm package. You can install it by running npm i @sveltia/cms
or pnpm add @sveltia/cms
on your project. The manual initialization flow with the init
method is the same as for Netlify/Decap CMS.
Updating Sveltia CMS is transparent, unless you include a specific version in the <script>
source URL or use the npm package. Whenever you (re)load the CMS, the latest version will be served via UNPKG. The CMS also periodically checks for updates and notifies you when a new version is available. After the product reaches GA, you could use a semantic version range (^1.0.0
) like Netlify/Decap CMS.
If you’ve chosen to install with npm, updating the package is your responsibility. We recommend using ncu
or a service like Dependabot to keep dependencies up to date, otherwise you’ll miss important bug fixes and new features.
You can host your Sveltia CMS-managed site anywhere, such as Cloudflare Pages or GitHub Pages. But moving away from Netlify means you can no longer sign in with GitHub or GitLab via Netlify. Instead, you can use our own OAuth client, which can be easily deployed to Cloudflare Workers, or any other 3rd party client made for Netlify/Decap CMS.
Sveltia CMS supports a configuration file written in the JSON format in addition to the standard YAML format. This allows developers to programmatically generate the CMS configuration to enable bulk or complex collections. To do this, simply add a <link>
tag to your HTML, just like a custom YAML config link, but with the type application/json
:
<link href="path/to/config.json" type="application/json" rel="cms-config-url" />
Alternatively, you can manually initialize the CMS with a JavaScript configuration object.
If you get an “Authentication Aborted” error when trying to sign in to GitHub or GitLab using the authorization code flow, you may need to check your site’s Cross-Origin-Opener-Policy
. The COOP header is not widely used, but it’s known to break the OAuth flow with a popup window. If that’s your case, changing same-origin
to same-origin-allow-popups
solves the problem. (Discussion)
Sveltia CMS has simplified the local repository workflow by removing the need for additional configuration (the local_backend
property) and a proxy server (netlify-cms-proxy-server
or decap-server
), thanks to the File System Access API available in some modern browsers.
Here are the workflow steps and tips:
name: git-gateway
won’t work. You’ll need either name: github
or name: gitlab
along with the repo
definition. If you haven’t determined your repository name yet, just use a tentative name.npm run dev
or pnpm dev
.http://localhost:[port]/admin/index.html
with Chrome or Edge.127.0.0.1
addresses can also be used instead of localhost
./admin/
, use the appropriate path.git init
) or GUI, and the hidden .git
folder exists.http://localhost:[port]/
to check the rendered pages.git diff
or a GUI like GitHub Desktop to see if the produced changes look good.Note that, as with Netlify/Decap CMS, the local repository support in Sveltia CMS doesn’t perform any Git operations. You’ll have to manually fetch, pull, commit and push all changes using a Git client. In the future, we’ll figure out if there’s a way to commit in a browser, because the proxy server actually has the undocumented, experimental git
mode that creates commits to a local repository.[^131]
You will also need to reload the CMS after making changes to the configuration file or retrieving remote updates. This manual work will hopefully be unnecessary once the proposed FileSystemObserver
API, which is being implemented in Chromium behind a flag, becomes available.
If you have migrated from Netlify/Decap CMS and are happy with the local repository workflow of Sveltia CMS, you can remove the local_backend
property from your configuration and uninstall the proxy server. If you have configured a custom port number with the .env
file, you can remove it as well.
In the Brave browser, you must enable the File System Access API with an experiment flag to take advantage of the local repository workflow.
brave://flags/#file-system-access-api
in a new browser tab.You can specify an icon for each collection for easy identification in the collection list. You don’t need to install a custom icon set because the Material Symbols font file is already loaded for the application UI. Just pick one of the 2,500+ icons:
config.yml
as the new icon
property, like the example below. - name: tags
label: Tags
+ icon: sell
create: true
folder: data/tags/
Sveltia CMS allows developers to add dividers to the collection list to distinguish different types of collections. To do this, insert a fake collection with the divider: true
option along with a random, unique name
. In VS Code, you may get a validation error if config.yml
is treated as a “Netlify YAML config” file. You can work around this by adding an empty files
list as well:
collections:
- name: products
...
- divider: true
name: d1 # d2, d3, etc. Should be unique for each divider
files: []
- name: pages
...
This is actually not new in Sveltia CMS but rather an undocumented feature in Netlify/Decap CMS.[^4] You can specify media and public folders for each collection that override the global media folder. Well, it’s documented, but that’s probably not what you want.
Rather, if you’d like to add all the media files for a collection in one single folder, specify both media_folder
and public_folder
instead of leaving them empty. The trick is to use an absolute path for media_folder
like the example below. You can try this with Netlify/Decap CMS first if you prefer.
media_folder: static/media
public_folder: /media
collections:
- name: products
label: Products
create: true
folder: data/products/
+ media_folder: /static/media/products # start with a slash
+ public_folder: /media/products
In Sveltia CMS, those collection media folders are displayed prominently for easier asset management. We recommend setting media_folder
and public_folder
for each collection if it contains one or more File/Image fields.
Sveltia CMS has extended the sortable_fields
collection option to allow developers to define the field name and direction to be used for sorting entries by default. Our implementation is compatible with Static CMS. This is especially useful if you want to sort entries by date from new to old:
collections:
- name: posts
sortable_fields:
fields: [title, published_date, author]
default:
field: published_date
direction: descending # default: ascending
For backward compatibility with Netlify/Decap CMS, sortable_fields
with a field list (an array) will continue to work.
For backward compatibility with Static CMS, the direction
option accepts title case values: Ascending
and Descending
. However, None
is not supported and has the same effect as ascending
.
Alt+1
Alt+2
Ctrl+F
(Windows/Linux) or Command+F
(macOS)Ctrl+E
(Windows/Linux) or Command+E
(macOS)Ctrl+S
(Windows/Linux) or Command+S
(macOS)Escape
Standard keyboard shortcuts are also available in the Markdown editor, including Ctrl+B
/Command+B
for bold text, Ctrl+I
/Command+I
for italics, and Tab
to indent a list item.
Sveltia CMS comes with a handy DeepL integration so that you can translate any text field from another locale without leaving the Content Editor. To enable the high quality, AI-powered, quick translation feature:
Note that the Translation button on the pane header only translates empty fields, while in-field Translation buttons override any filled text.
If you have upgraded to DeepL API Pro, provide your new Authentication Key:
:fx
with the new paid API key in the DeepL API Authentication Key field.In Sveltia CMS, it’s possible to localize entry slugs (filenames) if the i18n structure is multiple_files
or multiple_folders
. All you need is the localize
filter for slug
template tags:
i18n:
structure: multiple_folders
locales: [en, fr]
slug:
encoding: ascii
clean_accents: true
collections:
- name: posts
label: Blog posts
create: true
folder: data/posts/
slug: '{{title | localize}}' # This does the trick
format: yaml
i18n: true
fields:
- name: title
label: Title
widget: string
i18n: true
With this configuration, an entry is saved with localized filenames, while the default locale’s slug is stored in each file as an extra translationKey
property, which is used in Hugo’s multilingual support. Sveltia CMS and Hugo read this property to link localized files.
data/posts/en/my-trip-to-new-york.yaml
translationKey: my-trip-to-new-york
title: My trip to New York
data/posts/fr/mon-voyage-a-new-york.yaml
translationKey: my-trip-to-new-york
title: Mon voyage à New York
You can customize the property name and value for a different framework or i18n library by adding the canonical_slug
option to your top-level or collection-level i18n
configuration. The example below is for @astrolicious/i18n, which requires a locale prefix in the value (discussion):
i18n:
canonical_slug:
key: defaultLocaleVersion # default: translationKey
value: 'en/{{slug}}' # default: {{slug}}
For Jekyll, you may want to use the ref
property:
i18n:
canonical_slug:
key: ref
You can disable output of content in selected non-default locales by adding the save_all_locales
property to the top-level or collection-level i18n
configuration. Then you’ll find “Disable (locale name)” in the three-dot menu in the top right corner of the Content Editor. This is useful if the translation isn’t ready yet, but you want to publish the default locale content first.
With the following configuration, you can disable the French and/or German translation while writing in English.
i18n:
structure: multiple_files
locales: [en, fr, de]
default_locale: en
+ save_all_locales: false
By default, the slug for a new entry file will be generated based on the entry’s title
field. Or, you can specify the collection’s slug
option to use the file creation date or other fields. While the behaviour is generally acceptable and SEO-friendly, it’s not useful if the title might change later or if it contains non-Latin characters like Chinese. In Sveltia CMS, you can easily generate a random UUID for a slug without a custom widget!
It’s simple — just specify {{uuid}}
(full UUID v4), {{uuid_short}}
(last 12 characters only) or {{uuid_shorter}}
(first 8 characters only) in the slug
option. The results would look like 4fc0917c-8aea-4ad5-a476-392bdcf3b642
, 392bdcf3b642
and 4fc0917c
, respectively.
- name: members
label: Members
create: true
folder: data/members/
+ slug: '{{uuid_short}}'
Sveltia CMS allows you to edit and save a list at the top-level of a data file, without a field name. All you need to do is create a single List field with the new root
option set to true
. The configuration below reproduces this Jekyll data file example:
collections:
- name: data
label: Data Files
files:
- name: members
label: Member List
file: _data/members.yml
fields:
- name: members
label: Members
label_singular: Member
widget: list
root: true # This does the trick
fields:
- name: name
label: Name
- name: github
label: GitHub account
Note: The root
option is ignored if the collection or collection file contains multiple fields. You can still have subfields under the List field.
Sveltia CMS supports some data output options, including JSON/YAML formatting preferences, in the configuration file. The default options are listed below:
output:
omit_empty_optional_fields: false
json:
indent_style: space # or tab
indent_size: 2
yaml:
quote: none # or single or double
indent_size: 2
You may already have a CI/CD tool set up on your Git repository to automatically deploy changes to production. Occasionally, you make a lot of changes to your content to quickly reach the CI/CD provider’s (free) build limits, or you just don’t want to see builds triggered for every single small change.
With Sveltia CMS, you can disable automatic deployments by default and manually trigger deployments at your convenience. This is done by adding the [skip ci]
prefix to commit messages, the convention supported by GitHub Actions, GitLab CI/CD, CircleCI, Travis CI, Netlify, Cloudflare Pages and others. Here are the steps to use it:
automatic_deployments
property to your backend
configuration with a value of false
: backend:
name: github
repo: owner/repo
branch: main
+ automatic_deployments: false
[skip ci]
is automatically added to each commit message. However, deletions are always committed without the prefix to avoid unexpected data retention on your site.[skip ci]
.If you set automatic_deployments
to true
, the behaviour is reversed. CI/CD will be triggered by default, while you have an option to Save without Publishing that adds [skip ci]
only to the associated commit.
Gotcha: Unpublished entries and assets are not drafts. Once committed to your repository, those changes can be deployed any time another commit is pushed without [skip ci]
, or when a manual deployment is triggered.
If the automatic_deployments
property is defined, you can manually trigger a deployment by clicking the Publish Changes button on the application header. To use this feature:
repository_dispatch
event with the sveltia-cms-publish
event type. Update your build workflow to receive this event: on:
push:
branches: [$default-branch]
+ repository_dispatch:
+ types: [sveltia-cms-publish]
If your site adopts Content Security Policy (CSP), use the following policy for Sveltia CMS, or some features may not work.
style-src 'self' 'unsafe-inline' https://fonts.googleapis.com;
font-src 'self' https://fonts.gstatic.com;
img-src 'self' blob: data:;
media-src blob:;
frame-src blob:;
script-src 'self' https://unpkg.com;
connect-src 'self' blob: data: https://unpkg.com;
(UNPKG is used not only to download the CMS script bundle, but also to check for the latest version and retrieve additional dependencies such as PDF.js and Prism language definitions)
Then, add the following origins depending on your Git backend and enabled integrations.
img-src
https://*.githubusercontent.com
connect-src
https://api.github.com https://www.githubstatus.com
img-src
https://gitlab.com https://secure.gravatar.com
connect-src
https://gitlab.com https://status-api.hostedstatus.com
img-src
https://images.pexels.com
connect-src
https://images.pexels.com https://api.pexels.com
img-src
https://pixabay.com
connect-src
https://pixabay.com
img-src
https://images.unsplash.com
connect-src
https://images.unsplash.com https://api.unsplash.com
connect-src
https://api-free.deepl.com
connect-src
https://api.deepl.com
frame-src
https://www.youtube-nocookie.com
If you choose to disable automatic deployments and have configured a webhook URL, you may need to add the origin to the connect-src
directive. For example,
connect-src
https://api.netlify.com
connect-src
https://api.cloudflare.com
If you have image field(s) and expect that images will be inserted as URLs, you may want to allow any source using a wildcard instead of specifying individual origins:
img-src 'self' blob: data: https://*;
Now you can see the application version under the Help menu, next to the Account menu.
While we don’t have dedicated developer/user support resources, quick questions and feedback are welcome on the Discussions page of our GitHub repository. We also have a Discord channel for casual chat.
As described throughout this README, Sveltia CMS is being built as a replacement for Netlify/Decap CMS. At this point, we assume that most developers and users are migrating from the other product or Static CMS. We are happy to help you migrate, but we cannot help you set up Sveltia CMS from scratch through our free support channels.
Planning to build a website with Sveltia CMS? Looking for professional support? Maintainer @kyoshino is available for hire depending on your needs. Feel free to reach out!
See Contributing to Sveltia CMS. Bug reports are highly encouraged!
config.yml
schema validationThis software is provided “as is” without any express or implied warranty. We are not obligated to provide any support for the application. This product is not affiliated with or endorsed by Netlify, Decap CMS or any other integrated services. All product names, logos, and brands are the property of their respective owners.
[^1]: Netlify/Decap CMS #2557
[^2]: Netlify/Decap CMS #2039, #3267
[^3]: Netlify/Decap CMS #1040
[^4]: Netlify/Decap CMS #3671
[^5]: Netlify/Decap CMS #1032
[^6]: Netlify/Decap CMS #3240
[^7]: Netlify/Decap CMS #4386, #4888
[^8]: Netlify/Decap CMS #2579
[^9]: Netlify/Decap CMS #3505, #4211, #5439
[^10]: Netlify/Decap CMS #341, #1167
[^11]: Netlify/Decap CMS #1382, #6994
[^12]: Netlify/Decap CMS #1975, #3712
[^13]: Netlify/Decap CMS #5112, #5653
[^14]: Netlify/Decap CMS #4635, #5920, #6410, #6827, #6924
[^15]: Netlify/Decap CMS #6932
[^16]: Netlify/Decap CMS #2103, #2790, #7302
[^17]: Netlify/Decap CMS #1333, #4216
[^18]: Netlify/Decap CMS #441
[^19]: Netlify/Decap CMS #5910
[^20]: Netlify/Decap CMS #4563
[^21]: Netlify/Decap CMS #4781
[^22]: Netlify/Decap CMS #3615, #4069, #5097, #6642
[^23]: Netlify/Decap CMS #2
[^24]: Netlify/Decap CMS #6831
[^25]: Netlify/Decap CMS #526, #6987
[^26]: Netlify/Decap CMS #3285, #7030, #7067, #7217
[^27]: Netlify/Decap CMS #4564, #5617, #5815
[^28]: Netlify/Decap CMS #2677, #6836
[^29]: Netlify/Decap CMS #4783
[^30]: Netlify/Decap CMS #565, #6733
[^31]: Netlify/Decap CMS #1045
[^32]: Netlify/Decap CMS #302, #5549
[^33]: Netlify/Decap CMS #542, #4532, #6513, #7295
[^34]: Netlify/Decap CMS #2138, #2343, #4367, #5932
[^35]: Netlify/Decap CMS #7086
[^36]: Netlify/Decap CMS #6325
[^37]: Netlify/Decap CMS #1481
[^38]: Netlify/Decap CMS #1984
[^39]: Netlify/Decap CMS #946, #1970
[^40]: Netlify/Decap CMS #5630
[^41]: Netlify/Decap CMS #7011
[^42]: Netlify/Decap CMS #2307
[^43]: Netlify/Decap CMS #4387, #5381
[^44]: Netlify/Decap CMS #2613
[^45]: Netlify/Decap CMS #1424
[^46]: Netlify/Decap CMS #4726
[^47]: Netlify/Decap CMS #2370, #5596
[^48]: Netlify/Decap CMS #5569, #6754
[^49]: Netlify/Decap CMS #5752
[^50]: Netlify/Decap CMS #4646, #7167
[^51]: Netlify/Decap CMS #6731
[^52]: Netlify/Decap CMS #6970, #7147
[^53]: Netlify/Decap CMS #512, #5673, #6707
[^54]: Netlify/Decap CMS #1347, #1559, #4629, #4837, #6287, #6826 — Decap CMS 3.0 updated the Slate editor in an attempt to fix the problems, but the IME issues remain unresolved when using a mobile/tablet browser.
[^55]: Netlify/Decap CMS #4480, #5122, #6353
[^56]: Netlify/Decap CMS #6515
[^57]: Netlify/Decap CMS #328, #1290
[^58]: Netlify/Decap CMS #5125
[^59]: Netlify/Decap CMS #1654
[^60]: Netlify/Decap CMS #283, #386
[^61]: Netlify/Decap CMS #1489, #5838
[^62]: Netlify/Decap CMS #7192
[^63]: Netlify/Decap CMS #4877
[^64]: Netlify/Decap CMS #3853
[^65]: Netlify/Decap CMS #6034
[^66]: Netlify/Decap CMS #3353
[^67]: Netlify/Decap CMS #7077
[^68]: Netlify/Decap CMS #6978
[^69]: Netlify/Decap CMS #4350
[^70]: Netlify/Decap CMS #6482
[^71]: Netlify/Decap CMS #6999, #7000, #7001, #7152, #7220, #7283, #7316
[^72]: Netlify/Decap CMS #7047
[^73]: Netlify/Decap CMS #6993, #7123, #7127, #7128, #7237, #7251, #7361
[^74]: Netlify/Decap CMS #4209
[^75]: Netlify/Decap CMS #5472
[^76]: Netlify/Decap CMS #4738
[^77]: Netlify/Decap CMS #2009, #2293, #3415, #3952, #6563
[^78]: Netlify/Decap CMS #2294, #3046, #4363, #4520, #5806
[^79]: Netlify/Decap CMS #5726
[^80]: Netlify/Decap CMS #5493, #6600
[^81]: Netlify/Decap CMS #4645
[^82]: Netlify/Decap CMS #6500
[^83]: Netlify/Decap CMS #6508
[^84]: Netlify/Decap CMS #7142, #7276
[^85]: Netlify/Decap CMS #5055, #5470, #6989
[^86]: Netlify/Decap CMS #1609, #3557, #5253, #6759, #6901
[^87]: Netlify/Decap CMS #5280
[^88]: Netlify/Decap CMS #1267
[^89]: Netlify/Decap CMS #4255
[^90]: Netlify/Decap CMS #725
[^91]: Netlify/Decap CMS #4954
[^92]: Netlify/Decap CMS #1466
[^93]: Netlify/Decap CMS #1000
[^94]: Netlify/Decap CMS #5487
[^95]: Netlify/Decap CMS #4417
[^96]: Netlify/Decap CMS #962
[^97]: Netlify/Decap CMS #4288
[^98]: Netlify/Decap CMS #3856
[^99]: Netlify/Decap CMS #1685
[^100]: Netlify/Decap CMS #4147
[^101]: Netlify/Decap CMS #5969
[^102]: Netlify/Decap CMS #1270
[^103]: Netlify/Decap CMS #6307
[^104]: Netlify/Decap CMS #450, #2122, #6819
[^105]: Netlify/Decap CMS #5701
[^106]: Netlify/Decap CMS #2822
[^107]: Netlify/Decap CMS #332, #683, #999, #1456, #4175, #4818, #5688, #6828, #6829, #6862, #7023
[^108]: Netlify/Decap CMS #6879
[^109]: Netlify/Decap CMS #7197
[^110]: Netlify/Decap CMS #4637, #5198
[^111]: Netlify/Decap CMS #7190, #7218
[^112]: Netlify/Decap CMS #5815, #6522, #6532, #6588, #6617, #6640, #6663, #6695, #6697, #6764, #6765, #6835, #6983, #7205
[^113]: Netlify/Decap CMS #5656, #5837, #5972, #6476, #6516, #6930, #6965, #7080, #7105, #7106, #7119, #7176, #7194, #7244, #7301, #7342, #7348, #7354, #7376 — These removeChild
crashes are common in React apps, likely caused by a browser extension or Google Translate.
[^114]: Netlify/Decap CMS #5029, #5048
[^115]: Netlify/Decap CMS #7172
[^116]: Netlify/Decap CMS #3431
[^117]: Netlify/Decap CMS #3562, #6215
[^118]: Netlify/Decap CMS #7267
[^119]: Netlify/Decap CMS #5640, #6444
[^120]: Netlify/Decap CMS #2727, #4884
[^121]: Netlify/Decap CMS #7262
[^122]: Netlify/Decap CMS #1776, #2064, #7158, #7259
[^123]: Netlify/Decap CMS #961, #5489
[^124]: Netlify/Decap CMS #991, #4488, #7233
[^125]: Netlify/Decap CMS #475, #5469
[^126]: Netlify/Decap CMS #7279
[^127]: Netlify/Decap CMS #2289, #4518
[^128]: Netlify/Decap CMS #7092
[^129]: Netlify/Decap CMS #4961, #4979, #5545, #5778, #6279, #6464, #6810, #6922, #7118, #7293 — A comment on one of the issues says the crash was due to Google Translate. Sveltia CMS has turned off Google Translate on the admin page.
[^130]: Netlify/Decap CMS #6571
[^131]: Netlify/Decap CMS #4429
[^132]: Netlify/Decap CMS #6816
[^133]: Netlify/Decap CMS #445
[^134]: Netlify/Decap CMS #5548
[^135]: Netlify/Decap CMS #2133
[^136]: Netlify/Decap CMS #7085
[^137]: Netlify/Decap CMS #4092
[^138]: Netlify/Decap CMS #4841
[^139]: Netlify/Decap CMS #6202
[^140]: Netlify/Decap CMS #5444
[^141]: Netlify/Decap CMS #3723, #6990
[^142]: Netlify/Decap CMS #7124
[^143]: Netlify/Decap CMS #1341
[^144]: Netlify/Decap CMS #3284
[^145]: Netlify/Decap CMS #4733
[^146]: Netlify/Decap CMS #2524
[^147]: Netlify/Decap CMS #3583
[^148]: Netlify/Decap CMS #531, #621, #1282, #1877, #2514, #2737
[^149]: Netlify/Decap CMS #13 — The issue appears to have been closed without a fix being available.
[^150]: Netlify/Decap CMS #7319
[^151]: Netlify/Decap CMS #7328
[^152]: Netlify/Decap CMS #2491
[^153]: Netlify/Decap CMS #7347
[^154]: Netlify/Decap CMS #1449, #1988
[^155]: Netlify/Decap CMS #5870
[^156]: Netlify/Decap CMS #995, #2017, #7120, #7186
[^157]: Netlify/Decap CMS #2007, #2848
[^158]: Netlify/Decap CMS #6107
[^159]: Netlify/Decap CMS #3796
[^160]: Netlify/Decap CMS #3291
[^161]: Netlify/Decap CMS #1274
[^162]: Netlify/Decap CMS #2380
[^163]: Netlify/Decap CMS #7322
[^164]: Netlify/Decap CMS #756 — The Expand All and Collapse All buttons cannot be found in the current version of Decap CMS.
[^165]: Netlify/Decap CMS #7143
[^166]: Netlify/Decap CMS #277
[^167]: Netlify/Decap CMS #263
[^168]: Netlify/Decap CMS #1948
[^169]: Netlify/Decap CMS #7364
[^170]: Netlify/Decap CMS #7371
[^171]: Netlify/Decap CMS #4754
[^172]: Netlify/Decap CMS #3715
[^173]: Netlify/Decap CMS #3715