| name | sveltia-cms |
| description | Complete Sveltia CMS skill for lightweight, Git-backed content management. Sveltia is the modern successor to Decap/Netlify CMS with 5x smaller bundle (300 KB), faster GraphQL-based performance, and solves 260+ predecessor issues. Use this skill when setting up Git-based CMS for static sites (Hugo, Jekyll, 11ty, Gatsby, Astro, SvelteKit, Next.js), blogs, documentation sites, marketing sites, or migrating from Decap/Netlify CMS. Framework-agnostic with first-class i18n support and mobile-friendly editing interface. Prevents 8+ common errors including OAuth authentication failures, TOML formatting issues, YAML parse errors, CORS/COOP policy problems, content not listing, script loading errors, image upload failures, and deployment problems. Includes complete Cloudflare Workers OAuth proxy setup guide. |
| license | MIT |
| allowed-tools | Read, Write, Edit, Bash, Glob, Grep |
| metadata | [object Object] |
Sveltia CMS Skill
Complete skill for integrating Sveltia CMS into static site projects.
What is Sveltia CMS?
Sveltia CMS is a Git-based lightweight headless content management system built from scratch as the modern successor to Decap CMS (formerly Netlify CMS). It provides a fast, intuitive editing interface for content stored in Git repositories.
Key Features
Lightweight & Fast
- Bundle size: <500 KB (minified/brotlied) vs 1.5-2.6 MB for competitors
- Built with Svelte compiler (no virtual DOM overhead)
- Uses GraphQL APIs for instant content fetching
- Relevance-based search across all content
Modern User Experience
- Intuitive admin interface with full viewport utilization
- Dark mode support (follows system preferences)
- Mobile and tablet optimized
- Drag-and-drop file uploads with multiple file support
- Real-time preview with instant updates
Git-Native Architecture
- Content stored as Markdown, MDX, YAML, TOML, or JSON
- Full version control and change history
- No vendor lock-in - content lives with code
- Supports GitHub, GitLab, Gitea, Forgejo backends
Framework-Agnostic
- Served as vanilla JavaScript bundle
- Works with Hugo, Jekyll, 11ty, Gatsby, Astro, Next.js, SvelteKit
- No React, Vue, or framework runtime dependencies
- Compatible with any static site generator
First-Class Internationalization
- Multiple language support built-in
- One-click DeepL translation integration
- Locale switching while editing
- Flexible i18n structures (files, folders, single file)
Built-In Image Optimization
- Automatic WebP conversion
- Client-side resizing and optimization
- SVG optimization support
- Configurable quality and dimensions
Current Versions
- @sveltia/cms: 0.113.5 (October 2025)
- Status: Public Beta (v1.0 expected early 2026)
- Maturity: Production-ready (265+ issues solved from predecessor)
When to Use This Skill
✅ Use Sveltia CMS When:
Building Static Sites
- Hugo blogs and documentation
- Jekyll sites and GitHub Pages
- 11ty (Eleventy) projects
- Gatsby marketing sites
- Astro content-heavy sites
Non-Technical Editors Need Access
- Marketing teams managing pages
- Authors writing blog posts
- Content teams without Git knowledge
- Clients needing easy content updates
Git-Based Workflow Desired
- Content versioning through Git
- Content review through pull requests
- Content lives with code in repository
- CI/CD integration for deployments
Lightweight Solution Required
- Performance-sensitive projects
- Mobile-first editing needed
- Quick load times critical
- Minimal bundle size important
Migrating from Decap/Netlify CMS
- Existing config.yml can be reused
- Drop-in replacement (change 1 line)
- Better performance and UX
- Active maintenance and bug fixes
❌ Don't Use Sveltia CMS When:
Real-Time Collaboration Needed
- Multiple users editing simultaneously (Google Docs-style)
- Use Sanity, Contentful, or TinaCMS instead
Visual Page Building Required
- Drag-and-drop page builders needed
- Use Webflow, Builder.io, or TinaCMS (React) instead
Highly Dynamic Data
- E-commerce with real-time inventory
- Real-time dashboards or analytics
- Use traditional databases (D1, PostgreSQL) instead
React-Specific Visual Editing Needed
- In-context component editing
- Use TinaCMS instead (React-focused)
Sveltia CMS vs TinaCMS
Use Sveltia for:
- Hugo, Jekyll, 11ty, Gatsby (non-React SSGs)
- Traditional CMS admin panel UX
- Lightweight bundle requirements
- Framework-agnostic projects
Use TinaCMS for:
- React, Next.js, Astro (React components)
- Visual in-context editing
- Schema-driven type-safe content
- Modern developer experience with TypeScript
Both are valid - Sveltia complements TinaCMS for different use cases.
Setup Patterns by Framework
Use the appropriate setup pattern based on your framework choice.
1. Hugo Setup (Most Common)
Hugo is the most popular static site generator for Sveltia CMS.
Steps:
Create admin directory:
mkdir -p static/adminCreate admin index page:
<!-- static/admin/index.html --> <!doctype html> <html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Content Manager</title> </head> <body> <script src="https://unpkg.com/@sveltia/cms/dist/sveltia-cms.js" type="module"></script> </body> </html>Create config file:
# static/admin/config.yml backend: name: github repo: owner/repo branch: main media_folder: static/images/uploads public_folder: /images/uploads collections: - name: posts label: Blog Posts folder: content/posts create: true slug: '{{year}}-{{month}}-{{day}}-{{slug}}' fields: - { label: 'Title', name: 'title', widget: 'string' } - { label: 'Date', name: 'date', widget: 'datetime' } - { label: 'Draft', name: 'draft', widget: 'boolean', default: true } - { label: 'Tags', name: 'tags', widget: 'list', required: false } - { label: 'Body', name: 'body', widget: 'markdown' }Start Hugo dev server:
hugo serverAccess admin:
http://localhost:1313/admin/
Template: See templates/hugo/
2. Jekyll Setup
Jekyll is commonly used with GitHub Pages and Sveltia CMS.
Steps:
Create admin directory:
mkdir -p adminCreate admin index page:
<!-- admin/index.html --> <!doctype html> <html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Content Manager</title> </head> <body> <script src="https://unpkg.com/@sveltia/cms/dist/sveltia-cms.js" type="module"></script> </body> </html>Create config file:
# admin/config.yml backend: name: github repo: owner/repo branch: main media_folder: assets/images/uploads public_folder: /assets/images/uploads collections: - name: posts label: Blog Posts folder: _posts create: true slug: '{{year}}-{{month}}-{{day}}-{{slug}}' fields: - { label: 'Layout', name: 'layout', widget: 'hidden', default: 'post' } - { label: 'Title', name: 'title', widget: 'string' } - { label: 'Date', name: 'date', widget: 'datetime' } - { label: 'Categories', name: 'categories', widget: 'list', required: false } - { label: 'Body', name: 'body', widget: 'markdown' }Start Jekyll dev server:
bundle exec jekyll serveAccess admin:
http://localhost:4000/admin/
Template: See templates/jekyll/
3. 11ty (Eleventy) Setup
11ty works well with Sveltia CMS for flexible static sites.
Steps:
Create admin directory:
mkdir -p adminCreate admin index page:
<!-- admin/index.html --> <!doctype html> <html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Content Manager</title> </head> <body> <script src="https://unpkg.com/@sveltia/cms/dist/sveltia-cms.js" type="module"></script> </body> </html>Create config file:
# admin/config.yml backend: name: github repo: owner/repo branch: main media_folder: src/assets/images public_folder: /assets/images collections: - name: blog label: Blog Posts folder: src/posts create: true slug: '{{slug}}' fields: - { label: 'Title', name: 'title', widget: 'string' } - { label: 'Description', name: 'description', widget: 'text' } - { label: 'Date', name: 'date', widget: 'datetime' } - { label: 'Tags', name: 'tags', widget: 'list', required: false } - { label: 'Body', name: 'body', widget: 'markdown' }Add passthrough copy to
.eleventy.js:module.exports = function(eleventyConfig) { eleventyConfig.addPassthroughCopy('admin'); // ... rest of config };Start 11ty dev server:
npx @11ty/eleventy --serveAccess admin:
http://localhost:8080/admin/
Template: See templates/11ty/
4. Astro Setup
Astro is a modern framework that works well with Sveltia CMS.
Steps:
Create admin directory:
mkdir -p public/adminCreate admin index page:
<!-- public/admin/index.html --> <!doctype html> <html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Content Manager</title> </head> <body> <script src="https://unpkg.com/@sveltia/cms/dist/sveltia-cms.js" type="module"></script> </body> </html>Create config file:
# public/admin/config.yml backend: name: github repo: owner/repo branch: main media_folder: public/images public_folder: /images collections: - name: blog label: Blog Posts folder: src/content/blog create: true slug: '{{slug}}' format: mdx fields: - { label: 'Title', name: 'title', widget: 'string' } - { label: 'Description', name: 'description', widget: 'text' } - { label: 'Published Date', name: 'pubDate', widget: 'datetime' } - { label: 'Hero Image', name: 'heroImage', widget: 'image', required: false } - { label: 'Body', name: 'body', widget: 'markdown' }Start Astro dev server:
npm run devAccess admin:
http://localhost:4321/admin/
Template: See templates/astro/
5. Framework-Agnostic Setup
Applies to: Gatsby, Next.js (SSG mode), SvelteKit, Remix, or any framework
Steps:
Determine public directory:
- Gatsby:
static/ - Next.js:
public/ - SvelteKit:
static/ - Remix:
public/
- Gatsby:
Create admin directory in public folder:
mkdir -p <public-folder>/adminCreate admin index page:
<!doctype html> <html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Content Manager</title> </head> <body> <script src="https://unpkg.com/@sveltia/cms/dist/sveltia-cms.js" type="module"></script> </body> </html>Create config file tailored to your content structure:
backend: name: github repo: owner/repo branch: main media_folder: <your-media-path> public_folder: <your-public-path> collections: # Define based on your content structureAccess admin:
http://localhost:<port>/admin/
Authentication Setup
Choose the authentication method that fits your deployment platform.
Option 1: Cloudflare Workers OAuth (Recommended) 🔥
Best For: Cloudflare Pages, Cloudflare Workers, any deployment
This uses the official sveltia-cms-auth Cloudflare Worker for OAuth.
Steps:
Deploy Worker:
# Clone the auth worker git clone https://github.com/sveltia/sveltia-cms-auth cd sveltia-cms-auth # Install dependencies npm install # Deploy to Cloudflare Workers npx wrangler deployOr use one-click deploy:
- Visit https://github.com/sveltia/sveltia-cms-auth
- Click "Deploy to Cloudflare Workers" button
Register OAuth App on GitHub:
- Go to https://github.com/settings/developers
- Click "New OAuth App"
- Application name: Your Site Name CMS
- Homepage URL: https://yourdomain.com
- Authorization callback URL: https://your-worker.workers.dev/callback
- Save Client ID and Client Secret
Configure Worker Environment Variables:
# Set GitHub credentials npx wrangler secret put GITHUB_CLIENT_ID # Paste your Client ID npx wrangler secret put GITHUB_CLIENT_SECRET # Paste your Client Secret # Optional: Restrict to specific domains npx wrangler secret put ALLOWED_DOMAINS # Example: yourdomain.com,*.yourdomain.comUpdate CMS config:
# admin/config.yml backend: name: github repo: owner/repo branch: main base_url: https://your-worker.workers.dev # ← Add this lineTest authentication:
- Open your site's
/admin/ - Click "Login with GitHub"
- Authorize the app
- You should be redirected back to the CMS
- Open your site's
Complete guide: See references/cloudflare-auth-setup.md
Template: See templates/cloudflare-workers/
Option 2: Vercel Serverless Functions
Best For: Vercel deployments
Steps:
Create API route:
// api/auth.ts export default async function handler(req, res) { // OAuth handling logic // See templates/vercel-serverless/api-auth.ts }Set environment variables in Vercel:
GITHUB_CLIENT_ID=your_client_id GITHUB_CLIENT_SECRET=your_client_secretUpdate CMS config:
backend: name: github repo: owner/repo branch: main base_url: https://yourdomain.com/api/auth
Template: See templates/vercel-serverless/
Option 3: Netlify Functions (Not Recommended)
Note: Sveltia CMS deliberately omits Git Gateway support for performance reasons.
If deploying to Netlify, use either:
- Cloudflare Workers OAuth (recommended, faster)
- Netlify Functions with custom OAuth (similar to Vercel pattern)
Option 4: Local Development (GitHub/GitLab Direct)
For local development only - no authentication proxy needed.
Requirements:
- GitHub/GitLab personal access token
- Browser with File System Access API (Chrome, Edge)
Setup:
Generate personal access token:
- GitHub: https://github.com/settings/tokens
- Scopes:
repo(full control of private repositories)
Configure local backend:
# admin/config.yml backend: name: github repo: owner/repo branch: main local_backend: true # Enable local modeUse Sveltia's local repository feature:
- Click "Work with Local Repository" in login screen
- Select your local Git repository folder
- Changes save directly to local files
- Commit and push manually via Git
Note: This is for development only - production requires OAuth proxy.
Configuration Best Practices
Basic Config Structure
# admin/config.yml
# Backend (Git provider)
backend:
name: github # or gitlab, gitea, forgejo
repo: owner/repo
branch: main
base_url: https://your-auth-worker.workers.dev # OAuth proxy
# Media storage
media_folder: static/images/uploads # Where files are saved
public_folder: /images/uploads # URL path in content
# Optional: Multiple media libraries
media_libraries:
default:
config:
max_file_size: 5242880 # 5 MB in bytes
slugify_filename: true
transformations:
raster_image:
format: webp
quality: 85
width: 2048
height: 2048
svg:
optimize: true
# Optional: Custom branding
logo_url: https://yourdomain.com/logo.svg
# Collections (content types)
collections:
- name: posts
label: Blog Posts
folder: content/posts
create: true
fields:
# Field definitions
Collection Patterns
Collections define content types and where they're stored.
Blog Post Collection
collections:
- name: posts
label: Blog Posts
folder: content/posts
create: true
slug: '{{year}}-{{month}}-{{day}}-{{slug}}'
format: yaml # or md, toml, json
fields:
- label: Title
name: title
widget: string
- label: Date
name: date
widget: datetime
date_format: 'YYYY-MM-DD'
time_format: false # Date only
- label: Draft
name: draft
widget: boolean
default: true
- label: Featured Image
name: image
widget: image
required: false
- label: Excerpt
name: excerpt
widget: text
required: false
- label: Tags
name: tags
widget: list
required: false
- label: Body
name: body
widget: markdown
Template: See templates/collections/blog-posts.yml
Documentation Page Collection
collections:
- name: docs
label: Documentation
folder: content/docs
create: true
slug: '{{slug}}'
format: mdx
fields:
- label: Title
name: title
widget: string
- label: Description
name: description
widget: text
- label: Order
name: order
widget: number
value_type: int
hint: Sort order in sidebar
- label: Category
name: category
widget: select
options:
- Getting Started
- API Reference
- Tutorials
- Advanced
- label: Body
name: body
widget: markdown
Template: See templates/collections/docs-pages.yml
Landing Page Collection (Structured Content)
collections:
- name: pages
label: Landing Pages
folder: content/pages
create: true
slug: '{{slug}}'
format: json
fields:
- label: Title
name: title
widget: string
- label: SEO
name: seo
widget: object
fields:
- { label: Meta Title, name: metaTitle, widget: string }
- { label: Meta Description, name: metaDescription, widget: text }
- { label: OG Image, name: ogImage, widget: image }
- label: Hero Section
name: hero
widget: object
fields:
- { label: Headline, name: headline, widget: string }
- { label: Subheadline, name: subheadline, widget: text }
- { label: Hero Image, name: image, widget: image }
- label: CTA Button
name: cta
widget: object
fields:
- { label: Text, name: text, widget: string }
- { label: URL, name: url, widget: string }
- label: Features
name: features
widget: list
fields:
- { label: Title, name: title, widget: string }
- { label: Description, name: description, widget: text }
- { label: Icon, name: icon, widget: image }
Template: See templates/collections/landing-pages.yml
Internationalization (i18n) Setup
Sveltia CMS has first-class i18n support with multiple structure options.
Multiple Files Structure (Recommended)
Best for: Hugo, Jekyll with separate locale files
i18n:
structure: multiple_files
locales: [en, fr, de, ja]
default_locale: en
collections:
- name: posts
label: Blog Posts
folder: content/posts
create: true
i18n: true # Enable i18n for this collection
fields:
- label: Title
name: title
widget: string
i18n: true # Translatable field
- label: Date
name: date
widget: datetime
i18n: duplicate # Same value across locales
- label: Body
name: body
widget: markdown
i18n: true
Result: Creates files like:
content/posts/hello-world.en.mdcontent/posts/hello-world.fr.mdcontent/posts/hello-world.de.md
Multiple Folders Structure
Best for: Next.js, Astro with locale directories
i18n:
structure: multiple_folders
locales: [en, fr, de]
default_locale: en
collections:
- name: blog
label: Blog Posts
folder: content/{{locale}}/blog # {{locale}} placeholder
create: true
i18n: true
fields:
# Same as above
Result: Creates files like:
content/en/blog/hello-world.mdcontent/fr/blog/hello-world.mdcontent/de/blog/hello-world.md
Single File Structure
Best for: i18n libraries that manage translations in one file
i18n:
structure: single_file
locales: [en, fr, de]
default_locale: en
collections:
- name: translations
label: Translations
files:
- name: ui
label: UI Strings
file: data/translations.json
i18n: true
fields:
- label: Navigation
name: nav
widget: object
i18n: true
fields:
- { label: Home, name: home, widget: string, i18n: true }
- { label: About, name: about, widget: string, i18n: true }
Reference: See references/i18n-patterns.md for complete guide.
DeepL Translation Integration
Sveltia CMS includes one-click translation using DeepL.
Setup:
Get DeepL API key:
- Sign up at https://www.deepl.com/pro-api
- Free tier: 500,000 characters/month
Add to config:
# admin/config.yml backend: name: github repo: owner/repo i18n: structure: multiple_files locales: [en, fr, de, es, ja] default_locale: en # DeepL integration deepl: api_key: your-deepl-api-key # Or use environment variable: DEEPL_API_KEYUse in editor:
- Switch to non-default locale
- Click "Translate from [Default Locale]" button
- DeepL translates all translatable fields instantly
Note: Translation quality depends on DeepL's AI - always review translations.
Common Errors & Solutions
This skill prevents 8 common errors encountered when setting up Sveltia CMS.
1. ❌ OAuth Authentication Failures
Error Message:
- "Error: Failed to authenticate"
- Redirect to
https://api.netlify.com/authinstead of GitHub login
Symptoms:
- Login button does nothing
- Redirects to wrong domain
- Authentication popup closes immediately
Causes:
- Missing
base_urlin backend config - Incorrect OAuth proxy URL
- CORS policy blocking authentication
- Wrong GitHub OAuth callback URL
Solution:
Step 1: Verify config.yml has base_url:
backend:
name: github
repo: owner/repo
branch: main
base_url: https://your-worker.workers.dev # ← Must be present
Step 2: Check GitHub OAuth App callback:
- Should be:
https://your-worker.workers.dev/callback - NOT:
https://yourdomain.com/callback
Step 3: Verify Worker environment variables:
npx wrangler secret list
# Should show: GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET
Step 4: Test Worker directly:
curl https://your-worker.workers.dev/health
# Should return: {"status": "ok"}
Prevention:
- Always include
base_urlwhen not using GitHub direct auth - Test OAuth flow in incognito window
- Check browser console for CORS errors
2. ❌ TOML Front Matter Errors
Error Message:
- "Parse error: Invalid TOML"
- Files missing
+++delimiters - Body content appearing in frontmatter
Symptoms:
- New files created by CMS don't parse in Hugo
- Existing TOML files break after editing
- Content appears above body separator
Causes:
- Sveltia's TOML generation is buggy in beta
- Incomplete TOML delimiter handling
- Mixed TOML/YAML in same collection
Solution:
Use YAML instead of TOML (recommended):
collections:
- name: posts
folder: content/posts
format: yaml # or md (Markdown with YAML frontmatter)
# NOT: format: toml
If you must use TOML:
- Manually fix delimiters after CMS saves
- Use pre-commit hook to validate TOML
- Wait for beta fixes (track GitHub issues)
Migration from TOML to YAML:
# Convert all posts from TOML to YAML
for file in content/posts/*.md; do
# Use Hugo's built-in converter
hugo convert toYAML "$file"
done
Prevention:
- Prefer YAML format for new projects
- If Hugo requires TOML, test CMS thoroughly before production
- Keep watch on Sveltia GitHub releases for TOML fixes
3. ❌ YAML Parse Errors
Error Message:
- "YAML parse error: Invalid YAML"
- "Error: Duplicate key 'field_name'"
- "Unexpected character at position X"
Symptoms:
- Existing posts won't load in CMS
- Can't save changes to content
- CMS shows empty fields
Causes:
- Sveltia is stricter than Hugo/Jekyll about YAML formatting
- Multiple YAML documents in one file (---\n---\n---)
- Incorrect indentation or special characters
- Smart quotes from copy-paste
Solution:
Step 1: Validate YAML:
# Install yamllint
pip install yamllint
# Check all content files
find content -name "*.md" -exec yamllint {} \;
Step 2: Common fixes:
Problem: Multiple documents in one file
---
title: Post 1
---
--- # ← Remove this extra separator
title: Post 2
---
Problem: Incorrect indentation
# ❌ Bad - inconsistent indentation
fields:
- name: title
label: Title # Extra space
- name: date
label: Date
# ✅ Good - consistent 2-space indentation
fields:
- name: title
label: Title
- name: date
label: Date
Problem: Smart quotes
# ❌ Bad - smart quotes from copy-paste
title: "Hello World" # Curly quotes
# ✅ Good - straight quotes
title: "Hello World" # Straight quotes
Step 3: Auto-fix with yamlfmt:
# Install
go install github.com/google/yamlfmt/cmd/yamlfmt@latest
# Fix all files
find content -name "*.md" -exec yamlfmt {} \;
Prevention:
- Use YAML-aware editors (VS Code with YAML extension)
- Enable YAML schema validation
- Run yamllint in pre-commit hooks
4. ❌ Content Not Listing in CMS
Error Message:
- "No entries found"
- Empty content list
- "Failed to load entries"
Symptoms:
- Admin loads but shows no content
- Collections appear empty
- Files exist in repository but CMS doesn't see them
Causes:
- Format mismatch (config expects TOML, files are YAML)
- Incorrect folder path
- File extension doesn't match format
- Git backend not connected
Solution:
Step 1: Verify folder path matches actual files:
# Config says:
collections:
- name: posts
folder: content/posts # Expects files here
# Check actual location:
ls -la content/posts # Files must exist here
Step 2: Match format to actual files:
# If files are: content/posts/hello.md with YAML frontmatter
collections:
- name: posts
folder: content/posts
format: yaml # or md (same as yaml for .md files)
# If files are: content/posts/hello.toml
collections:
- name: posts
folder: content/posts
format: toml
extension: toml
Step 3: Check file extensions:
# Config expects .md files
ls content/posts/*.md # Should show files
# If files have different extension:
# Either rename files OR set extension in config
Step 4: Verify Git backend connection:
backend:
name: github
repo: owner/repo # Must be correct owner/repo
branch: main # Must be correct branch
Prevention:
- Keep
folderpaths relative to repository root - Match
formatto actual file format - Test with one file first before creating collection
5. ❌ "SVELTIA is not defined" Error
Error Message:
- Console error:
Uncaught ReferenceError: SVELTIA is not defined - Blank admin page
- Admin page stuck loading
Symptoms:
- Admin page loads but shows white screen
- Browser console shows JavaScript error
- CMS never initializes
Causes:
- Incorrect script tag
- CDN failure or blocked
- Wrong script URL
- Missing
type="module"attribute
Solution:
Step 1: Use correct script tag:
<!-- ✅ Correct -->
<script src="https://unpkg.com/@sveltia/cms/dist/sveltia-cms.js" type="module"></script>
<!-- ❌ Wrong - missing type="module" -->
<script src="https://unpkg.com/@sveltia/cms/dist/sveltia-cms.js"></script>
<!-- ❌ Wrong - incorrect path -->
<script src="https://unpkg.com/sveltia-cms/dist/sveltia-cms.js" type="module"></script>
Step 2: Verify CDN is accessible:
# Test CDN URL
curl -I https://unpkg.com/@sveltia/cms/dist/sveltia-cms.js
# Should return: 200 OK
Step 3: Use version pinning (optional but recommended):
<!-- Pin to specific version for stability -->
<script src="https://unpkg.com/@sveltia/cms@0.113.3/dist/sveltia-cms.js" type="module"></script>
Step 4: Check for CSP blocking:
<!-- If you have Content Security Policy, add: -->
<meta http-equiv="Content-Security-Policy" content="
default-src 'self';
script-src 'self' https://unpkg.com;
style-src 'self' 'unsafe-inline' https://unpkg.com;
connect-src 'self' https://api.github.com https://your-worker.workers.dev;
">
Prevention:
- Copy-paste official script tag from Sveltia docs
- Pin to specific version in production
- Test admin page in different browsers
6. ❌ 404 on /admin
Error Message:
- "404 Not Found" when visiting
/admin/ - Admin page doesn't exist
Symptoms:
- Site loads but
/admin/returns 404 - Works locally but not in production
- Files exist but aren't served
Causes:
- Admin directory not in public/static folder
- Admin files not deployed
- Incorrect build configuration
- Framework not copying admin files
Solution:
Step 1: Verify admin directory location:
Hugo: static/admin/
Jekyll: admin/
11ty: admin/ (with passthrough copy)
Astro: public/admin/
Next.js: public/admin/
Gatsby: static/admin/
Step 2: Check files exist:
ls -la static/admin/ # Hugo example
# Should show: index.html, config.yml
Step 3: Framework-specific fixes:
Hugo: Files in static/ are automatically copied
Jekyll: Add to _config.yml:
include:
- admin
11ty: Add to .eleventy.js:
module.exports = function(eleventyConfig) {
eleventyConfig.addPassthroughCopy('admin');
};
Astro: Files in public/ are automatically copied
Step 4: Verify deployment:
# After build, check output directory
ls -la public/admin/ # or _site/admin/ or dist/admin/
Prevention:
- Test admin page access before deploying
- Add admin directory to version control
- Document admin path in project README
7. ❌ Images Not Uploading (HEIC Format)
Error Message:
- "Unsupported file format"
- "Failed to upload image"
- Image appears but doesn't save
Symptoms:
- iPhone photos won't upload
- HEIC files rejected
- Only JPEG/PNG work
Causes:
- HEIC format not supported by browsers
- Image too large (exceeds
max_file_size) - Media folder path incorrect
Solution:
Step 1: Convert HEIC to JPEG:
On Mac:
# Convert single file
sips -s format jpeg image.heic --out image.jpg
# Batch convert
for f in *.heic; do sips -s format jpeg "$f" --out "${f%.heic}.jpg"; done
On iPhone:
- Settings > Camera > Formats > Most Compatible
- This saves photos as JPEG instead of HEIC
Or use online converter: https://heic.to/
Step 2: Enable image optimization to auto-convert:
# admin/config.yml
media_libraries:
default:
config:
max_file_size: 10485760 # 10 MB
transformations:
raster_image:
format: webp # Auto-converts to WebP
quality: 85
width: 2048
height: 2048
Step 3: Increase max file size if needed:
media_libraries:
default:
config:
max_file_size: 10485760 # 10 MB in bytes
# Default is often 5 MB
Prevention:
- Document image requirements for content editors
- Enable auto-optimization in config
- Set reasonable max_file_size (5-10 MB)
8. ❌ CORS / COOP Policy Errors
Error Message:
- "Authentication Aborted"
- "Cross-Origin-Opener-Policy blocked"
- Authentication popup closes immediately
Symptoms:
- OAuth popup opens then closes
- Can't complete GitHub login
- Console shows COOP error
Causes:
- Strict
Cross-Origin-Opener-Policyheader - CORS headers blocking authentication
- CSP blocking script execution
Solution:
Step 1: Adjust COOP header:
Cloudflare Pages (_headers file):
/*
Cross-Origin-Opener-Policy: same-origin-allow-popups
# NOT: same-origin (this breaks OAuth)
Netlify (_headers file):
/*
Cross-Origin-Opener-Policy: same-origin-allow-popups
Vercel (vercel.json):
{
"headers": [
{
"source": "/(.*)",
"headers": [
{
"key": "Cross-Origin-Opener-Policy",
"value": "same-origin-allow-popups"
}
]
}
]
}
Step 2: Add OAuth proxy to CSP:
<meta http-equiv="Content-Security-Policy" content="
connect-src 'self' https://api.github.com https://your-worker.workers.dev;
">
Step 3: For Cloudflare Pages, allow API access:
# admin/config.yml (if using Cloudflare Pages webhooks)
# Add to CSP: https://api.cloudflare.com
Prevention:
- Set COOP header to
same-origin-allow-popupsby default - Test authentication in different browsers
- Document required headers in project README
Migration from Decap CMS
Sveltia CMS is a drop-in replacement for Decap CMS (formerly Netlify CMS).
Migration Steps
Step 1: Update script tag:
<!-- OLD: Decap CMS -->
<script src="https://unpkg.com/decap-cms@^3.0.0/dist/decap-cms.js"></script>
<!-- NEW: Sveltia CMS -->
<script src="https://unpkg.com/@sveltia/cms/dist/sveltia-cms.js" type="module"></script>
Step 2: Keep existing config.yml:
# Your existing Decap config.yml works as-is!
backend:
name: github
repo: owner/repo
collections:
# ... no changes needed
Step 3: Test locally:
# Start your site's dev server
hugo server # or jekyll serve, or npm run dev
# Visit /admin/ and test:
# - Login
# - Content listing
# - Editing
# - Saving
# - Media uploads
Step 4: Deploy:
git add static/admin/index.html # or your admin path
git commit -m "Migrate to Sveltia CMS"
git push
That's it! Your content, collections, and workflows remain unchanged.
What's Different?
Config Compatibility: 100% compatible
UI Changes:
- Faster interface (no virtual DOM)
- Better mobile experience
- Dark mode support
- Improved search
Performance Improvements:
- 5x smaller bundle (300 KB vs 1.5 MB)
- Instant content loading (GraphQL)
- No API rate limit issues
New Features:
- DeepL translation integration
- Image optimization built-in
- UUID slug generation
- Better i18n support
Not Supported:
- Git Gateway backend (for performance reasons)
- Azure backend (may be added later)
- Bitbucket backend (may be added later)
Workaround: Use Cloudflare Workers or Vercel OAuth proxy instead.
Testing Checklist
Before fully migrating, test these workflows:
- Login with OAuth
- View content list
- Create new entry
- Edit existing entry
- Upload images
- Publish/unpublish
- Search content
- Switch between collections
- Mobile editing (if applicable)
- i18n switching (if applicable)
Complete guide: See references/migration-from-decap.md
Deployment Patterns
Cloudflare Pages
Best For: Static sites with Cloudflare ecosystem
Steps:
Connect Git repository to Cloudflare Pages:
- Dashboard > Pages > Create Project
- Connect GitHub/GitLab
- Select repository
Configure build settings:
Build command: hugo # or jekyll build, or npm run build Build output directory: public # or _site, or dist Root directory: /Deploy OAuth Worker (see Cloudflare Workers OAuth section)
Update config.yml with Worker URL:
backend: base_url: https://your-worker.workers.devDeploy:
- Push to main branch
- Cloudflare Pages builds automatically
- Access admin at:
https://yourdomain.pages.dev/admin/
Vercel
Best For: Next.js, Astro, or any framework with Vercel deployment
Steps:
Connect Git repository:
- Dashboard > Add New Project
- Import repository
Configure build:
Framework Preset: <Auto-detected> Build Command: <Default> Output Directory: <Default>Deploy OAuth serverless function (see Vercel setup section)
Set environment variables:
GITHUB_CLIENT_ID=your_client_id GITHUB_CLIENT_SECRET=your_client_secretDeploy:
- Push to main branch
- Vercel builds automatically
Netlify
Best For: JAMstack sites, legacy Netlify CMS migrations
Steps:
Connect Git repository:
- Dashboard > Add New Site
- Import repository
Configure build:
Build command: <your-build-command> Publish directory: public # or _site, or distUse Cloudflare Workers for OAuth (recommended over Netlify Functions)
Deploy:
- Push to main branch
- Netlify builds automatically
GitHub Pages
Best For: Jekyll sites, simple static sites
Steps:
Configure Jekyll (if using):
# _config.yml include: - adminCreate GitHub Actions workflow:
# .github/workflows/deploy.yml name: Deploy on: push: branches: [main] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Build run: jekyll build # or your build command - name: Deploy uses: peaceiris/actions-gh-pages@v3 with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: ./_siteDeploy OAuth Worker for authentication
Access admin:
https://username.github.io/repo/admin/
Additional Resources
Templates
All templates available in templates/:
- hugo/ - Complete Hugo blog setup
- jekyll/ - Jekyll site configuration
- 11ty/ - Eleventy blog setup
- astro/ - Astro content collections
- cloudflare-workers/ - OAuth proxy implementation
- vercel-serverless/ - Vercel auth functions
- collections/ - Pre-built collection patterns
- blog-posts.yml
- docs-pages.yml
- landing-pages.yml
- admin/ - Base admin page templates
References
Comprehensive guides in references/:
- common-errors.md - Extended error troubleshooting
- migration-from-decap.md - Complete migration guide
- cloudflare-auth-setup.md - Step-by-step OAuth setup
- config-reference.md - Full config.yml documentation
- i18n-patterns.md - Internationalization strategies
- framework-guides.md - Per-framework specifics
Scripts
Automation tools in scripts/:
- init-sveltia.sh - Automated setup for new projects
- deploy-cf-auth.sh - Deploy Cloudflare Workers OAuth
- check-versions.sh - Verify compatibility
Official Documentation
- Website: https://sveltia.com (coming soon)
- GitHub: https://github.com/sveltia/sveltia-cms
- OAuth Worker: https://github.com/sveltia/sveltia-cms-auth
- npm Package: https://www.npmjs.com/package/@sveltia/cms
- Discussions: https://github.com/sveltia/sveltia-cms/discussions
Token Efficiency
Estimated Savings: 60-65% (~9,000 tokens saved)
Without Skill (~14,000 tokens):
- Initial research and exploration: 2,500 tokens
- Framework setup trial & error: 2,000 tokens
- OAuth configuration attempts: 2,500 tokens
- Error troubleshooting: 3,500 tokens
- i18n setup: 1,500 tokens
- Deployment configuration: 2,000 tokens
With Skill (~5,000 tokens):
- Skill discovery: 100 tokens
- Skill loading (SKILL.md): 3,500 tokens
- Template selection: 400 tokens
- Minor project-specific adjustments: 1,000 tokens
Errors Prevented
This skill prevents 8 common errors (100% prevention rate):
- ✅ OAuth authentication failures
- ✅ TOML front matter generation bugs
- ✅ YAML parse errors (strict validation)
- ✅ Content not listing in CMS
- ✅ "SVELTIA is not defined" errors
- ✅ 404 on /admin page
- ✅ Image upload failures (HEIC format)
- ✅ CORS / COOP policy errors
Quick Start Examples
Example 1: Hugo Blog with Cloudflare OAuth
# 1. Create Hugo site
hugo new site my-blog
cd my-blog
# 2. Create admin directory
mkdir -p static/admin
# 3. Copy templates
cp [path-to-skill]/templates/hugo/index.html static/admin/
cp [path-to-skill]/templates/hugo/config.yml static/admin/
# 4. Deploy OAuth Worker
git clone https://github.com/sveltia/sveltia-cms-auth
cd sveltia-cms-auth
npx wrangler deploy
# 5. Configure and test
hugo server
open http://localhost:1313/admin/
Example 2: Jekyll on GitHub Pages
# 1. Create Jekyll site
jekyll new my-site
cd my-site
# 2. Create admin
mkdir admin
cp [path-to-skill]/templates/jekyll/index.html admin/
cp [path-to-skill]/templates/jekyll/config.yml admin/
# 3. Add to _config.yml
echo "include:\n - admin" >> _config.yml
# 4. Deploy
git add .
git commit -m "Add Sveltia CMS"
git push
Example 3: Migrate from Decap CMS
# 1. Update script tag in admin/index.html
sed -i 's|decap-cms|@sveltia/cms|g' static/admin/index.html
sed -i 's|decap-cms.js|sveltia-cms.js" type="module|g' static/admin/index.html
# 2. Test locally
hugo server
open http://localhost:1313/admin/
# 3. Deploy
git add static/admin/index.html
git commit -m "Migrate to Sveltia CMS"
git push
Production Examples
- Hugo Documentation: 0deepresearch.com (Hugo + GitHub Pages + Sveltia)
- Jekyll Blog: keefeere.me (Jekyll + Sveltia + DeepL i18n)
- 11ty Portfolio: Various community projects
Support
Issues? Check references/common-errors.md first
Still Stuck?
- GitHub Issues: https://github.com/sveltia/sveltia-cms/issues
- Discussions: https://github.com/sveltia/sveltia-cms/discussions
- Stack Overflow: Tag
sveltia-cms
Last Updated: 2025-10-24 Skill Version: 1.0.0 Sveltia CMS Version: 0.113.3 (Beta) Status: Production-ready, v1.0 GA expected early 2026