Từ ngày chuyển blog qua Astro, mỗi lần viết bài mới, mình phải mở VS Code, tạo file markdown mới, điền frontmatter, viết nội dung, commit rồi push lên GitHub.
Quy trình không phức tạp như WordPress, nhưng vẫn hơi phiền khi muốn sửa nhanh một bài viết hoặc thay đổi metadata mà không có giao diện trực quan. Đặc biệt, không thể viết bài trên điện thoại di động — bắt buộc phải sử dụng máy tính.
Mới đây, mình đã tích hợp thêm Sveltia CMS — một open-source Git-based CMS — giúp quản lý nội dung blog hoàn toàn bằng giao diện GUI ngay trên trình duyệt. Điểm mình thích nhất: giờ có thể sửa bài, viết bài mới ngay trên điện thoại, không cần máy tính.
Bài viết này sẽ hướng dẫn cách tích hợp Sveltia CMS cho Astro, tạo nên bộ đôi hoàn hảo để quản lý bài viết cho blog.
I. Vì sao chọn Sveltia CMS?
Với blog Astro dạng static site, mọi nội dung đều lưu dưới dạng file Markdown trong repo. Cách này rất phù hợp với developer: dễ quản lý lịch sử, build nhanh, deploy đơn giản.
Tuy nhiên, khi muốn:
- Sửa nhanh tiêu đề, mô tả, tags
- Đổi ảnh đại diện cho bài viết
- Xem lại danh sách bài để chọn bài cần chỉnh
- Thêm bài mới mà không muốn cần mở VS Code
…thì thao tác thủ công trên VS Code lại trở thành rào cản.
Sveltia CMS giải quyết triệt để vấn đề này bằng giao diện web hiện đại, cho phép:
- Xem, tạo, chỉnh sửa, xóa bài viết
- Upload ảnh trực tiếp lên Cloudflare R2
- Preview nội dung trước khi publish
- Quản lý nhiều loại bài viết (blog, portfolio, sản phẩm…)
II. Giới thiệu Sveltia CMS
Sveltia CMS là một hệ thống quản lý nội dung (content management system) mã nguồn mở, miễn phí, hoạt động theo mô hình Git-based headless CMS. Đây là phiên bản kế thừa từ Netlify CMS (nay là Decap CMS), tương thích hoàn toàn với cấu hình cũ nhưng bổ sung nhiều tính năng mới.

1. Đặc điểm kiến trúc
- Single-page application (SPA): Chỉ nặng khoảng 600 KB, chạy hoàn toàn trên trình duyệt qua CDN
- Không có database riêng: Content được lưu trực tiếp trong Git repository của bạn
- Không cần tài khoản CMS: Người dùng chỉ cần đăng nhập qua tài khoản GitHub (hoặc GitLab) là đã có quyền quản lý nội dung
- Bảo mật quyền riêng tư: Không có analytics, không thu thập data
2. Luồng hoạt động
Trình duyệt (Sveltia CMS) ←→ GitHub API ←→ GitHub Repository ↑ Cloudflare R2 (ảnh)- Người dùng đăng nhập qua GitHub OAuth
- Sveltia giao tiếp với GitHub API để đọc/ghi file markdown
- Mỗi thao tác save tạo một commit mới trên branch (thường là
main) - Cloudflare Workers tự động rebuild blog khi có commit mới
- Ảnh upload lên Cloudflare R2, URL public được chèn tự động vào content
3. Vì sao nên dùng Git-based CMS?
- Toàn bộ thay đổi đều có kiểm tra qua Git history — ai sửa, sửa gì, lúc nào đều có thể tra được
- Không phụ thuộc vào bất kỳ ai: Muốn đổi Git service provider? Không vấn đề gì
- Không cần VPS hay server riêng: Chỉ cần Git repository + CDN là đủ
- Người dùng không cần biết Git: Dù nền tảng quản lý là Git, end-user vẫn thao tác bình thường qua giao diện web
III. Hướng dẫn tích hợp Sveltia CMS
1. Thêm file cấu hình CMS
Tạo file public/cms/config.yml với nội dung:
backend: name: github repo: username/repo-name branch: main skip_ci: true
media_libraries: cloudflare_r2: access_key_id: ... bucket: bucket-name account_id: ... public_url: https://<r2-public-url> prefix: images/
collections: - name: blog label: Blog folder: /src/data/blog identifier_field: title extension: md format: frontmatter frontmatter_delimiter: "---" fields: - { label: Title, name: title, widget: string } - { label: Author, name: author, widget: string, default: "Thuan Bui" } - { label: Publish Date, name: pubDatetime, widget: datetime, date_format: "YYYY-MM-DD", time_format: "HH:mm", format: "YYYY-MM-DDTHH:mm:ssZ", } - { label: Last Modified Date, name: modDatetime, widget: datetime, required: false, } - { label: Featured, name: featured, widget: boolean, default: false } - { label: Tags, name: tags, widget: list, default: [], required: false } - { label: Categories, name: categories, widget: list, default: [] } - { label: Series, name: series, widget: list, required: false } - { label: Description, name: description, widget: string, required: false, } - { label: Featured Image, name: image, widget: image, required: false } - { label: Draft, name: draft, widget: boolean, default: false } - { label: Body, name: body, widget: markdown, modes: [raw] } path: "{{year}}-{{month}}-{{day}}-{{slug}}" sortable_fields: [title, pubDatetime, modDatetime]File này gồm 3 phần chính: backend, media_libraries, và collections:
a. Backend
backend: name: github repo: username/repo-name branch: main skip_ci: truePhần này khai báo Sveltia CMS dùng GitHub làm backend:
name: github— dùng GitHub APIrepo: username/repo-name— repo chứa contentbranch: main— branch để đọc/ghiskip_ci: true— khi lưu bài viết, commit message sẽ có prefix[skip ci], Cloudflare Worker sẽ không tự động build và deploy. Muốn deploy khi lưu bài viết thì sử dụng nút “Save and Publish”.
b. Media libraries (R2)
media_libraries: cloudflare_r2: access_key_id: ... bucket: bucket-name account_id: ... public_url: https://<r2-public-url> prefix: images/Phần này cấu hình upload ảnh lên Cloudflare R2:
bucket: bucket-name— tên R2 bucketpublic_url: https://<r2-public-url>— URL public cho ảnhprefix: images/— prefix cho đường dẫn ảnh
Khi upload ảnh trong CMS, file sẽ được upload lên R2 bucket/images/ và URL public sẽ tự động được chèn vào markdown.
c. Collections
Phần collections khai báo các loại content. Mình khai báo collection Blog để quản lý bài viết với các trường thông tin sau:
| Field | Widget | Mô tả |
|---|---|---|
title | string | Tiêu đề bài viết |
pubDatetime | datetime | Ngày giờ publish |
modDatetime | datetime | Ngày giờ chỉnh sửa cuối |
featured | boolean | Bài viết nổi bật |
tags, categories, series | list | Phân loại nội dung |
description | string | Mô tả ngắn cho SEO |
image | image | Ảnh đại diện |
draft | boolean | Trạng thái nháp |
body | markdown | Nội dung bài viết |
Đặc biệt, path: "{{year}}-{{month}}-{{day}}-{{slug}}" giúp file mới tạo có format 2026-05-08-tich-hop-sveltia-cms-astro-blog.md.
2. Tạo trang CMS index
Tạo file public/cms/index.html — đây là trang HTML để load Sveltia CMS:
<!doctype html><html> <head> <meta charset="utf-8" /> <meta name="robots" content="noindex" /> <title>Sveltia CMS</title> </head> <body> <script src="https://unpkg.com/@sveltia/cms/dist/sveltia-cms.js"></script> </body></html>Sveltia CMS sẽ tự động đọc file config.yml để khởi tạo giao diện quản lý. Truy cập /cms/ là có thể bắt đầu sử dụng.
IV. Xác thực qua OAuth thay vì dùng Token
Mặc định, Sveltia CMS dùng Github Access Token (personal access token) — đây là cách đơn giản nhất, không cần cấu hình thêm.
Bấm vào Sign In Using Access Token và nhập Token để đăng nhập

Mình thích xác thực trực tiếp qua GitHub OAuth thay vì dùng token, vì:
- Không cần tạo và quản lý Github personal access token
- Đăng nhập qua trình duyệt, revoke quyền dễ dàng khi cần
Để dùng OAuth, cần phải deploy thêm Sveltia CMS Auth Worker — đây là OAuth client server chạy trên Cloudflare Workers.
1. Deploy Sveltia CMS Auth Worker
Deploy nhanh lên Cloudflare Worker theo link sau:
Truy cập: https://deploy.workers.cloudflare.com/?url=https://github.com/sveltia/sveltia-cms-auth
Bấm Create an deploy để tạo Worker mới

Sau khi deploy, copy URL Worker (ví dụ: https://sveltia-cms-auth.xxx.workers.dev) để dùng cấu hình cho Github OAuth App.
2. Tạo GitHub OAuth Application
Tiếp theo, cần tạo OAuth App trên GitHub để lấy Client ID và Client Secret:
- Truy cập Settings > Developer Settings > OAuth Apps
- Click New OAuth App
- Điền thông tin:
- Application name:
Sveltia CMS(tùy ý) - Homepage URL:
<YOUR_WORKER_URL> - Authorization callback URL:
<YOUR_WORKER_URL>/callback
- Application name:
- Bấm Register applicaton để tạo

Bấm vào nút Generate a new client secret.

Lưu Client ID và Client Secret để cấu hình bên Worker.

3. Lưu Client ID và Client Secret vào Worker
Quay lại Worker vừa tạo, truy cập vào phần Settings > bấm Add ở mục Variables and Secrets

Nhập vào 2 thông số sau và bấm Deploy
GITHUB_CLIENT_ID= Client ID từ OAuth AppGITHUB_CLIENT_SECRET= Client Secret

4. Cập nhật config.yml
Thêm base_url vào config.yml và push lên Github để Cloudflare cập nhật thông số
backend: name: github repo: username/repo-name branch: main base_url: https://sveltia-cms-auth.xxx.workers.devGiờ mình đã có thể đăng nhập bằng cách bấm vào nút Sign In with Github để đăng nhập bằng tài khoản Github

V. Trải nghiệm sử dụng thực tế
Quy trình viết bài của mình trở nên linh hoạt hơn hẳn, có thể dùng VS Code hoặc Sveltia CMS tùy tình huống:
- VS Code: Phù hợp khi viết bài dài, cần nhiều chỉnh sửa code, hoặc làm việc offline
- Sveltia CMS: Phù hợp khi cần sửa nhanh metadata, viết bài ngắn trên điện thoại, hoặc upload ảnh nhanh
Giao diện quản lý bài viết của Sveltia CMS

Sau khi tích hợp Sveltia CMS, mình vẫn dùng VS Code cho các bài viết dài và phức tạp. Nhưng với những lúc cần sửa vội một bài trên điện thoại, Sveltia CMS là lựa chọn tiện lợi hơn nhiều.
- Chỉnh sửa metadata cực nhanh, không cần mở code
- Upload ảnh trực tiếp lên R2
- Preview bài viết trước khi publish
- Đánh dấu draft, tìm kiếm bài viết qua giao diện.
Sveltia CMS có tích hợp sẵn Lexica Editor để chỉnh sửa bài viết trực quan, nhưng mình thích dùng markdown nên chọn chế độ raw mode.

VI. Kết luận
Sveltia CMS là giải pháp tuyệt vời cho blog Astro: nhẹ, miễn phí, không cần server riêng, tích hợp cực nhanh (chỉ 2 file), quản lý nội dung qua UI hiện đại, upload ảnh trực tiếp lên R2.
Nếu bạn đang sử dụng Astro xây dựng blog, hãy thử tích hợp Sveltia CMS — đảm bảo sẽ tiện lợi hơn rất nhiều!
Chúc bạn cài đặt thành công!