Khi xây dựng website cho khách hàng, lập trình viên thường đứng trước một lựa chọn quen thuộc: dùng WordPress cho nhanh, thuê một headless CMS dạng SaaS, hay tự viết trang quản trị. Mỗi hướng đều có cái giá riêng, từ việc khó tùy biến, chi phí tăng theo lượng dữ liệu, cho tới hàng tuần công sức làm lại những thứ ai cũng cần. Payload CMS đi theo một hướng khác: một CMS mã nguồn mở, viết bằng TypeScript, cấu hình hoàn toàn bằng code và chạy ngay bên trong ứng dụng Next.js của bạn. Bài viết này giới thiệu Payload từ góc nhìn của một đội phát triển đang dùng nó trong dự án thực tế.
Payload là gì?
Payload tự giới thiệu là một framework fullstack cho Next.js. Bạn có thể dùng nó như một headless CMS, nhưng cũng có thể dùng để xây công cụ nội bộ, nền tảng thương mại điện tử hay hệ thống quản lý tài sản số. Từ phiên bản 3.0, Payload được cài thẳng vào thư mục app của một dự án Next.js, nghĩa là trang quản trị, API và website có thể nằm chung một codebase và triển khai cùng nhau.
Một số đặc điểm nổi bật:
- Cấu hình bằng code: collection, field, quyền truy cập đều khai báo trong file TypeScript, dễ review và quản lý phiên bản bằng Git.
- Trang quản trị tự sinh: giao diện admin bằng React được tạo ra từ cấu hình, và có thể mở rộng bằng component riêng.
- Nhiều cách truy cập dữ liệu: REST API, GraphQL và Local API gọi trực tiếp từ code server.
- Hỗ trợ nhiều cơ sở dữ liệu thông qua adapter, gồm MongoDB và PostgreSQL, bên cạnh SQLite.
- Tính năng sẵn có: xác thực người dùng, phân quyền chi tiết, upload file kèm resize ảnh, bản nháp và lịch sử phiên bản, đa ngôn ngữ nội dung, live preview và trình soạn thảo rich text dựa trên Lexical.
Định nghĩa dữ liệu bằng collection
Trung tâm của Payload là collection, tương ứng với một loại nội dung như bài viết, sản phẩm hay người dùng. Một collection bài viết đơn giản trông như sau:
import type { CollectionConfig } from "payload";
export const Posts: CollectionConfig = {
slug: "posts",
admin: { useAsTitle: "title" },
access: { read: () => true },
fields: [
{ name: "title", type: "text", required: true },
{ name: "slug", type: "text", unique: true },
{ name: "content", type: "richText" },
{ name: "category", type: "relationship", relationTo: "categories" },
],
};Chỉ từ cấu hình này, Payload sinh ra bảng hoặc collection trong database, form chỉnh sửa trên trang admin, các endpoint API và cả kiểu TypeScript tương ứng. Khi bạn thêm một trường mới, mọi thứ cập nhật đồng bộ, không phải sửa ở nhiều nơi.
Local API: truy vấn dữ liệu không qua HTTP
Đây là điểm khiến Payload đặc biệt hợp với Next.js. Trong Server Component hoặc route handler, bạn gọi thẳng vào Payload mà không cần một request HTTP nào:
import { getPayload } from "payload";
import config from "@payload-config";
const payload = await getPayload({ config });
const posts = await payload.find({ collection: "posts", limit: 10 });Kết quả được gõ kiểu đầy đủ, nên trình soạn thảo sẽ gợi ý đúng tên trường và báo lỗi khi bạn truy cập trường không tồn tại. Cần lưu ý: theo tài liệu, Local API mặc định bỏ qua kiểm tra quyền truy cập. Khi xử lý dữ liệu thay mặt người dùng, hãy truyền overrideAccess: false kèm thông tin user để quy tắc phân quyền được áp dụng.
Phân quyền linh hoạt
Quyền truy cập trong Payload là các hàm, nên bạn có thể viết bất kỳ logic nào: chỉ admin được xóa, tác giả chỉ sửa bài của mình, khách chỉ đọc bài đã xuất bản. Hàm phân quyền có thể trả về true hoặc false, hoặc trả về một điều kiện truy vấn để lọc dữ liệu theo người dùng. Quyền còn có thể đặt ở cấp field, ví dụ ẩn trường giá vốn với nhân viên bán hàng.
Khi nào nên chọn Payload?
Payload phù hợp khi:
- Đội ngũ đã quen TypeScript và React, đặc biệt khi dự án dùng Next.js.
- Cần mô hình dữ liệu tùy biến sâu, có quan hệ phức tạp, hoặc logic nghiệp vụ gắn liền với nội dung.
- Muốn tự chủ hạ tầng và dữ liệu, không phụ thuộc vào gói cước của nhà cung cấp SaaS.
- Cần trang quản trị cho khách hàng mà không muốn tự xây từ đầu.
Ngược lại, hãy cân nhắc giải pháp khác nếu người vận hành cần tự dựng trang bằng kéo thả mà không có lập trình viên hỗ trợ, hoặc nếu team không có kinh nghiệm JavaScript. Bạn cũng sẽ tự chịu trách nhiệm về hosting, sao lưu database và cập nhật phiên bản, điều mà các dịch vụ SaaS lo hộ.
Bắt đầu nhanh
Cách nhanh nhất để thử là dùng lệnh npx create-payload-app@latest, chọn template và cơ sở dữ liệu, rồi chạy server phát triển. Template website có sẵn trang blog, trang tĩnh và live preview, là điểm khởi đầu tốt để khám phá cách các thành phần kết nối với nhau.
Kết luận
Payload mang đến cách làm CMS rất "thuận tay" cho lập trình viên: mọi thứ là code TypeScript, kiểu dữ liệu xuyên suốt từ database tới giao diện, và CMS sống chung với ứng dụng Next.js thay vì là một hệ thống tách rời. Với các dự án cần tùy biến cao và đội ngũ quen hệ sinh thái React, đây là lựa chọn đáng cân nhắc nghiêm túc. Hãy thử một dự án nhỏ để cảm nhận trước khi đưa vào sản phẩm lớn.






