If I Were Starting a New SaaS Today, I'd Do This

8 min read

Most SaaS projects fail because founders spend weeks building scaffolding instead of features. Here's how to skip the boilerplate and ship fast.

I've built half a dozen SaaS products. Some succeeded. Most failed. But the failures taught me something critical: ideas don't die from competition—they die from delayed launches.

You lose weeks setting up databases, authentication, APIs, file uploads, and admin panels before writing a single line of actual product code. By the time you're ready to ship, momentum is gone.

If I were starting today, I'd skip all that. I'd use Supabase—and I'd ship an MVP in days, not months.

The Problem with "Building from Scratch"

Building foundations feels productive. You're writing code, making decisions, setting up infrastructure. But you're not building anything users can touch.

Auth alone consumes days: password hashing, session management, password resets, email verification. Then you need database migrations, API routes, input validation, error handling. Before you know it, you've burned two weeks on scaffolding.

That's two weeks you could've spent validating whether anyone actually wants what you're building.

Why Supabase Changes Everything

Supabase isn't just a database. It's a complete backend—authentication, storage, real-time updates, edge functions—packaged as a single platform. And unlike Firebase, it's built on PostgreSQL, so you're not locked into proprietary tech.

PostgreSQL Foundation

Every table you create automatically gets REST and GraphQL APIs. No backend needed. Query directly from your frontend with row-level security enforcing permissions at the database layer.

// Fetch user's tasks directly from the frontend
const { data, error } = await supabase
  .from('tasks')
  .select('*')
  .eq('user_id', userId);

You still get full PostgreSQL power: triggers, extensions, stored procedures, joins, indexes. It's not a toy database—it's enterprise-grade Postgres with a developer experience that doesn't suck.

Authentication That Just Works

Built-in support for email/password, magic links, OTPs, OAuth (Google, GitHub, etc.), and custom SSO. User records live in your Postgres schema. Add custom fields. Create relationships. No vendor lock-in.

// Sign up with email/password
const { user, error } = await supabase.auth.signUp({
  email: '[email protected]',
  password: 'secure-password'
});

// Magic link (passwordless)
await supabase.auth.signInWithOtp({
  email: '[email protected]'
});

No JWT libraries. No session stores. No password reset flows. It's handled. You write product code.

Real-Time Updates Without Redis

WebSocket-based subscriptions give you instant updates on table changes. No message brokers. No Kafka. No Redis pub/sub.

// Subscribe to new messages
supabase
  .channel('messages')
  .on('postgres_changes', {
    event: 'INSERT',
    schema: 'public',
    table: 'messages'
  }, (payload) => {
    console.log('New message:', payload.new);
  })
  .subscribe();

Insert a row in your messages table? All connected clients receive it instantly. Build chat, notifications, live dashboards—without standing up infrastructure.

Row-Level Security

Database-level authorization policies replace entire backend authorization layers. One policy line defines who can access what.

-- Users can only see their own tasks
CREATE POLICY "Users see own tasks"
  ON tasks FOR SELECT
  USING (auth.uid() = user_id);

Policies compose. Multi-tenant? Add tenant_id checks. Admin override? Add role conditions. Security moves from scattered backend checks to centralized, auditable rules.

Storage & Edge Functions

Native file upload handling with access rules compatible with row-level security. TypeScript-based edge functions deploy in seconds for webhooks, scheduled jobs, or integrations.

// Upload file with automatic access control
const { data, error } = await supabase.storage
  .from('avatars')
  .upload(`${userId}/avatar.png`, file);

// Edge function for webhook processing
import { serve } from 'https://deno.land/std/http/server.ts'

serve(async (req) => {
  const payload = await req.json();
  // Process webhook
  return new Response('OK', { status: 200 });
});

The Developer Experience You Deserve

The CLI, dashboard, SQL editor, and APIs feel cohesive. You're not juggling five different tools with five different authentication methods. Everything integrates.

Need to see your database? Open the dashboard. Want to test a query? Use the SQL editor. Ready to deploy a function? supabase functions deploy. It just works.

Open Source & Portability

Unlike Firebase, Supabase runs self-hosted via Docker Compose. Start on their hosted platform. Move to self-hosted if you outgrow it. Same codebase. Same developer experience.

You're not locked in. Your data is Postgres. Your auth is Postgres. Your files are S3-compatible storage. If Supabase disappears tomorrow, you can migrate. Try doing that with Firebase.

Ship Fast, Own Your Stack, Avoid Unnecessary Complexity

This is the indie developer playbook: start small, ship fast, scale naturally. Supabase embodies that philosophy.

You're not choosing between a custom backend and a proprietary platform. Supabase sits in the middle—powerful enough for serious applications, simple enough to start with one table and an auth flow.

If I were starting a SaaS today, I'd skip the scaffolding. I'd use Supabase. And I'd ship in days—not weeks.

Because the best way to validate an idea isn't to build perfect infrastructure. It's to put something in front of users and learn whether they care.

Supabase gets you there faster. And when you're running solo, speed is everything.