Sveltia CMS is a Git-based lightweight headless CMS under active development as a modern, 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, UX-focused alternative to Netlify/Decap CMS is now in public beta — with more features to come.
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 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.
Due to its unfortunate abandonment, Netlify CMS spawned 3 successors:
- Static CMS: a community maintenance fork, initial commit made in September 2022, discontinued in September 2024
- Sveltia CMS: a total reboot, started in November 2022, first appeared on GitHub in March 2023
- Decap CMS: a rebranded version, owned by a Netlify agency partner, announced in February 2023 as the official successor
Sveltia CMS is the only project that doesn’t inherit the complexity, technical debt and miscellaneous bugs of Netlify CMS, which was launched back in 2016. 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 products. (Note: While we are closely following the development of Decap CMS, compatibility with Static CMS will be worked on after the release of Sveltia CMS 1.0)
- Making Sveltia CMS a viable, definitive successor to Netlify CMS
- Emerging as the leading open source offering in the Git-based CMS market
- Empowering small businesses and individuals who need a simple, free, yet powerful CMS solution
- Extending its capabilities as digital asset management (DAM) software
- Showcasing the vast potential of the Svelte framework
Sveltia CMS is still in beta, so please be careful when trying it out.
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:
- Ensuring substantial compatibility with existing versions of Netlify/Decap CMS
- Tackling as many issues reported to Netlify/Decap CMS as possible
- So far, 115+ of them (or 195+ including duplicates) have been effectively solved in Sveltia CMS
- Target: 150 issues by GA, 250 in a future release
- Let us know if you have any specific issues you’d like to see solved!
- Responding to feedback from clients and regular users
- Implementing our own enhancement ideas for every part of the product
Sveltia CMS version 1.0 is expected to ship by the end of 2024. Check our release notes for updates. See also our roadmap.
We are working hard to create a significantly better alternative to Netlify CMS and Decap CMS by improving everything. Here’s what makes Sveltia CMS different. Look how serious we are!
- 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.
- Your existing configuration file can be reused as is.
- However, some features are still missing or will not be added, most notably Git Gateway and Netlify Identity. Look at the compatibility info below to see if you can migrate now or soon.
- Created and maintained by an experienced UX engineer who loves code, design and marketing. You can expect constant improvements to the user experience (UX) and developer experience (DX) across the platform.
- Offers a modern, intuitive user interface, including an immersive dark mode1, inspired in part by the Netlify CMS v3 prototype2.
- Comes with touch device support, such as larger buttons for easier tapping. While the UI is not yet optimized for small screens, it should work well with large tablets like iPad Pro or Pixel Tablet. Mobile support and other optimizations such as swipe navigation are planned after the 1.0 release.
- Made with Svelte, not React, means we can spend more time on UX rather than tedious state management. It also allows us to avoid common fatal application crashes3. Best of all, Svelte offers unmatched performance!
- The screenshots above are worth a thousand words, but read on to learn about many other improvements in detail.
- Built completely from scratch with Svelte instead of forking React-based Netlify/Decap CMS. The app starts fast and stays fast. The compiled code is vanilla JavaScript — you can use it with any framework that can load static data files while building your website or application.
- Small footprint: The bundle size is less than 450 KB when minified and gzipped, which is much lighter than Netlify CMS (1.5 MB), Decap CMS (1.8 MB) and Static CMS (2.6 MB)45, even though we haven’t implemented some features yet. That’s the power of Svelte + Vite.
- We have upgraded from Svelte 4 to Svelte 5 Release Candidate to further boost performance, resulting in faster rendering, reduced memory usage and even smaller bundle size. A full migration to the runes reactivity API will follow.
- Sveltia CMS is free of technical debt and virtual DOM overhead.
- Uses the GraphQL API for GitHub and GitLab to quickly fetch content at once, so that entries and assets can be listed and searched instantly67. It also avoids the slowness and potential API rate limit violations caused by hundreds of requests with Relation widgets8.
- Saving entries and assets to GitHub is also much faster thanks to the GraphQL mutation.
- Using caching and lazy loading techniques. A list of repository files is stored locally for faster startup and bandwidth savings.
- Thumbnails of assets, including videos and PDF files, are generated and cached for faster rendering of the Asset Library and other parts of the CMS9.
- No typing lag on input widgets, especially within nested lists and objects10.
- You can work with a local Git repository without any extra configuration or proxy server11.
- In addition to a streamlined workflow, it offers great performance by reading and writing files natively through the browser rather than using a slow, ad hoc REST API.
- It also avoids a number of issues, including the 30 MB file size limit12, an unknown error with
publish_mode
13, and an unusedlogo_url
14. - When you delete an entry or an asset file, the empty folder that contains it is also deleted, so you don’t have to delete it manually.
- Provides a smoother user experience in the Content Editor:
- A local backup of an entry draft is automatically created without interruption by a confirmation dialog, which annoys users and can cause a page navigation problem if dismissed15. The backup can then be reliably restored without unexpected overwriting16.
- Click once (the Save button) instead of twice (Publish > Publish now) to save an entry.
- The editor closes automatically when an entry is saved. This behaviour can be changed in Settings.
- You can upload multiple assets at once17.
- You can delete multiple entries and assets at once.
- Some keyboard shortcuts are available for faster editing.
- Never miss out on the latest features and bug fixes by being notified when an update to the CMS is available18. Then update to the latest version with a single click19.
- Improved keyboard handling lets you efficiently navigate through UI elements using the Tab, Space, Enter and arrow keys2021.
- Comprehensive WAI-ARIA support enables users who rely on screen readers such as NVDA and VoiceOver.
- The rich text editor is built with Lexical, which is said to follow accessibility best practices. The Dragon NaturallySpeaking support is enabled.
- Ensures sufficient contrast between the foreground text and background colours.
- Enabled and disabled buttons can be clearly distinguished22.
- Links are underlined by default to make them easier to recognize. This behaviour can be changed in the Accessibility Settings if you prefer.
- Honours your operating system’s reduced motion and reduced transparency settings. (Support for high contrast mode will be added later.)
- Browser console logs for developers are readable in either light or dark mode23.
- We’ll continue to test and improve the application to meet WCAG 2.2.
- Avoids severity vulnerabilities through constant dependency updates,
pnpm audit
, and frequent releases24. - We have documented how to set up a Content Security Policy for the CMS to prevent any unexpected errors or otherwise insecure configuration25.
- The
unsafe-eval
andunsafe-inline
keywords are not needed in thescript-src
CSP directive26. - The
same-origin
referrer policy is automatically set with a<meta>
tag.
- Some servers and frameworks remove the trailing slash from the CMS URL (
/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 error27. - Supports a JSON configuration file that can be generated for bulk or complex collections28.
- The application renders within the dimensions of a custom mount element, if exists29.
- Uses the GraphQL API where possible for better performance, as mentioned above. You don’t need to set the
use_graphql
option to enable it for GitHub and GitLab. - The Git branch name is automatically set to the repository’s default branch (
main
,master
or whatever) if not specified in the configuration file, preventing data loading errors due to a hardcoded fallback tomaster
3031. - You can disable automatic deployments by default or on demand to save costs and resources associated with CI/CD and to publish multiple changes at once32.
- The GitLab backend support comes with background service status checking, just like GitHub.
- Service status checks are performed frequently and an incident notification is displayed prominently.
- You can quickly open the source file of an entry or asset in your repository using View on GitHub (or GitLab) under the 3-dot menu.
- You won’t get a 404 Not Found error when you sign in to the GitLab backend33.
- Features the all-new local backend that boosts DX. See the productivity section above.
- You can select the local and remote backends while working on a local server.
Sveltia CMS has been built with a multilingual architecture from the very beginning. You can expect first-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 a city where 150+ languages are spoken.
- Configuration
- Supports multiple files/folders i18n structure for file collections34. To enable it, simply use the
{{locale}}
template tag in thefile
path option, e.g.content/pages/about.{{locale}}.json
orcontent/pages/{{locale}}/about.json
. For backward compatibility, the globalstructure
option only applies to folder collections as before. - Entry-relative media folders can be used in conjunction with the
multiple_folders
i18n structure35. - Removes the limitations in the List and Object widgets so that changes made with these widgets will be duplicated between locales as expected when using the
i18n: duplicate
field configuration3637. - You can use the
{{locale}}
template tag in thepreview_path
collection option to provide site preview links for each language38. - You can use a random UUID for an entry slug, which is a good option for locales that write in non-Latin characters.
- You can localize entry slugs while linking the localized files39, thanks to the support for Hugo’s
translationKey
40. - When the
clean_accents
option is enabled for entry slugs, certain characters, such as German umlauts, will be transliterated41. - You can embed the locale code in an entry by using
widget: hidden
along withdefault: '{{locale}}'
42.
- Supports multiple files/folders i18n structure for file collections34. To enable it, simply use the
- User interface
- Eliminates UI confusion: The preview pane can be displayed without toggling i18n in the Content Editor. Both panes are scrollable. There is no condition where both panes are edited in the same language at the same time.
- You can easily switch between locales while editing by clicking a button instead of a dropdown list. No internal error is thrown when changing the locale43.
- Language labels appear in human-readable display names instead of ISO 639 language codes, which not everyone is familiar with. (For example, it might be difficult to recognize
DE
as German,NL
as Dutch, orZH
as Chinese.) - The List widget’s
label
andlabel_singular
are not converted to lowercase, which is especially problematic in German, where all nouns are capitalized44. - Long menu item labels, especially in non-English locales, don’t overflow the dropdown container45.
- Content editing
- Integrates DeepL to allow translation of text fields from another locale with one click. More translation services will be added in the future.
- You can disable non-default locale content46.
- Boolean, DateTime, List and Number fields in the entry preview are displayed in a localized format.
- Boolean fields are updated in real time between locales like other widgets to avoid confusion47.
- Relation fields with i18n enabled won’t trigger a change in the content draft status when you start editing an existing entry48.
- Solves problems with Chinese, Japanese and Korean (CJK) IME text input in the rich text editor for the Markdown widget49.
- Raises a validation error instead of failing silently if the
single_file
structure is used and a required field is not filled in any of the locales50. - Fields in non-default locales are validated as expected51.
- Configuration
- You can choose a custom icon for each collection with the new
icon
collection option52. - You can add dividers to the collection list with the new
divider
collection option. - You can specify the field name for a thumbnail displayed on the entry list with the new
thumbnail
collection option. A nested field can be specified using dot notation, e.g.images.0.src
. If undefined, thename
of the first image field is used. - You can use nested fields (dot notation) in the
path
option for a folder collection, e.g.{{fields.state.name}}/{{slug}}
53. - You can use Markdown in the
description
collection option54. Bold, italic, strikethrough, code and links are allowed.
- You can choose a custom icon for each collection with the new
- Entry slugs
- You can use a random UUID for an entry slug.
- Entry slug template tags support filter transformations just like summary string template tags55.
- Single quotes in a slug will be replaced with
sanitize_replacement
(default: hyphen) rather than being removed56. - You can set the maximum number of characters for an entry slug with the new
slug_length
collection option57.
- Entry listing
- A folder collection filter with a boolean value works as expected58.
- Hugo’s special
_index.md
files are ignored in folder collections. You can still manage these files as part of a file collection if necessary59. - If there was an error while parsing an entry file, such as duplicate front matter keys, it won’t show up as a blank entry, and a clear error message will be displayed in the browser console60.
- Sorting entries by a DateTime field works as expected61.
- Assets stored in a per-collection media folder can be displayed next to the entries.
- The New Entry button won’t appear when a developer accidentally sets the
create: true
option on a file collection because it’s useless62. - The Delete Entry button won’t appear when a developer accidentally sets the
delete: true
option on a file collection because the preconfigured files should not be deleted.
- Required fields, not optional fields, are clearly marked for efficient data entry.
- You can revert changes to all fields or a specific field.
- If you revert changes and there are no unsaved changes, the Save button is disabled as expected63.
- You can hide the preview of a specific field with
preview: false
. - Fields with validation errors are automatically expanded if they are part of nested, collapsed objects64.
- When you click on a field in the preview pane, the corresponding field in the edit pane is highlighted. It will be automatically expanded if collapsed65.
- The preview pane displays all fields, including each title, making it easier to see which fields are populated.
- Provides better scroll synchronization between the panes when editing or previewing an entry66.
- You can use a full regular expression, including flags, for the widget
pattern
option67. 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 themaxlength
option instead). - A long validation error message is displayed in full, without being hidden behind the field label68.
- Any links to other entries will work as expected, with the Content Editor being updated for the other69.
- Keys in generated JSON/TOML/YAML content are always sorted by the order of configured fields, making Git commits clean and consistent70.
- For data consistency, Boolean, List (see below) and other fields are always saved as a proper value, such as an empty string or an empty array, rather than nothing, even if it’s optional or empty717273.
- Leading and trailing spaces in text-type field values are automatically removed when you save an entry74.
- JSON/TOML/YAML data is saved with a new line at the end of the file to prevent unnecessary changes being made to the file7576.
- String values in YAML files can be quoted with the new
yaml_quote: true
option for a collection, mainly for framework compatibility77. - YAML string folding (maximum line width) is disabled, mainly for framework compatibility78.
- Boolean
- Color
- The preview shows both the RGB(A) hex value and the
rgb()
function notation.
- The preview shows both the RGB(A) hex value and the
- DateTime
- A DateTime field doesn’t trigger a change in the content draft status when you’ve just started editing a new entry79.
- Hidden
- The
default
value is saved when you create a file collection item, not just a folder collection item80. - The
default
value supports the{{locale}}
and{{datetime}}
template tags, which will be replaced by the locale code and the current date/time in ISO 8601 format, respectively4281.
- The
- List
- The Add Item button appears at the bottom of the list when the
add_to_top
option is nottrue
, so you don’t have to scroll up each time to add new items. - You can expand or collapse the entire list, while the Expand All and Collapse All buttons allow you to expand or collapse all items in the list at once.
- A required List field with no subfield or value is marked as invalid82.
- An optional List field with no subfield or value is saved as an empty array, rather than nothing73.
- You can enter spaces in a simple text-based List field83.
- You can preview variable types without having to register a preview template84.
- The Add Item button appears at the bottom of the list when the
- Markdown
- The rich text editor is built with Lexical, which solves various issues with a Slate-based editor in Netlify/Decap CMS, including fatal application crashes85868788, lost formatting when pasting89, backslash injections90, dropdown visibility91, and text input difficulties with IME49.
- You can set the default editor mode by changing the order of the
modes
option92. If you want to use the plain text editor by default, addmodes: [raw, rich_text]
to the field configuration. - Line breaks are rendered as line breaks in the preview pane according to GitHub Flavored Markdown.
- Object
- Sveltia CMS offers two ways to have conditional fields in a collection93:
- You can use variable types (the
types
option) with the Object widget just like the List widget. - An optional Object field (
required: false
) can be manually added or removed with a checkbox94. If unadded or removed, the required subfields won’t trigger validation errors95, and the field will be saved asnull
.
- You can use variable types (the
- Sveltia CMS offers two ways to have conditional fields in a collection93:
- Relation
- Field options are displayed with no additional API requests8. The confusing
options_length
option, which defaults to 20, is therefore ignored96. slug
can be used forvalue_field
to show all available options instead of just one in some situations97.- Template strings with a wildcard like
{{cities.*.name}}
can also be used forvalue_field
98. display_fields
is displayed in the preview pane instead ofvalue_field
.- The redundant
search_fields
option is not required in Sveltia CMS, as it defaults todisplay_fields
(andvalue_field
).
- Field options are displayed with no additional API requests8. The confusing
- Select
- It’s possible to select an option with value
0
99. label
is displayed in the preview pane instead ofvalue
.
- It’s possible to select an option with value
- String
- When a YouTube video URL is entered in a String field, it appears as an embedded video in the preview pane. Check your site’s CSP if the preview doesn’t work.
- When a regular URL is entered in a String field, it appears as a link that can be opened in a new browser tab.
- Supports the
type
option that acceptsurl
oremail
as a value, which will validate the value as a URL or email. - Supports the
prefix
andsuffix
string options, which automatically prepend and/or append the developer-defined value to the user-input value.
- Boolean, Number and String
- Supports the
before_input
andafter_input
string options, which allow developers to display custom labels before and/or after the input UI100. Markdown is supported in the value.
- Supports the
- File and Image
- Provides a reimagined all-in-one asset selection dialog for File and Image fields.
- Collection-specific assets are listed for easy selection, while all assets are displayed in a separate tab101.
- A new asset can be uploaded by dragging & dropping it into the dialog102.
- A URL can also be entered in the dialog.
- Integration with Pexels, Pixabay and Unsplash makes it easy to select and insert a free stock photo103. More stock photo providers will be added in the future.
- Large images automatically fit in the preview pane instead of being displayed at their original size, which can easily exceed the width of the pane.
- Provides a reimagined all-in-one asset selection dialog for File and Image fields.
- List and Object
- The
summary
is displayed correctly when it refers to a Relation field104 or a simple List field.
- The
- Markdown, String and Text
- A required field containing only spaces or line breaks will result in a validation error, as if no characters were entered.
- Relation and Select
- If a dropdown list has options with long wrapping labels, they won’t overlap with the next option105.
- When there are 5 or fewer options, the UI switches from a dropdown list to radio buttons (single-select) or checkboxes (multi-select) for faster data entry106. This number can be changed with the
dropdown_threshold
option for therelation
andselect
widgets.
- String and Text
- Supports the
minlength
andmaxlength
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 thepattern
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.
- Supports the
- Compute
- The experimental
compute
widget allows to reference the value of other fields in the same collection, similar to thesummary
property for the List and Object widgets107. Use thevalue
property to define the value template, e.g.posts-{{fields.slug}}
(example). - The
value
property also supports a value of{{index}}
, which can hold the index of a list item (example).
- The experimental
- UUID
- In addition to generating UUIDs for entry slugs, Sveltia CMS also supports the proposed
uuid
widget with the following properties108: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
.
- In addition to generating UUIDs for entry slugs, Sveltia CMS also supports the proposed
- A completely new Asset Library, built separately from the image selection dialog, makes it easy to manage all of your files, including images, videos and documents109.
- Navigate between the global media folder and per-collection media folders110.
- Preview image, audio, video, text and PDF files. Check your site’s CSP if the preview doesn’t work.
- Copy the public URL111, file path, text data or image data of a selected asset to clipboard. The file path starts with
/
as expected112. - Edit a plain text asset, including SVG images.
- Rename an existing asset. If the asset is used in any entries, the File/Image fields will be automatically updated with a new file path.
- Replace an existing asset.
- Download one or more selected assets at once.
- Delete one or more selected assets at once.
- Upload multiple assets at once, including files in nested folders, by browsing or dragging and dropping them into the library17.
- Sort or filter assets by name or file type.
- View asset details, including size, dimensions, commit author/date and a list of entries that use the selected asset.
- PDF documents are displayed with a thumbnail image in both the Asset Library and the Select File dialog, making it easier to find the file you’re looking for113.
- Assets stored in an entry-relative media folder are automatically deleted when the associated entry is deleted because these assets are not available for other entries114. When you’re working with a local repository, the empty enclosing folder is also deleted.
- Hidden files (dot files) don’t appear in the Asset Library115.
- You can add assets using the Quick Add button in the upper right corner of the application.
- Files are uploaded with their original names, without converting uppercase letters and spaces to lowercase letters and hyphens116.
- No fatal application crash when uploading assets117.
We are trying to make Sveltia CMS compatible with Netlify/Decap CMS where possible, so that more users can seamlessly switch to our modern, powerful, high performance alternative. However, some features will be omitted due to deprecations and other factors.
- The Bitbucket, Gitea/Forgejo and Git Gateway backends will not be supported for performance reasons. We may implement a high-performance Git Gateway alternative in the future. We may also support the other services if/when their APIs improve to allow the CMS to fetch multiple files at once.
- The Netlify Identity Widget will not be supported, as it’s not useful without Git Gateway. We may be able to support it in the future if/when a Git Gateway alternative is created.
- The deprecated client-side implicit grant for the GitLab backend will not be supported, as it has already been removed from GitLab 15.0. Use the client-side PKCE authorization instead.
- The deprecated Netlify Large Media service will not be supported. Consider other storage providers.
- The deprecated Date widget will not be supported, as it has already been removed from Decap CMS 3.0. Use the DateTime widget instead.
- Remark plugins will not be supported, as they are not compatible with our Lexical-based rich text editor.
- Undocumented methods exposed on the
window.CMS
object will not be implemented. This includes custom backends and custom media libraries, if any.
These limitations are expected to be resolved before or shortly after GA:
Feature | Status in Sveltia CMS |
---|---|
Backends | The Test backend needed for our demo site is not yet added. We’ll see if Azure 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. |
Workflow | Editorial Workflow and Open Authoring are not yet supported. |
Collections | Nested collections are not yet supported. |
Widgets | Custom widgets are not yet supported. See the table below for other limitations. |
Customizations | Custom previews, custom formatters and event subscriptions are not yet supported. |
Widget | Status in Sveltia CMS |
---|---|
Code | Not yet supported. |
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 soon. |
File/Image | Field-specific media folders and media library options are not yet supported other than media_library.config.max_file_size for the default media library. |
Map | Not yet supported. |
Markdown | Editor components, including built-in image and code-block as well as custom components, are not yet supported. |
Missing any other features? Let us know by filing an issue.
- Svelte 5 runes migration
- Enhanced compatibility with Netlify/Decap CMS
- Localization with the new Fluent-powered sveltia-i18n library
- Accessibility audit
- Developer documentation (implementation guide)
- Marketing site
- Live demo site
- Official starter templates for the most popular frameworks, including SvelteKit and Next.js
- Broad automation test coverage (Vitest + Playwright)
- Tackling more Netlify/Decap CMS issues, especially the top voted features, including MDX support118, manual entry sorting119, roles120, mobile optimization121 and config editor122 — Some features are already implemented in Sveltia CMS
- Certain compatibility with Static CMS, a now-discontinued community fork of Netlify CMS, including the KeyValue widget123
- Advanced digital asset management (DAM) features, including image editing and tagging124
- AI integrations
- End-user documentation
- Contributor documentation
- and so much more!
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. 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!
- Eleventy starter template by @danurbanowicz
- Hugo module by @privatemaker
- hugolify-sveltia-cms by @sebousan
- Astro: astro-sveltia-cms, astro-starter and astros by @zanhk
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 custom widget, custom preview or plugin, 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.
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.
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.
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 backend 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.
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.
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)
You can use Sveltia CMS with a local Git repository like Netlify/Decap CMS, but Sveltia CMS has simplified the workflow by removing the need for additional configuration (the local_backend
property) and a proxy server, thanks to the File System Access API available in some modern browsers.
- Make sure you have configured the GitHub or GitLab backend.
- Please note that the Git Gateway backend mentioned in the Netlify/Decap CMS local Git repository document is not supported in Sveltia CMS, so
name: git-gateway
won’t work. You’ll need eithername: github
orname: gitlab
along with therepo
definition. If you haven’t determined your repository name yet, just use a random one. - You can remove
local_backend
from your configuration, as it will be ignored by Sveltia CMS.
- Please note that the Git Gateway backend mentioned in the Netlify/Decap CMS local Git repository document is not supported in Sveltia CMS, so
- Launch the local development server for your frontend framework, typically with
npm run dev
orpnpm dev
. - Visit
http://localhost:[port]/admin/index.html
with Chrome or Edge. The port number varies by framework.- Other Chromium-based browsers may also work. Brave user? See below.
- Click “Work with Local Repository” and select the project’s root directory once prompted.
- If you get an error saying “not a repository root directory”, make sure you’ve turned the folder into a repository with either a CUI (
git init
) or GUI, and the hidden.git
folder exists. - If you’re using Windows Subsystem for Linux (WSL), you may get an error saying “Can’t open this folder because it contains system files.” This is due to a limitation in the browser, and you can try some workarounds mentioned in this issue and this thread.
- If you get an error saying “not a repository root directory”, make sure you’ve turned the folder into a repository with either a CUI (
- Make some changes to your content on Sveltia CMS.
- See if the produced changes look good using
git diff
or a GUI like GitHub Desktop. - Open the dev site at
http://localhost:[port]/
to check the rendered pages. - Commit and push the changes if satisfied, or discard them if you’re just testing.
Keep in mind that the local repository support doesn’t perform any Git operations. You’ll have to manually fetch, pull, commit and push all changes using a Git client. In the near future, we’ll figure out if there’s a way to do this in a browser (because netlify-cms-proxy-server
actually has undocumented git
mode that allows developers to create commits to a local repository).
Also, at this point, you have to reload the CMS to see the latest content after retrieving remote updates. This manual work will be unnecessary once the proposed FileSystemObserver
API, which is being implemented in Chromium behind a flag, becomes available.
In the Brave browser, you must enable the File System Access API with an experiment flag to take advantage of local development.
- Open
brave://flags/#file-system-access-api
in a new browser tab. - Click Default (Disabled) next to File System Access API and select Enabled.
- Relaunch the browser.
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:
- Visit the Material Symbols page on Google Fonts.
- Search and select an icon, and copy the icon name displayed on the right panel.
- Add it to one of your collection definitions in
config.yml
as the newicon
property, like the example below. - Repeat the same steps for all the collections if desired.
- Commit and push the changes to your Git repository.
- Reload Sveltia CMS once the updated config file is deployed.
- 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 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
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 CMS125. 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
+ public_folder: /media/products
In Sveltia CMS, those per-collection media folders are displayed prominently for easier asset management.
- View the Content Library:
Alt+1
- View the Asset Library:
Alt+2
- Search for entries and assets:
Ctrl+F
(Windows/Linux) orCommand+F
(macOS) - Create a new entry:
Ctrl+E
(Windows/Linux) orCommand+E
(macOS) - Save an entry:
Ctrl+S
(Windows/Linux) orCommand+S
(macOS) - Cancel entry editing:
Escape
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:
- Update your configuration file to enable the i18n support with multiple locales.
- Sign up for DeepL API and copy your Authentication Key from DeepL’s Account page.
- Open an entry in Sveltia CMS.
- Click on the Translation button on the pane header or each field, right next to the 3-dot menu.
- Paste your key when prompted.
- The field(s) will be automatically translated.
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:
- Click the Account button in the upper right corner, then click Settings.
- Select the Language tab.
- Paste your key to the DeepL API Authentication Key field.
- Close the Settings dialog.
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}}'
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
title: My trip to New York translationKey: my-trip-to-new-york
data/posts/fr/mon-voyage-a-new-york.yaml
title: Mon voyage à New York translationKey: my-trip-to-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 per-collection 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}}
Or, for Jekyll, you may want to use the ref
property:
i18n:
canonical_slug:
key: ref
You can now disable output of content in selected non-default locales by adding the save_all_locales
property to the top-level or per-collection 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}}'
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, GitLab, CircleCI, Travis CI, Netlify, Cloudflare Pages and others. Here are the steps to use it:
- Add the new
automatic_deployments
property to yourbackend
configuration with a value offalse
:backend: name: github repo: owner/repo branch: main + automatic_deployments: false
- Commit and deploy the change to the config file and reload the CMS.
- Now, whenever you save an entry or asset,
[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. - If you want to deploy a new or updated entry, as well as any other unpublished entries and assets, click an arrow next to the Save button in the content editor, then select Save and Publish. This will trigger CI/CD by omitting
[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 selecting Publish Changes under the Account button in the top right corner of the CMS. To use this feature:
- GitHub Actions:
- Without any configuration, Publish Changes will trigger a
repository_dispatch
event with thesveltia-cms-publish
event type. Update your build workflow to receive this event:on: push: branches: [$default-branch] + repository_dispatch: + types: [sveltia-cms-publish]
- Without any configuration, Publish Changes will trigger a
- Other CI/CD providers:
- Select Settings under the Account button in the top right corner of the CMS.
- Select the Advanced tab.
- Enter the deploy hook URL for your provider, e.g. Netlify or Cloudflare Pages.
- Configure the CSP if necessary. See below.
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)
Then, add the following origins depending on your Git backend and enabled integrations.
- GitHub: (If you’re running a GitHub Enterprise Server, you’ll also need to add the origin to these directives.)
img-src
https://*.githubusercontent.com
connect-src
https://api.github.com https://www.githubstatus.com
- GitLab: (If you’re running a self-hosted instance, you’ll also need to add the origin to these directives.)
img-src
https://gitlab.com https://secure.gravatar.com
connect-src
https://gitlab.com https://status-api.hostedstatus.com
- Pexels:
img-src
https://images.pexels.com
connect-src
https://images.pexels.com https://api.pexels.com
- Pixabay:
img-src
https://pixabay.com
connect-src
https://pixabay.com
- Unsplash:
img-src
https://images.unsplash.com
connect-src
https://images.unsplash.com https://api.unsplash.com
- DeepL API Free:
connect-src
https://api-free.deepl.com
- DeepL API Pro:
connect-src
https://api.deepl.com
- YouTube:
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,
- Netlify:
connect-src
https://api.netlify.com
- Cloudflare Pages
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://*;
While we don’t have dedicated developer/user support resources, quick questions and feedback are welcome on the Discussions page of this GitHub repository. We also have a Discord channel for casual chat and instant help.
Looking to build a website with Sveltia CMS? Maintainer @kyoshino is available for hire depending on your requirements. Feel free to reach out!
See Contributing to Sveltia CMS.
- Introducing Sveltia CMS: a short technical presentation by @kyoshino during the This Week in Svelte online meetup on March 31, 2023 — recording & slides
This 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.
Footnotes
-
Netlify/Decap CMS #5656, #5837, #5972, #6476, #6516, #6930, #6965, #7080, #7105, #7106, #7119, #7176, #7194, #7244 — These
removeChild
crashes are common in React apps and seem to be caused by a browser extension or Google Translate. ↩ -
Netlify/Decap CMS #332, #683, #999, #1456, #4175, #5688, #6828, #6862, #7023 ↩
-
Netlify/Decap CMS #1347, #4629, #6287, #6826 — Decap 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. ↩ ↩2
-
Netlify/Decap CMS #6993, #7123, #7127, #7128, #7237, #7251 ↩
-
Netlify/Decap CMS #5815, #6522, #6532, #6588, #6617, #6640, #6663, #6695, #6697, #6764, #6765, #6835, #6983, #7205 ↩