The Complete Supabase Guide | Firebase Alternative, PostgreSQL, Auth, Storage, Realtime, Edge Functions

The Complete Supabase Guide | Firebase Alternative, PostgreSQL, Auth, Storage, Realtime, Edge Functions

What this post covers

This is a complete guide to building full-stack applications with Supabase. It covers PostgreSQL, Auth, Storage, Realtime, and Edge Functions as practical examples of an open-source Firebase alternative.

From the field: After migrating from Firebase to Supabase, we gained more database flexibility and cut costs by about 60%.

Introduction: “Firebase is expensive”

Real-world scenarios

Scenario 1: I need complex queries

Firestore is limited. Supabase uses PostgreSQL. Scenario 2: Costs are too high

Firebase can be costly. Supabase is open source and more affordable. Scenario 3: I’m worried about vendor lock-in

Firebase ties you to its ecosystem. Supabase uses standard PostgreSQL.


1. What is Supabase?

Core characteristics

Supabase is an open-source Firebase alternative. Key features:

  • PostgreSQL: a powerful relational database
  • Auth: email, OAuth, Magic Link
  • Storage: file uploads
  • Realtime: live subscriptions
  • Edge Functions: Deno-based serverless
  • Row Level Security: access control

2. Project setup

Install

npm install @supabase/supabase-js

Initialize

// lib/supabase.ts
import { createClient } from '@supabase/supabase-js';
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!;
const supabaseKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!;
export const supabase = createClient(supabaseUrl, supabaseKey);

3. Database (PostgreSQL)

Creating tables

Below is a detailed implementation using SQL. Read through the code while understanding the role of each part.

-- Run in SQL Editor
CREATE TABLE users (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  email TEXT UNIQUE NOT NULL,
  name TEXT,
  created_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE posts (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  title TEXT NOT NULL,
  content TEXT,
  author_id UUID REFERENCES users(id),
  published BOOLEAN DEFAULT FALSE,
  created_at TIMESTAMP DEFAULT NOW()
);

CRUD

Below is a detailed implementation using TypeScript. It uses async flows for efficiency and error handling for reliability. Read through the code while understanding the role of each part.

// Create
const { data, error } = await supabase
  .from('users')
  .insert({ email: 'john@example.com', name: 'John' })
  .select()
  .single();
// Read
const { data: users } = await supabase
  .from('users')
  .select('*')
  .order('created_at', { ascending: false });
// Read with Join
const { data: posts } = await supabase
  .from('posts')
  .select(`
    *,
    author:users(name, email)
  `)
  .eq('published', true);
// Update
const { data } = await supabase
  .from('users')
  .update({ name: 'John Updated' })
  .eq('id', userId)
  .select();
// Delete
const { error } = await supabase
  .from('users')
  .delete()
  .eq('id', userId);

4. Authentication (Auth)

Email sign-up

Below is a simple TypeScript example. It uses async flows for efficiency and error handling for reliability. Run the code yourself to see how it behaves.

const { data, error } = await supabase.auth.signUp({
  email: 'john@example.com',
  password: 'password123',
});

Sign in

Below is a simple TypeScript example. It uses async flows for efficiency and error handling for reliability. Run the code yourself to see how it behaves.

const { data, error } = await supabase.auth.signInWithPassword({
  email: 'john@example.com',
  password: 'password123',
});

OAuth

const { data, error } = await supabase.auth.signInWithOAuth({
  provider: 'google',
});

Session management

The code below is a TypeScript example. It uses async flows for efficiency. Read through the code while understanding the role of each part.

// Current user
const { data: { user } } = await supabase.auth.getUser();
// Sign out
await supabase.auth.signOut();
// Listen for session changes
supabase.auth.onAuthStateChange((event, session) => {
  console.log('Auth event:', event, session);
});

5. Storage

File upload

The code below is a TypeScript example. It uses async flows for efficiency and error handling for reliability. Read through the code while understanding the role of each part.

const file = event.target.files[0];
const { data, error } = await supabase.storage
  .from('avatars')
  .upload(`public/${userId}/${file.name}`, file);
// Public URL
const { data: { publicUrl } } = supabase.storage
  .from('avatars')
  .getPublicUrl(`public/${userId}/${file.name}`);

File download

const { data, error } = await supabase.storage
  .from('avatars')
  .download(`public/${userId}/avatar.png`);

6. Realtime

Subscriptions

Below is a detailed TypeScript implementation. Read through the code while understanding the role of each part.

const channel = supabase
  .channel('posts')
  .on(
    'postgres_changes',
    {
      event: '*',
      schema: 'public',
      table: 'posts',
    },
    (payload) => {
      console.log('Change:', payload);
    }
  )
  .subscribe();
// Unsubscribe
channel.unsubscribe();

React example

Below is a detailed TypeScript implementation. It imports the modules you need, uses async flows for efficiency, and maps over data in the render tree. Read through the code while understanding the role of each part.

import { useEffect, useState } from 'react';
import { supabase } from './lib/supabase';
export default function Posts() {
  const [posts, setPosts] = useState([]);
  useEffect(() => {
    // Initial data
    fetchPosts();
    // Realtime subscription
    const channel = supabase
      .channel('posts')
      .on(
        'postgres_changes',
        { event: '*', schema: 'public', table: 'posts' },
        () => {
          fetchPosts();
        }
      )
      .subscribe();
    return () => {
      channel.unsubscribe();
    };
  }, []);
  async function fetchPosts() {
    const { data } = await supabase.from('posts').select('*');
    setPosts(data || []);
  }
  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  );
}

7. Row Level Security (RLS)

Policy setup

Below is a detailed implementation using SQL. Read through the code while understanding the role of each part.

-- Enable RLS
ALTER TABLE posts ENABLE ROW LEVEL SECURITY;
-- Read: everyone can view
CREATE POLICY "Public posts are viewable by everyone"
ON posts FOR SELECT
USING (published = true);
-- Write: only the author
CREATE POLICY "Users can create their own posts"
ON posts FOR INSERT
WITH CHECK (auth.uid() = author_id);
CREATE POLICY "Users can update their own posts"
ON posts FOR UPDATE
USING (auth.uid() = author_id);

8. Edge Functions

Create a function

npx supabase functions new hello

The code below is a TypeScript example. It imports the modules you need and uses async flows for efficiency. Read through the code while understanding the role of each part.

// supabase/functions/hello/index.ts
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts';
serve(async (req) => {
  const { name } = await req.json();
  return new Response(
    JSON.stringify({ message: `Hello ${name}!` }),
    { headers: { 'Content-Type': 'application/json' } }
  );
});

Deploy

npx supabase functions deploy hello

Invoke

const { data, error } = await supabase.functions.invoke('hello', {
  body: { name: 'John' },
});

Connecting to job search and interviews

If you can explain Auth, RLS, and Edge Functions as a full-stack portfolio story, it carries a lot of weight in interviews. Pair Tech Interview Preparation Guide with the achievements and tech-stack sections in Developer Job Hunting Practical Tips when you describe your projects.


Summary and checklist

Key takeaways

  • Supabase: open-source Firebase alternative
  • PostgreSQL: powerful relational database
  • Auth: multiple authentication options
  • Storage: file management
  • Realtime: live subscriptions
  • RLS: security policies

Implementation checklist

  • Create a project
  • Design tables
  • Implement CRUD
  • Configure Auth
  • Implement Storage
  • Add Realtime subscriptions
  • Configure RLS policies


Keywords in this post

Supabase, Firebase, PostgreSQL, Auth, Storage, Realtime, Backend

Frequently asked questions (FAQ)

Q. How does it compare to Firebase?

A. Supabase is built on PostgreSQL, so you can run complex queries and often keep costs lower. Firebase is simpler to start with but more limited for relational data and advanced queries.

Q. Is there a free tier?

A. Yes. The free plan includes up to 500MB database, 1GB Storage, and 50K MAU.

Q. Can I self-host?

A. Yes. It is open source and you can self-host with Docker Compose.

Q. Is it production-ready?

A. Yes. Many startups and enterprises use it reliably in production.