Xây SaaS không Supabase: Backend linh hoạt để tăng trưởng

24/05/2026 · P T P · Chung

Xây SaaS không dùng Supabase: kiến trúc backend linh hoạt cho tăng trưởng

Supabase giúp khởi đầu nhanh: database, auth, storage, realtime, API. Nhưng khi SaaS lớn dần, câu hỏi đổi: nhanh hôm nay có đủ bền cho ngày mai không?

Nhiều đội chọn Supabase vì muốn ship MVP nhanh. Đúng. Nhưng không phải SaaS nào cũng hợp với backend-as-a-service. Khi sản phẩm bắt đầu có nhiều tenant, logic phân quyền phức tạp, workload nặng, yêu cầu compliance, hoặc cần kiểm soát hạ tầng sâu hơn, kiến trúc tự chủ đáng xem xét.

Không dùng Supabase không có nghĩa quay về “tự build mọi thứ từ đầu”. Nghĩa đúng hơn: thiết kế backend bằng các khối chuẩn, thay thế được, mở rộng được, không bị khóa vào một nền tảng duy nhất.

Bài này đi vào kiến trúc thực tế cho SaaS tăng trưởng: database, API, auth, background jobs, file storage, observability, deployment, multi-tenancy và chiến lược mở rộng.


Vì sao không dùng Supabase?

Supabase mạnh ở giai đoạn đầu. Nhưng vài giới hạn thường xuất hiện khi SaaS lớn hơn.

Kiểm soát kiến trúc hạn chế

Supabase gom nhiều lớp vào cùng trải nghiệm: Postgres, Auth, Storage, Edge Functions, Realtime. Tiện, nhưng cũng làm kiến trúc dễ phụ thuộc vào cách Supabase tổ chức dịch vụ.

Khi cần:

– Custom auth flow sâu
– Multi-region phức tạp
– Tách service theo domain
– Kiểm soát connection pooling
– Tối ưu query lớn
– Tuân thủ quy định dữ liệu riêng

… đội dev thường phải đi vòng hoặc rời bớt khỏi Supabase.

Rủi ro vendor lock-in

Postgres vẫn là Postgres, nhưng Auth schema, Storage API, Realtime channel, Edge Functions, policy pattern có thể gắn chặt với hệ sinh thái Supabase.

Nếu sau này migrate, chi phí không chỉ là chuyển data. Còn phải đổi:

– Logic phân quyền
– SDK frontend
– API contract
– File URL pattern
– Webhook
– Background workflows
– Monitoring setup

SaaS tăng trưởng cần backend “thay ruột được”

Backend tốt không phải backend có nhiều tính năng nhất. Backend tốt là backend cho phép thay từng phần mà không phá cả hệ thống.

Ví dụ:

– Đổi Redis provider không ảnh hưởng business logic
– Đổi S3-compatible storage không đổi API client
– Đổi auth provider không rewrite app
– Tách billing service ra riêng khi doanh thu tăng
– Chuyển một module sang worker queue khi traffic tăng

Đó là mục tiêu chính.


Nguyên tắc kiến trúc: modular, explicit, boring

SaaS tăng trưởng không cần công nghệ lạ. Cần nền tảng rõ.

Modular: chia theo domain

Thay vì chia code theo kỹ thuật như controllers, services, models, nên chia theo domain:

src/
  modules/
    auth/
    billing/
    teams/
    projects/
    notifications/
    files/
  shared/
    db/
    queue/
    config/
    logger/

Mỗi module có:

– API routes
– Service logic
– Repository/database access
– Validation schema
– Events riêng

Lợi ích: khi domain lớn, dễ tách thành service riêng. Không cần microservices từ ngày đầu, nhưng code phải sẵn đường tách.

Explicit: logic rõ, không ẩn quá nhiều

Backend-as-a-service thường ẩn nhiều phần: auth state, row-level policy, generated API, storage permission. Khi lỗi xảy ra, debug khó hơn.

Kiến trúc tự chủ nên làm rõ:

– Ai gọi API nào
– Permission check ở đâu
– Transaction nằm đâu
– Event nào phát ra sau action
– Job nào chạy nền
– Data model nào là nguồn sự thật

Rõ hơn, dễ vận hành hơn.

Boring: chọn công nghệ bền

Stack gợi ý:

API: Node.js + NestJS/Fastify, Go, hoặc Django
Database: PostgreSQL
Cache/queue: Redis
Job queue: BullMQ, Faktory, Sidekiq, Celery
Storage: S3 hoặc S3-compatible như Cloudflare R2, MinIO
Search: Meilisearch, OpenSearch, Typesense
Observability: OpenTelemetry, Prometheus, Grafana, Sentry
Deployment: Docker, Kubernetes khi cần, hoặc ECS/Fly.io/Render/Railway giai đoạn đầu

Không cần mới. Cần ổn.


Database: Postgres làm lõi, nhưng đừng để thành “thần hộ mệnh”

PostgreSQL vẫn là lựa chọn tốt cho SaaS: ACID, indexing mạnh, JSONB, full-text search cơ bản, partitioning, extensions.

Thiết kế schema cho tăng trưởng

Các bảng SaaS thường có tenant/team/workspace:

CREATE TABLE projects (
  id UUID PRIMARY KEY,
  tenant_id UUID NOT NULL,
  name TEXT NOT NULL,
  created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE INDEX idx_projects_tenant_id ON projects (tenant_id);

Quy tắc:

– Mọi bảng thuộc tenant nên có tenant_id
– Index theo tenant_id + trường lọc thường dùng
– Không lạm dụng JSONB cho dữ liệu cần query nhiều
– Có migration version rõ
– Dùng transaction cho workflow quan trọng

Multi-tenancy: chọn đúng cấp cô lập

Có ba mô hình phổ biến:

1. Shared database, shared schema
– Mỗi row có tenant_id
– Rẻ, dễ vận hành
– Phù hợp hầu hết SaaS B2B giai đoạn đầu

2. Shared database, separate schema
– Mỗi tenant một schema
– Cô lập hơn
– Migration phức tạp hơn

3. Database riêng từng tenant
– Cô lập mạnh
– Phù hợp enterprise/compliance
– Chi phí vận hành cao

Khuyến nghị thực tế: bắt đầu với shared schema, thiết kế abstraction để có thể đưa enterprise tenant sang database riêng sau.

Row-Level Security hay application-level authorization?

Supabase dùng nhiều RLS. Nếu tự build, có thể dùng RLS hoặc kiểm tra quyền trong app.

RLS tốt khi cần chặn lỗi query thiếu tenant filter
App-level authorization tốt khi logic quyền phức tạp, cần test rõ, cần audit

Nhiều SaaS dùng kết hợp: app-level cho business rule, RLS cho lớp bảo vệ cuối.


API layer: hợp đồng ổn định quan trọng hơn framework

API là biên giới giữa frontend, mobile app, integration, webhook và worker.

REST, GraphQL hay tRPC?

REST: rõ, bền, dễ cache, hợp public API
GraphQL: hợp client phức tạp, cần query linh hoạt
tRPC: nhanh cho TypeScript full-stack, ít hợp public API dài hạn

Nếu SaaS có kế hoạch mở API cho khách hàng, REST với OpenAPI là lựa chọn an toàn.

Validation và error contract

Đừng để frontend đoán lỗi. Chuẩn hóa response:

{
  "error": {
    "code": "PROJECT_LIMIT_REACHED",
    "message": "Project limit reached for current plan."
  }
}

Mỗi endpoint cần:

– Validate input
– Kiểm tra auth
– Kiểm tra permission
– Gọi service
– Log event quan trọng
– Trả lỗi có code ổn định

API tốt giúp sản phẩm dễ mở rộng integration.


Auth: tự build ít nhất có thể, kiểm soát nhiều nhất cần thiết

Auth là nơi không nên “tự chế” nếu không có lý do mạnh. Không dùng Supabase Auth không nghĩa là tự viết password hashing, session, OAuth từ đầu.

Lựa chọn tốt:

– Auth0
– Clerk
– WorkOS
– Keycloak
– FusionAuth
– Ory
– Lucia/Auth.js nếu muốn code-level control

SaaS B2B cần gì?

Auth cho SaaS B2B thường cần:

– Email/password hoặc magic link
– OAuth Google/Microsoft
– Organization/team membership
– Roles/permissions
– SSO/SAML cho enterprise
– SCIM nếu bán cho công ty lớn
– Audit log

Tách rõ hai khái niệm:

Identity: user là ai
Authorization: user được làm gì trong tenant nào

Đừng gắn role trực tiếp vào user toàn cục nếu SaaS có nhiều workspace. Một user có thể là admin ở workspace A, viewer ở workspace B.


Background jobs: tăng trưởng bắt đầu khi request không còn đủ

Nhiều việc không nên chạy trong HTTP request:

– Gửi email
– Tạo invoice
– Xử lý file
– Đồng bộ CRM
– Gọi webhook
– Tính analytics
– Import dữ liệu
– Retry payment

Dùng queue từ sớm giúp hệ thống chịu tải tốt hơn.

API request
  -> ghi database
  -> publish event/job
  -> trả response nhanh
Worker
  -> xử lý job
  -> retry nếu lỗi
  -> log kết quả

Cần có:

– Retry với backoff
– Dead-letter queue
– Idempotency key
– Job timeout
– Dashboard quan sát job

Không có idempotency, retry có thể tạo double charge, double email, double webhook. Đây là lỗi SaaS rất đau.


File storage: abstraction nhỏ, lợi ích lớn

Đừng để code gọi trực tiếp provider khắp nơi. Tạo interface:

interface StorageService {
  upload(path: string, body: Buffer): Promise<string>;
  getSignedUrl(path: string): Promise<string>;
  delete(path: string): Promise<void>;
}

Sau đó dùng S3, R2, GCS, Azure Blob hoặc MinIO phía sau. Khi cần đổi provider, chỉ đổi adapter.

Quy tắc:

– Không lưu file binary trong database
– Lưu metadata trong Postgres
– Dùng signed URL cho file private
– Quét virus nếu khách upload file nhạy cảm
– Tách bucket theo environment


Observability: không đo, không tăng trưởng

SaaS chết không chỉ vì bug. SaaS chết vì không biết bug nằm đâu.

Tối thiểu cần:

– Structured logs
– Request ID xuyên suốt API và worker
– Error tracking bằng Sentry
– Metrics: latency, error rate, queue depth, DB connection
– Tracing cho flow phức tạp
– Audit log cho hành động nhạy cảm

Log nên có context:

{
  "requestId": "req_123",
  "tenantId": "tenant_456",
  "userId": "user_789",
  "action": "project.create"
}

Khi khách báo lỗi, đội support cần tìm được sự kiện trong vài phút, không phải vài giờ.


Deployment: bắt đầu đơn giản, chuẩn bị đường lớn

Không cần Kubernetes từ ngày đầu. Nhiều SaaS chạy tốt với:

– Docker image
– Managed Postgres
– Managed Redis
– Object storage
– One API service
– One worker service
– CI/CD tự động

Khi traffic tăng, scale theo lớp:

1. Tăng instance API
2. Tăng worker riêng theo queue
3. Tối ưu index và query
4. Thêm read replica
5. Tách service nặng
6. Dùng cache có chiến lược
7. Multi-region nếu cần

Quan trọng: backend phải stateless ở API layer. Session lưu trong cookie/JWT hoặc Redis, file lưu object storage, job lưu queue. Như vậy horizontal scale dễ hơn.


Billing và entitlement: đừng để thành if-else khắp code

SaaS nào cũng sẽ có plan, quota, trial, add-on, overage. Nếu rải logic kiểu:

if (user.plan === "pro") ...

… code sẽ nát nhanh.

Nên có service riêng:

EntitlementService.canCreateProject(tenantId)
EntitlementService.canInviteMember(tenantId)
EntitlementService.getLimit(tenantId, "projects")

Billing provider như Stripe chỉ là nguồn thanh toán. Product entitlement nên nằm trong hệ thống riêng, đồng bộ từ Stripe webhook.

Cần xử lý:

– Webhook retry
– Payment failed
– Subscription cancelled
– Trial expired
– Plan changed
– Invoice paid
– Grace period

Billing sai ảnh hưởng doanh thu trực tiếp.


Kết luận: không dùng Supabase để có quyền chọn

Supabase rất tốt cho nhiều dự án. Nhưng với SaaS cần tăng trưởng dài hạn, backend tự chủ cho nhiều quyền hơn: quyền tối ưu, quyền thay provider, quyền thiết kế domain sâu, quyền đáp ứng enterprise, quyền debug rõ.

Kiến trúc khuyến nghị:

– Postgres làm lõi dữ liệu
– API rõ contract
– Auth dùng provider chuyên biệt hoặc self-hosted chuẩn
– Queue cho việc nền
– S3-compatible storage qua abstraction
– Observability từ sớm
– Multi-tenancy thiết kế ngay ngày đầu
– Billing/entitlement tách riêng
– Deployment đơn giản nhưng stateless

Không cần build phức tạp ngay. Cần build đúng điểm nối. SaaS tăng trưởng không thắng nhờ backend “ngầu”. Thắng nhờ backend dễ hiểu, dễ sửa, dễ mở rộng, ít khóa chặt.

#backend #khong #linh #saas #supabase
Chia sẻ:
← Trước
Khi nào nên rời Supabase? 7 dấu hiệu không thể bỏ qua

Bài viết tương tự

Bình luận

Chưa có bình luận. Hãy là người đầu tiên!