Bức tường quy mô: Khi Firebase bắt đầu gây khó
Firebase giống như giai đoạn “trăng mật” tuyệt vời đối với các nhà phát triển. Thật thỏa mãn khi có thể thiết lập cơ sở dữ liệu, xác thực và hosting chỉ trong chưa đầy mười phút.
But with many people, this relationship gradually turns sour as the project grows. You start with a simple chat app, but suddenly customers need a complex dashboard that requires joining data from five different collections. In Firestore’s NoSQL world, you’re forced to choose: either fetch thousands of records to process on the client side — reducing performance — or maintain redundant data everywhere.
Gần đây tôi đã di chuyển một ứng dụng production nơi chi phí đọc (read cost) của Firebase lên tới 400 USD mỗi tháng cho một lượng người dùng tương đối nhỏ. Tính nhất quán của dữ liệu đã trở thành một cơn ác mộng. Nếu bạn từng dành cả đêm thứ Sáu để debug tại sao avatar của người dùng đã cập nhật trong hồ sơ nhưng vẫn giữ nguyên trong các bài đăng của họ, thì bạn đã chạm tới bức tường quy mô rồi đó.
Tại sao dữ liệu quan hệ lại “ngạt thở” trong NoSQL
Vấn đề không phải là Firebase được xây dựng kém; mà là NoSQL thường là công cụ sai cho dữ liệu quan hệ, có cấu trúc. Hầu hết các ứng dụng về bản chất là quan hệ. Người dùng có bài đăng, bài đăng có bình luận, và bình luận có lượt thích.
Firestore buộc bạn phải chọn giữa hai phương án khó khăn: lồng nhau (nesting) hoặc bộ sưu tập phẳng (flat collections). Việc lồng nhau khiến các truy vấn độc lập gần như không thể thực hiện được. Trong khi đó, các bộ sưu tập phẳng yêu cầu bạn phải viết các lệnh “join” thủ công trong code frontend. Sự lệch lạc về kiến trúc này tạo ra three điểm yếu cụ thể:
- Thuế dư thừa: Bạn kết thúc bằng việc lưu cùng một tên người dùng trong mười tài liệu khác nhau chỉ để tránh các lượt đọc bổ sung, gây lãng phí lưu trữ và băng thông.
- Dữ liệu “ma”: Cập nhật một mẩu thông tin trên mười vị trí hiếm khi thành công 100% nếu không có các transaction (giao dịch) phức tạp và tốn kém.
- Bảo mật cồng kềnh: Firebase Security Rules là mã nguồn đóng. Khi chúng vượt quá 500 dòng, chúng trở thành một “hộp đen” không thể tìm kiếm và cực kỳ đáng sợ khi kiểm tra (audit).
Giải pháp: Sự đơn giản của BaaS với sức mạnh của SQL
Khi bạn đã vượt quá khả năng của Firebase, bước đi truyền thống là xây dựng một backend tùy chỉnh bằng Node.js hoặc Go với cơ sở dữ liệu PostgreSQL. Mặc dù điều này mang lại quyền kiểm soát toàn diện, bạn lại mất đi cảm giác “live” (thời gian thực) và tính năng xác thực sẵn có giúp Firebase trở nên hiệu quả. Bạn cũng phải gánh thêm gánh nặng quản lý hạ tầng máy chủ.
Supabase mang đến một con đường thứ ba thông minh hơn. Nó không phải là một hệ sinh thái đóng; nó là một bộ các công cụ mã nguồn mở mạnh mẽ như PostgreSQL, GoTrue cho Auth, và Realtime được đóng gói thành một trải nghiệm duy nhất. Bạn có được cấu trúc chặt chẽ của SQL kết hợp với trải nghiệm phát triển mượt mà của một BaaS hiện đại.
Các trụ cột của Supabase: Bảo mật và Cập nhật thời gian thực
Thay thế Firebase đòi hỏi nhiều hơn là chỉ một cấu trúc bảng. Bạn cần một lớp bảo mật vững chắc và khả năng đẩy các cập nhật tới người dùng ngay lập tức.
1. PostgreSQL và Row Level Security (RLS)
Hãy quên việc viết các quy tắc bằng một ngôn ngữ giống JSON tùy chỉnh đi. Supabase sử dụng Row Level Security (RLS), một tính năng gốc của PostgreSQL. Bảo mật nằm ngay bên trong cơ sở dữ liệu, chứ không phải trong code ứng dụng của bạn. Ngay cả khi một kẻ tấn công đánh cắp public API key của bạn, chính cơ sở dữ liệu sẽ từ chối trả về bất kỳ dòng nào không khớp với ID đã được xác thực của người dùng.
-- Ví dụ: Một chính sách bảo mật đơn giản và chặt chẽ
ALTER TABLE profiles ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Người dùng chỉ có thể xem dữ liệu của chính mình"
ON profiles FOR SELECT
USING (auth.uid() = id);
Đây là một chiến thắng lớn cho sự an tâm. Logic bảo mật của bạn được xử lý bởi Postgres — một database engine với hơn 30 năm thử thách thực tế — thay vì một script tùy chỉnh của nhà cung cấp đám mây.
2. Realtime Subscriptions có khả năng mở rộng
Nhiều nhà phát triển ở lại với Firebase chỉ vì tính năng đồng bộ thời gian thực. Supabase đáp ứng điều này bằng cách lắng nghe luồng replication của PostgreSQL (WAL). Khi một dòng thay đổi, server sẽ phát đi sự thay đổi đó qua WebSockets. Dưới đây là một triển khai điển hình cho chat hoặc thông báo:
import { createClient } from '@supabase/supabase-client'
const supabase = createClient('PROJECT_URL', 'ANON_KEY')
const channel = supabase
.channel('room-1')
.on('postgres_changes',
{ event: 'INSERT', schema: 'public', table: 'messages' },
payload => console.log('Nhận được tin nhắn mới!', payload)
)
.subscribe()
Bạn có được sự phản hồi tức thì đó mà không phải hy sinh khả năng thực hiện các thao tác JOIN phức tạp hoặc tìm kiếm toàn văn (full-text search) trên cùng một tập dữ liệu.
Mẹo nhỏ: Làm sạch dữ liệu trước khi di chuyển
Di chuyển dữ liệu là thời điểm tốt nhất để dọn dẹp “nợ dữ liệu”. Việc chuyển từ NoSQL hoặc các hệ thống cũ thường đi kèm với việc xử lý các tệp CSV lộn xộn. Để chuẩn bị dữ liệu nhanh chóng, tôi sử dụng toolcraft.app/vi/tools/data/csv-to-json. Nó chạy hoàn toàn trong trình duyệt của bạn, đảm bảo dữ liệu nhạy cảm không bao giờ rời khỏi máy cục bộ. Đây là cách nhanh nhất để định dạng các dữ liệu cũ trước khi nhập chúng vào dashboard của Supabase.
Bản kế hoạch triển khai tốt hơn
Nếu bạn đang bắt đầu một dự án mới, hãy làm theo quy trình này để đảm bảo backend của bạn vẫn có thể quản lý được trong nhiều năm tới:
- Định nghĩa Schema trước: Đừng chỉ làm tùy hứng. Sử dụng foreign keys (khóa ngoại) để duy trì tính toàn vẹn tham chiếu. Điều này ngăn chặn các lỗi “dữ liệu mồ côi” thường thấy trong các ứng dụng NoSQL.
- Khóa cửa ngay lập tức: Đừng bao giờ để một bảng mà không có chính sách RLS. Hãy bật RLS ngay giây phút bạn tạo bảng.
- Sử dụng Type Generation: Supabase có thể tự động tạo các type TypeScript từ schema của bạn. Điều này hầu như loại bỏ các lỗi “undefined is not a function” phổ biến khi xử lý các tài liệu Firebase không được định kiểu.
- Chuyển logic sang Edge Functions: Đối với các tác vụ không nên nằm ở phía client — như xử lý thanh toán Stripe hoặc gọi API của bên thứ ba — hãy sử dụng Supabase Edge Functions. Đó là các hàm Deno serverless được triển khai toàn cầu chỉ trong vài giây.
Mặc dù lộ trình học SQL ban đầu có thể dốc hơn một chút so with NoSQL, but the long-term benefits are huge. You won’t have to rewrite your entire architecture just because your data relationships become complex. Supabase provides the bridge to help you start fast and mở rộng đúng cách.

