@vivekcsein-logo
  • Home
  • About
  • Development

    • Web Development
    • Performance & Optimization
    • Backend & APIs
    • Authentication & Security

    Specialized

    • SEO & Ad Monetization
    • AR Experiences
    • Animation
    • Figma to Code
  • Articles
  • Projects
  • Marketplace
  • Contact
@vivekcsein-logo

A portfolio full stack developer with a passion for building scalable and high-performance web applications.

Explore

  • Home
  • About

Services

  • Web Development
  • Backend & APIs
  • Performance Optimization
  • Security & Authentication

Connect

  • Contact
  • Privacy
  • Terms
  • Home
  • About
  • Web Development
  • Backend & APIs
  • Performance Optimization
  • Security & Authentication
  • Contact
  • Privacy
  • Terms

© @vivekcsein. All rights reserved.

  • Home
  • All Articles47
  • Featured
  • Recently Added
  • Most Read
  • Bookmarks
Topics
  • Interview3
  • 3d4
  • Ai Prompts2
  • Business3
  • Deployment1
  • Dev2
  • Frontend5
  • Getting Started2
  • Security2
  • Seo2
  • Workflow10
  • Backend1
  • Deployment1
  • Security1
  • Javascript1
  • Client Advisory5
    • Client Advisory & Technical Playbook: Next.js AI Integration & LLM Architecture
    • Client Advisory & Technical Playbook: BaaS (Supabase/Firebase) vs. Custom Node.js
    • How Your Website Works: Hosting, Live Data & User Login
    • Client Advisory & Technical Playbook: Next.js App Router, RSC & Performance Engineering
    • High-Performance Technical SEO & Optimization Suite
  • Engineering2
Collections
  • Docs
  • Tutorials
  • Resources
  • Articles
“A better developer every single day.”
— Vivek
  1. Articles
  2. Client Advisory
  3. Client Advisory & Technical Playbook: BaaS (Supabase/Firebase) vs. Custom Node.js
Client Advisory

Client Advisory & Technical Playbook: BaaS (Supabase/Firebase) vs. Custom Node.js

Decision framework for choosing Supabase, Firebase or a custom Node.js/Express backend, with common bottlenecks, best practices, an intake checklist and SOW templates.

Updated Sep 12, 202614 min read
On this page

On this page

  • 1. Executive Summary & Client Decision Framework
  • Decision Matrix
  • 2. Top 5 Client Bottlenecks & Engineering Solutions
  • 2.1 Architectural Pitfalls (Relational SQL vs. NoSQL Document Stores)
  • 2.2 Security Vulnerabilities (Row-Level Security / Firestore Rules Misconfiguration)
  • 2.3 Spiking Operational Costs & Unpredictable Billing
  • 2.4 Environment Sync & Lack of Migration Workflows
  • 2.5 Business Logic Leakage into the Frontend
  • 3. BaaS Architecture Best Practices & Blueprint
  • 3.1 Frontend vs. Edge Function Boundaries
  • 3.2 Environment Separation Strategy
  • 3.3 Security Protocol
  • 4. Technical Audit & Discovery Checklist for New Clients
  • 5. Scope of Work (SOW) Templates for Freelance/Agency Projects
  • SOW Option A: BaaS Setup & MVP Delivery (0 to 1)
  • SOW Option B: Firebase → Supabase / Custom Node Migration & Technical Debt Cleanup

Internal Use: Sales discovery asset + technical operations manual. Use Section 1 and Section 4 in client-facing calls. Use Sections 2, 3, and 5 as internal engineering/PM reference and contract scaffolding.


1. Executive Summary & Client Decision Framework#

Most clients arrive with a platform decision already half-made — usually by a YouTube tutorial, not by their actual requirements. Our job in discovery is to re-anchor the decision to their product's real constraints: team size, compliance surface, data relationships, and 18-month cost trajectory, not just week-one velocity.

The three architectures below are not tiers of "better" — they are different trade-off profiles. Selling the wrong one to save a sales call costs us the client at month six when they hit the wall.

Decision Matrix#

CriteriaSupabaseFirebaseCustom Node.js/Express
Best Use CasesRelational data models, apps needing SQL joins/reporting, teams that want Postgres portability, B2B SaaS with complex permissionsReal-time consumer apps, mobile-first products, MVPs needing offline sync, chat/presence featuresComplex/proprietary business logic, multi-tenant enterprise systems, apps requiring custom infra (queues, ML pipelines), regulated industries
Time to MarketFast (1-3 weeks to MVP) — Postgres + auto-generated REST/GraphQL APIFastest (days) — SDK-driven, minimal backend code requiredSlowest (4-8+ weeks) — every endpoint, auth flow, and validation layer is hand-built
Long-Term ScalabilityGood — vertical Postgres scaling, read replicas, connection pooling (PgBouncer); relational integrity holds under complexityModerate — Firestore scales horizontally well for simple access patterns, but complex queries and relational joins require denormalization workarounds that compound tech debtExcellent — full control over horizontal scaling, caching layers, microservice extraction, and database choice
Pricing PredictabilityModerate — compute/storage pricing is transparent, but egress and Edge Function invocations can spike with usagePoor — pay-per-read/write/delete model means a single bad query pattern (N+1 reads in a loop) can 10x a bill overnightHigh — fixed infra cost (VPS/container/DB instance) regardless of query patterns; scales in discrete, plannable steps
Vendor Lock-in RiskLow — standard Postgres underneath; pg_dump gets you a portable database; self-hostableHigh — Firestore's proprietary query engine, security rules DSL, and SDKs have no direct migration path; data export ≠ working replicaNone — client owns 100% of the codebase and infrastructure choices

Client-facing framing: "Supabase and Firebase get you to market fast because we're renting someone else's infrastructure decisions. A custom Node.js backend costs more upfront because you're buying control. The right call depends on whether your product's value is in shipping fast or in logic that competitors can't easily replicate."


2. Top 5 Client Bottlenecks & Engineering Solutions#

2.1 Architectural Pitfalls (Relational SQL vs. NoSQL Document Stores)#

(a) Why clients get stuck Founders pick Firestore because "NoSQL is what modern apps use," then model their data exactly like relational tables — collections mirroring SQL tables, with manual for loops standing in for JOIN. This produces N+1 read patterns that are invisible in dev (10 test records) and catastrophic in production (10,000 records, 10,000 billed reads for one page load).

(b) Technical risks

  • Denormalized data drifts out of sync (e.g., a username copied into 500 documents doesn't update when the user renames)
  • No transactional integrity across collections without explicit (and easy-to-forget) runTransaction() blocks
  • Query limitations: Firestore cannot do OR across fields, can't do full-text search, can't do arbitrary joins — clients discover this mid-build, not at planning

(c) How our engineering support resolves it

  • We run a data-shape audit before any line of code: map every entity relationship (1:1, 1:many, many:many) and flag which ones need referential integrity
  • For Supabase, we design Postgres schemas with proper foreign keys and views — the client gets JOIN for free
  • For Firestore, we build explicit denormalization strategies with Cloud Functions that keep duplicated fields in sync on write, documented so future devs don't "fix" it into a bug
  • Deliverable: an ERD (entity relationship diagram) signed off before implementation begins

2.2 Security Vulnerabilities (Row-Level Security / Firestore Rules Misconfiguration)#

(a) Why clients get stuck BaaS platforms ship with permissive or default-deny rules that clients rarely audit. The most common failure we see in the wild: allow read, write: if true; left in from a Firebase tutorial, still live in production, exposing every user's data to anyone with the API key (which is not a secret in client-side apps).

(b) Technical risks

  • Full database read/write exposure to unauthenticated users
  • Privilege escalation: a user editing their own role field from "user" to "admin" because no rule blocks it
  • RLS policies in Supabase that check auth.uid() but forget to scope by tenant/organization, leaking cross-tenant data in multi-tenant apps

(c) How our engineering support resolves it

  • We treat security rules as code, not config — every RLS policy and Firestore rule is reviewed in a PR, tested with the platform's local emulator, and mapped to a written access-control spec
  • Standard baseline we deploy for every Supabase project:
sql
-- Enable RLS on every table by default — no exceptions
ALTER TABLE public.orders ENABLE ROW LEVEL SECURITY;

-- Scoped, explicit policy — not "if true"
CREATE POLICY "Users can only view their own orders"
ON public.orders FOR SELECT
USING (auth.uid() = user_id);

CREATE POLICY "Users can only modify their own orders"
ON public.orders FOR UPDATE
USING (auth.uid() = user_id)
WITH CHECK (auth.uid() = user_id);
  • Standard baseline for Firestore:
javascript
// firestore.rules
rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /orders/{orderId} {
      allow read, update, delete: if request.auth != null
                                    && request.auth.uid == resource.data.userId;
      allow create: if request.auth != null
                     && request.auth.uid == request.resource.data.userId;
    }
  }
}
  • We run automated rule-testing (@firebase/rules-unit-testing or Supabase's pgTAP) as part of CI, so a rule regression fails the build, not the client's user base

2.3 Spiking Operational Costs & Unpredictable Billing#

(a) Why clients get stuck BaaS billing is usage-metered (reads, writes, function invocations, bandwidth). A client's app going viral, a bad recursive query, or an unthrottled real-time listener can turn a $25/month bill into a $4,000 bill in 72 hours — and the client finds out when the card gets declined or the invoice arrives.

(b) Technical risks

  • Real-time listeners (onSnapshot) left attached on unmounted components, silently accumulating read costs
  • Missing pagination — a client "get all records" query that scales linearly with data growth and bills per document read
  • No budget alerts configured, so cost overruns are discovered retroactively

(c) How our engineering support resolves it

  • We configure hard budget alerts at 50%/80%/100% of projected spend on day one (Firebase Budget Alerts + Cloud Functions to auto-disable non-critical services at threshold; Supabase compute/egress alerts)
  • We audit every real-time subscription for proper cleanup (useEffect unsubscribe, unsubscribe() calls) as a mandatory PR checklist item
  • We enforce pagination and query limits (.limit(), cursor-based pagination) as a non-negotiable coding standard, not an optimization for "later"
  • We provide a monthly cost-projection model in the SOW so clients can forecast spend against user growth, not get surprised by it

2.4 Environment Sync & Lack of Migration Workflows#

(a) Why clients get stuck Solo founders and small teams frequently develop directly against production because setting up local/staging environments feels like overhead. This means every schema change, every security rule edit, is a live experiment on real user data with no rollback plan.

(b) Technical risks

  • Schema drift: local dev database no longer matches staging or production, causing "works on my machine" failures
  • No audit trail of what changed, when, or why — impossible to debug a regression introduced three deploys ago
  • Direct production edits bypass code review entirely

(c) How our engineering support resolves it

  • We stand up a proper three-environment pipeline (Local → Staging → Production) using platform-native CLI tooling, detailed fully in Section 3
  • Every schema change becomes a version-controlled migration file, reviewed in a PR, applied identically across environments — no manual dashboard edits in production, ever
  • We set this up in week one of every engagement, even MVP-stage ones — it's cheaper to build right than to retrofit after the client has live users

2.5 Business Logic Leakage into the Frontend#

(a) Why clients get stuck BaaS platforms make it trivially easy to call the database directly from client code, so pricing calculations, discount logic, permission checks, and payment amounts end up computed in JavaScript running in the user's browser — fully visible and editable via devtools.

(b) Technical risks

  • A user opens devtools, changes cartTotal before it's sent to the payment processor, and pays $1 for a $500 order
  • Business rules (loyalty tiers, referral bonuses, inventory checks) become inconsistent across web/mobile clients because each reimplements the logic slightly differently
  • Any competitor can read your pricing/discount algorithm directly from the network tab

(c) How our engineering support resolves it

  • We enforce a hard rule: any operation with financial, permission, or business-critical impact must execute server-side — via Supabase Edge Functions, Firebase Cloud Functions, or a thin custom Node.js service sitting in front of the BaaS
  • Client code is only ever allowed to request an action and display a result — never to compute the trusted value itself
  • Example boundary for a checkout flow:
javascript
// ❌ WRONG — client computes and trusts its own total
const total = cart.items.reduce((sum, i) => sum + i.price * i.qty, 0);
await processPayment(total);

// ✅ CORRECT — server recomputes and is the source of truth
// supabase/functions/checkout/index.ts (Edge Function)
const { data: items } = await supabase
  .from("cart_items")
  .select("product_id, quantity, products(price)")
  .eq("cart_id", cartId);

const trustedTotal = items.reduce(
  (sum, i) => sum + i.products.price * i.quantity,
  0,
);
// payment processor only ever sees trustedTotal

3. BaaS Architecture Best Practices & Blueprint#

3.1 Frontend vs. Edge Function Boundaries#

Not every read needs a server hop, and not every write should skip one. Our standard boundary rule:

Operation TypeDirect DB Call OK?Why
Reading public/non-sensitive data (blog posts, product listings)✅ Yes, with RLS/rules enforcedRLS/rules already scope access; no business logic involved
Reading the current user's own scoped data✅ Yes, with RLS/rules enforcedOwnership check is declarative and enforced at the DB layer
Writes that are pure user input (profile bio, comment text)✅ Yes, with validation constraints + RLSLow risk, DB constraints (CHECK, NOT NULL) catch malformed input
Anything touching price, payment, or inventory❌ No — Edge Function requiredMust be server-computed and server-verified, never client-trusted
Anything triggering third-party API calls (email, SMS, payment gateways)❌ No — Edge Function requiredSecrets (API keys) cannot live in client bundles
Multi-step operations needing atomicity❌ No — Edge Function/RPC requiredClient-side sequential calls can partially fail, leaving inconsistent state
Anything requiring elevated/service-role privileges❌ Never — Edge Function onlyService role keys must never ship to a client

3.2 Environment Separation Strategy#

We run every project on a Local → Staging → Production pipeline, mirrored by platform-specific CLI tooling.

Supabase:

bash
# Initialize project-local config
supabase init

# Start local Postgres + Studio + Auth emulation
supabase start

# Create a new versioned migration from schema changes
supabase db diff -f add_orders_table

# Apply migrations locally
supabase db reset

# Link to staging project and push
supabase link --project-ref <staging-ref>
supabase db push

# Promote to production only after staging sign-off
supabase link --project-ref <production-ref>
supabase db push

Firebase:

bash
# Initialize project with emulator config
firebase init emulators

# Run local Auth/Firestore/Functions emulator suite
firebase emulators:start

# Deploy rules and functions to staging project alias
firebase use staging
firebase deploy --only firestore:rules,functions

# Promote to production after QA sign-off on staging
firebase use production
firebase deploy --only firestore:rules,functions

Non-negotiable rule: no schema change, rule change, or function deploy ever touches production without first passing through staging with an identical migration script. Dashboard-only edits in production are treated as an incident, not a shortcut.

3.3 Security Protocol#

  • RLS/Rules: default-deny on every table/collection; every policy scoped to auth.uid() (Supabase) or request.auth.uid (Firestore) and, for multi-tenant apps, an explicit organization/tenant ID check
  • JWT Auth Flows: short-lived access tokens (1 hour default) with refresh token rotation; sensitive role/permission claims embedded in custom JWT claims (Supabase auth.jwt() claims, Firebase custom claims via Admin SDK) — never trust a role sent in a request body
  • Secret Management: service-role keys and third-party API secrets live only in Edge Function/Cloud Function environment variables, never in .env files committed to git, never in client bundles; we use platform secret managers (supabase secrets set, firebase functions:config:set / Secret Manager) exclusively

4. Technical Audit & Discovery Checklist for New Clients#

Run this before quoting any estimate on an existing BaaS project. Each answer directly informs scope and risk pricing.

  1. What is your current database schema, and can you export it? (Reveals relational complexity and whether documentation exists at all.)
  2. What are your current security rules/RLS policies, verbatim? (Most revealing single question — surfaces if true and missing tenant scoping immediately.)
  3. What is your last 3 months of platform billing history? (Identifies cost spikes and query anti-patterns before we touch code.)
  4. Do you have separate local, staging, and production environments today? (If no — this is Phase 1 of any engagement, non-negotiable.)
  5. Where does your business logic currently live — client code, Cloud/Edge Functions, or a separate backend? (Surfaces logic-leakage risk per Section 2.5.)
  6. How is authentication currently handled, and are there custom roles/claims? (Determines auth migration complexity.)
  7. What third-party integrations exist (payments, email, analytics), and where are their API keys stored? (Secret-management audit.)
  8. What is your current user/data volume, and what is your 12-month growth projection? (Determines whether current architecture will hold or needs redesign.)
  9. Do you have any compliance requirements (GDPR, HIPAA, SOC 2, data residency)? (BaaS platforms have specific, sometimes disqualifying, compliance postures.)
  10. What does your current test coverage and CI/CD pipeline look like, if any? (Determines how much regression risk exists in any migration or refactor.)

Internal use: Score each answer 0-2 (0 = absent/high risk, 1 = partial, 2 = solid). A total score under 10/20 flags the project as technical debt cleanup, not feature work — price and scope accordingly (see SOW Option B).


5. Scope of Work (SOW) Templates for Freelance/Agency Projects#

SOW Option A: BaaS Setup & MVP Delivery (0 to 1)#

Objective: Take a client from idea/wireframe to a production-deployed MVP on Supabase or Firebase within a fixed timeline.

Phase 1 — Discovery & Architecture (Week 1)

  • Run the 10-point Technical Audit Checklist (Section 4)
  • Deliver ERD and access-control specification, client sign-off required before build starts

Phase 2 — Environment & Security Foundation (Week 1-2)

  • Local/Staging/Production environment setup with CLI-based migration pipeline
  • Default-deny RLS/rules baseline implemented and tested

Phase 3 — Core Feature Build (Week 2-5, scope-dependent)

  • Auth flows (signup/login/session management/role claims)
  • Core CRUD features per client spec, with Edge Functions for any business-critical logic
  • Third-party integrations (payments, email/SMS) via server-side functions only

Phase 4 — QA & Launch (Week 5-6)

  • Security rule test suite execution
  • Cost-projection model delivered against growth assumptions
  • Production deployment + budget alert configuration

Exclusions: Ongoing feature development post-launch, marketing site, native mobile app builds (quoted separately), third-party service subscription costs (client-billed directly).

Payment structure: 40% upfront / 40% at Phase 3 completion / 20% at launch sign-off.


SOW Option B: Firebase → Supabase / Custom Node Migration & Technical Debt Cleanup#

Objective: Migrate an existing BaaS project off a problematic foundation (cost, security, or scalability driven) with zero data loss and minimal downtime.

Phase 1 — Audit & Risk Report (Week 1)

  • Full Technical Audit Checklist scoring (Section 4)
  • Written risk report: security exposures, cost anti-patterns, schema issues — ranked by severity
  • Migration plan with explicit rollback strategy, client sign-off required before touching production

Phase 2 — Schema & Data Migration Design (Week 1-2)

  • Target schema design (Postgres ERD if moving to Supabase/Node; revised Firestore structure if staying on Firebase)
  • Data transformation scripts written and tested against a full production data snapshot in a sandboxed environment

Phase 3 — Parallel-Run Migration (Week 2-5, scope-dependent)

  • New backend built alongside the old one (strangler-fig pattern) — no big-bang cutover
  • Dual-write or scheduled sync strategy to keep both systems consistent during transition
  • Security rules/RLS rebuilt to default-deny baseline from Section 3.3

Phase 4 — Cutover & Validation (Week 5-6)

  • Data integrity validation (row/document counts, checksum spot-checks)
  • Staged traffic cutover with monitoring window before decommissioning legacy system
  • Legacy platform decommissioned only after a client-agreed stability window (typically 2 weeks)

Exclusions: New feature development during migration (frozen scope to reduce risk), legacy platform subscription costs during parallel-run overlap (client-billed), UI/UX redesign.

Payment structure: 30% upfront (audit + plan) / 40% at Phase 3 completion / 30% at successful decommission of legacy system.


This playbook is a living document — update the decision matrix and pricing models quarterly as platform pricing and capabilities shift.

PreviousClient Advisory & Technical Playbook: Next.js AI Integration & LLM ArchitectureNext How Your Website Works: Hosting, Live Data & User Login

Keep reading

  • Client Advisory

    Client Advisory & Technical Playbook: Next.js AI Integration & LLM Architecture

    Client advisory playbook for adding AI to Next.js apps: choosing between direct API calls, the Vercel AI SDK, RAG and agents, with an intake checklist and SOW templates.

    23 min read·Sep 12, 2026
  • Client Advisory

    Client Advisory & Technical Playbook: Next.js App Router, RSC & Performance Engineering

    Client advisory playbook for Next.js performance: choosing CSR, SSR, SSG or ISR per route, fixing common bottlenecks, plus an audit checklist and SOW templates.

    17 min read·Sep 12, 2026
  • Client Advisory

    How Your Website Works: Hosting, Live Data & User Login

    A plain-English explanation of static websites for business owners: how hosting, live data from outside services and user login work, and what the approach cannot do.

    5 min read·Sep 12, 2026

On this page

  • 1. Executive Summary & Client Decision Framework
  • Decision Matrix
  • 2. Top 5 Client Bottlenecks & Engineering Solutions
  • 2.1 Architectural Pitfalls (Relational SQL vs. NoSQL Document Stores)
  • 2.2 Security Vulnerabilities (Row-Level Security / Firestore Rules Misconfiguration)
  • 2.3 Spiking Operational Costs & Unpredictable Billing
  • 2.4 Environment Sync & Lack of Migration Workflows
  • 2.5 Business Logic Leakage into the Frontend
  • 3. BaaS Architecture Best Practices & Blueprint
  • 3.1 Frontend vs. Edge Function Boundaries
  • 3.2 Environment Separation Strategy
  • 3.3 Security Protocol
  • 4. Technical Audit & Discovery Checklist for New Clients
  • 5. Scope of Work (SOW) Templates for Freelance/Agency Projects
  • SOW Option A: BaaS Setup & MVP Delivery (0 to 1)
  • SOW Option B: Firebase → Supabase / Custom Node Migration & Technical Debt Cleanup