Xây stack thay thế Supabase với Next.js, Prisma, PostgreSQL và S3
Supabase rất mạnh: database PostgreSQL, Auth, Storage, Realtime, Edge Functions, dashboard đẹp. Nhưng khi sản phẩm lớn hơn, nhiều team muốn kiểm soát sâu hơn: schema migration rõ hơn, auth tùy biến hơn, storage riêng hơn, chi phí dự đoán hơn, ít phụ thuộc vendor hơn.
Stack Next.js + Prisma + PostgreSQL + S3 là lựa chọn thực tế. Không phải “clone Supabase” hoàn toàn, mà là dựng nền tảng backend đủ mạnh cho SaaS, marketplace, CMS, app nội bộ, sản phẩm AI, hoặc dashboard doanh nghiệp.
Ý tưởng: Next.js xử lý frontend + API, Prisma quản lý data layer, PostgreSQL làm database chính, S3 lưu file/object. Thêm auth, queue, realtime nếu cần. Stack này ít màu mè hơn Supabase, nhưng linh hoạt, dễ scale, dễ debug.
Vì sao muốn thay Supabase?
Supabase giúp launch nhanh. Nhưng có vài điểm khiến team cân nhắc tự dựng stack:
Kiểm soát kiến trúc tốt hơn
Supabase gom nhiều thứ vào một nền tảng. Tiện, nhưng đôi khi khó tùy biến sâu. Khi cần luồng business phức tạp, quyền truy cập nhiều tầng, audit log, workflow doanh nghiệp, hoặc tích hợp legacy system, tự quản backend dễ hơn.
Migration và schema rõ hơn
Prisma có migration file, schema typed, code review dễ. Dev thấy thay đổi database ngay trong repo. CI/CD chạy migration có kiểm soát. Với team nhiều người, điều này giảm lỗi production.
Chi phí dễ tính hơn
Supabase tính theo compute, storage, bandwidth, project plan. Với app nhiều file, nhiều query, hoặc workload bất thường, tự dùng PostgreSQL managed + S3-compatible storage có thể dễ tối ưu hơn.
Tránh lock-in nhẹ
PostgreSQL và S3 là chuẩn phổ biến. Prisma chạy với nhiều database. Next.js deploy nhiều nơi. Nếu đổi nhà cung cấp, app ít bị kẹt.
model File {
id String @id @default(cuid())
key String @unique
bucket String
filename String
contentType String
size Int
userId String
organizationId String?
createdAt DateTime @default(now())
user User @relation(fields: [userId], references: [id])
organization Organization? @relation(fields: [organizationId], references: [id])
@@index([userId])
@@index([organizationId])
}
enum Role {
OWNER
ADMIN
MEMBER
}
Nguyên tắc schema
– Dùng foreign key để giữ dữ liệu sạch.
– Thêm unique constraint cho email, slug, key.
– Thêm index cho field hay filter: userId, organizationId, createdAt.
– Dùng transaction cho thao tác nhiều bảng.
– Không lưu file binary trong PostgreSQL. Lưu metadata, file thật để S3.
Prisma: type-safe data layer
Prisma giúp query dễ đọc, type tự sinh từ schema. Ví dụ lấy organization kèm quyền user:
Sau khi client upload thành công, gọi API khác để lưu metadata vào PostgreSQL.
Bảo mật storage
– Presigned URL phải hết hạn ngắn, ví dụ 60 giây.
– Validate contentType, size, extension.
– Scan virus nếu file nhạy cảm.
– Bucket private mặc định.
– Download cũng nên dùng presigned URL.
– Không public toàn bộ bucket trừ khi là asset công khai.
Auth và phân quyền
Supabase Auth là phần khó thay nhất nếu tự làm. Có 3 hướng:
Auth.js
Phù hợp nếu muốn open-source, tự host, OAuth provider, session trong database. Kết hợp Prisma adapter khá ổn.
Clerk
Nhanh, UI đẹp, nhiều tính năng enterprise. Nhưng lại phụ thuộc vendor khác. Tốt nếu team muốn tiết kiệm thời gian auth.
Custom auth
Chỉ nên làm khi có yêu cầu đặc biệt. Password login cần hash chuẩn, reset token, email verification, rate limit, session rotation. Sai auth là rủi ro lớn.
– Bật connection pooling cho PostgreSQL.
– Dùng Prisma migration trong CI/CD.
– Backup database hằng ngày.
– Bật point-in-time recovery nếu có.
– Log lỗi với Sentry.
– Rate limit endpoint nhạy cảm.
– Tách biến môi trường dev/staging/prod.
– Theo dõi query chậm.
– Dọn file orphan: file đã upload S3 nhưng không có metadata DB.
– Lifecycle rule cho S3: xóa temp object sau vài ngày.
Vấn đề hay gặp
Serverless + Prisma + PostgreSQL có thể gây nhiều connection. Dùng pooler như PgBouncer, Neon pooling, hoặc Prisma Accelerate nếu phù hợp.
Upload thành công nhưng lưu DB lỗi tạo orphan object. Cần job cleanup theo prefix temp/.
DB có record nhưng S3 thiếu file xảy ra khi client báo sai. Có thể dùng flow: upload vào temp/, server verify bằng HeadObject, rồi chuyển trạng thái READY.
So sánh thực tế với Supabase
Stack tự dựng mạnh ở:
– Kiểm soát code và schema.
– Tích hợp business logic phức tạp.
– Dễ đổi vendor storage/database.
– Type safety tốt với Prisma.
– Phù hợp team backend mạnh.
Supabase mạnh ở:
– Launch cực nhanh.
– Dashboard quản trị tiện.
– Auth và Storage có sẵn.
– Realtime tích hợp.
– Ít code hạ tầng ban đầu.
Nói ngắn: nếu cần MVP nhanh, Supabase thắng. Nếu cần nền tảng dài hạn, quy trình kỹ thuật chặt, quyền phức tạp, hoặc chi phí riêng, stack Next.js + Prisma + PostgreSQL + S3 đáng chọn.
Kết luận thực tế
Không cần ghét Supabase để xây stack thay thế. Supabase giải bài toán tốc độ. Stack tự dựng giải bài toán kiểm soát.
Cách tốt nhất: bắt đầu nhỏ. Dựng Next.js, Prisma, PostgreSQL trước. Thêm auth ổn định. Sau đó đưa file sang S3 bằng presigned URL. Chỉ thêm realtime, queue, cache khi có nhu cầu thật.
Kiến trúc tốt không phải nhiều service. Kiến trúc tốt là ít phần, rõ trách nhiệm, dễ debug, dễ thay. Với Next.js, Prisma, PostgreSQL và S3, bạn có nền móng đủ bền để đi từ MVP đến production nghiêm túc mà không phụ thuộc quá nhiều vào một nền tảng duy nhất.