Quay lại danh sách
22 tháng 2, 2026·6 phút đọcSanityHeadlessCMS

Quản lý nội dung Web cá nhân: Tại sao mình chọn Sanity?

Tự build nguyên một CMS cho web cá nhân thì khá cồng kềnh. Bài viết này mình chia sẻ lý do chọn Sanity làm Headless CMS, cùng với cách mình kẹp thêm Express.js làm proxy để bảo mật tuyệt đối API token.

Quản lý nội dung Web cá nhân: Tại sao mình chọn Sanity?

Ngay khi mình thực hiện trang web này thì mình cũng đã nghĩ tới việc viết các bài viết để chia sẻ kiến thức, kinh nghiệm cá nhân của mình với mọi người. Nhưng mà nếu mình tự build nguyên 1 CMS cho mỗi cái portfolio thì đúng là “Đem dao mổ trâu đi giết gà”, khá là tốn thời gian cũng như là công sức ấy.

Thế là sau 1 hồi dạo ChatGPT thì mình tìm được Sanity. Nó giải quyết gọn nhẹ bài toán của mình: có chỗ quản lý nội dung đàng hoàng mà không phải nai lưng ra code thêm nguyên một cái Admin Panel hay lo chuyện tìm hosting cho database.

Vậy Sanity rốt cuộc là gì?

Headless CMS là chân ái

Chắc anh em dev không lạ gì khái niệm Headless CMS. Giải thích nhanh thì nó "chặt" phần hiển thị (Frontend) ra khỏi phần quản trị dữ liệu (Backend/Admin).

Với Sanity, họ cung cấp sẵn hạ tầng lưu trữ (Cloud) và một bộ mã nguồn gọi là Sanity Studio để mình tự dựng giao diện nhập liệu. Việc của mình là định nghĩa các trường dữ liệu, gõ nội dung, ấn lưu. Còn việc lấy đống data đó ra hiển thị bằng Next.js, React hay framework nào... là do mình toàn quyền quyết định.

Trang nphuonha.id.vn của mình hiện tại chỉ xoay quanh 3 luồng nội dung: Projects, News và các trang tĩnh như Privacy Policy. Dùng Sanity là quá đủ, bớt được hẳn khâu hì hục dựng DB và viết API CRUD cồng kềnh.

Flow làm việc thực tế

Chơi với Sanity khá nhàn, flow cơ bản nó chạy như thế này:

1. Khởi tạo Studio phút mốt Gõ đúng một lệnh:

bash
1npm create sanity@latest

Nó sẽ sinh ra một thư mục chứa source code của trang Admin. Bạn cứ chạy localhost lên là có ngay chỗ nhập liệu.

Và cái hay nhất ở đây là: Bạn không cần phải mang cái cục Admin này lên Vercel hay VPS để host! Code cấu hình xong xuôi, chỉ cần gõ thêm lệnh npx sanity deploy, Sanity sẽ tự động ném cái Studio này lên server của họ và ném lại cho bạn một cái link (kiểu tên-project.sanity.studio). Nhàn tênh, đỡ tốn một slot deploy bên Vercel.

2. Giao diện sinh ra từ Code (Schema-driven) Đây là cái mình khoái nhất. Mình không cần phải vào UI kéo thả để tạo bảng trong DB. Cần form nhập liệu có field gì, kiểu dữ liệu ra sao thì cứ định nghĩa thẳng bằng JavaScript/TypeScript.

Ví dụ file project.ts của mình trông thế này:

typescript
1export default {
2  name: 'project',
3  title: 'Dự án của tôi',
4  type: 'document',
5  fields: [
6    { name: 'title', title: 'Tên dự án', type: 'string' },
7    { 
8      name: 'slug', 
9      title: 'Đường dẫn URL', 
10      type: 'slug', 
11      options: { source: 'title' } 
12    },
13    { name: 'mainImage', title: 'Ảnh minh họa', type: 'image' }
14  ]
15}

Lưu file lại là giao diện Admin tự update ra một cái form có đủ ô text, ô tự sinh slug và component upload ảnh. Cực kỳ hợp tư duy của dev.

3. Lấy dữ liệu và cách mình "độ" lại flow bảo mật

Bình thường, Sanity có một ngôn ngữ truy vấn tên là GROQ (Graph-Relational Object Queries) khá mạnh. Kịch bản gốc là bạn sẽ lấy token của Sanity và gọi thẳng API từ Frontend để kéo data về.

Nhưng đây là lúc mình phải đi bài riêng.

Việc phơi token của Sanity thẳng ra phía client không phải là cách làm hay về mặt bảo mật (nhất là khi token đó có quyền đọc các bài viết đang draft). Solution của mình là kẹp thêm một con server Express.js đứng giữa làm proxy.

  • Token của Sanity sẽ được giấu kín trong file .env trên server Express.js.
  • Frontend khi cần data sẽ gọi vào API nội bộ của Express.
  • Express cầm token, dùng GROQ chọc vào Sanity lấy dữ liệu, sau đó trả JSON về cho Frontend.

Code phía Express.js nó sẽ sương sương như này:

typescript
1app.get('/api/projects', async (req, res) => {
2  try {
3    // Gọi Sanity từ Backend, Token được giấu kín
4    const projects = await sanityClient.fetch(`*[_type == "project"]{ title, slug, "imageUrl": mainImage.asset->url }`);
5    
6    res.json(projects);
7  } catch (error) {
8    res.status(500).json({ error: 'Lỗi kéo data từ Sanity' });
9  }
10});

Tốn thêm chút thời gian dựng cái backend trung gian, nhưng đổi lại là kê cao gối ngủ, data flow rõ ràng và an toàn hơn.

Tóm lại

Nếu anh em muốn build blog, portfolio hay web cá nhân mà lười đụng vào database/backend truyền thống, Sanity thực sự là một option đáng thử. Setup nhanh, tuỳ biến mạnh bằng code, lại có gói Free tier bao la. Kết hợp nó với một proxy backend như Express.js là đủ để có một hệ thống mượt mà và bảo mật.

Phuong Nha Nguyen
Bài trướcCách mình xây hệ thống hỗ trợ người dùng bằng email cho FestiaBài tiếp theoServlet Starter Kit - Modern Java Web Starter Project