π₯ Stop Wasting Time with APIs β Build a Full Backend in Minutes using Supabase & React!
Imagine building a full-stack app with authentication, file uploads, and a powerful SQL database... and writing almost no backend code. Sound too good to be true? Let me show you how Supabase makes it possible.
π TL;DR
If you're tired of setting up backends, managing authentication, or just want to ship your product faster, Supabase is your new best friend. In this post, we'll build a full-stack React app with user authentication, a Postgres database, and real-time updates β all powered by Supabase.
π§ͺ What is Supabase?
Supabase is an open-source alternative to Firebase. It gives you:
- A hosted Postgres database
- Automatic RESTful and realtime APIs
- User authentication
- File storage
- Edge functions (serverless functions)
Unlike Firebase, Supabase is built on PostgreSQL, which means you get full SQL power and relational queries.
π§ Tech Stack for this Project
- React (using Vite for speed)
- Supabase (auth + DB)
Weβll build a simple Notes app with:
- User sign up/login/logout
- Real-time note syncing
- CRUD operations on notes
Letβs go! π οΈ
π¬ Step 1: Create a Supabase Project
- Go to https://app.supabase.com/
- Click
New Project
- Choose a name, password, and region
- Wait for your project to initialize
- Go to the
Settings -> API
tab and copy your anon key & project URL
Weβll use these in our React app.
ποΈ Step 2: Create the Notes Table
In your Supabase dash:
-- SQL Editor
create table notes (
id uuid primary key default gen_random_uuid(),
user_id uuid references auth.users(id),
content text,
inserted_at timestamp with time zone default timezone('utc', now())
);
Now letβs build the React frontend.
βοΈ Step 3: Set Up React App with Supabase
Using Vite for speed:
npm create vite@latest supabase-notes --template react
cd supabase-notes
npm install
npm i @supabase/supabase-js
Create Supabase Client
Create a file: src/supabaseClient.js
import { createClient } from '@supabase/supabase-js';
const supabaseUrl = 'https://your-project.supabase.co';
const supabaseAnonKey = 'your-anon-key';
export const supabase = createClient(supabaseUrl, supabaseAnonKey);
π Step 4: Add Authentication
In App.jsx
:
import { useState, useEffect } from 'react';
import { supabase } from './supabaseClient';
function App() {
const [session, setSession] = useState(null);
useEffect(() => {
supabase.auth.getSession().then(({ data: { session } }) => {
setSession(session);
});
const { data: listener } = supabase.auth.onAuthStateChange((event, session) => {
setSession(session);
});
return () => listener.subscription.unsubscribe();
}, []);
if (!session) return <Auth />;
return <Notes user={session.user} />;
}
function Auth() {
const [email, setEmail] = useState('');
const handleLogin = async () => {
await supabase.auth.signInWithOtp({ email });
alert('Check your email for the login link!');
};
return (
<div>
<h2>Login via Magic Link</h2>
<input value={email} onChange={(e) => setEmail(e.target.value)} />
<button onClick={handleLogin}>Send</button>
</div>
);
}
Supabase magic link auth makes signing in a breeze.
βοΈ Step 5: CRUD Notes in Real-Time
Let's implement our Notes
component:
function Notes({ user }) {
const [notes, setNotes] = useState([]);
const [newNote, setNewNote] = useState('');
useEffect(() => {
fetchNotes();
const realTimeSub = supabase
.channel('public:notes')
.on('postgres_changes', { event: '*', schema: 'public', table: 'notes' }, payload => {
console.log('Realtime update', payload);
fetchNotes();
})
.subscribe();
return () => supabase.removeChannel(realTimeSub);
}, []);
async function fetchNotes() {
const { data, error } = await supabase
.from('notes')
.select('*')
.eq('user_id', user.id)
.order('inserted_at', { ascending: false });
setNotes(data);
}
async function addNote() {
await supabase.from('notes').insert({ content: newNote, user_id: user.id });
setNewNote('');
}
async function deleteNote(id) {
await supabase.from('notes').delete().eq('id', id);
}
return (
<div>
<h2>My Notes</h2>
<input value={newNote} onChange={(e) => setNewNote(e.target.value)} />
<button onClick={addNote}>Add</button>
<ul>
{notes.map(note => (
<li key={note.id}>
{note.content} <button onClick={() => deleteNote(note.id)}>x</button>
</li>
))}
</ul>
</div>
);
}
Boom β You now have real-time, collaborative notes.
π Deploying with Vercel
- Push your code to GitHub
- Go to vercel.com and import your repo
- Set the environment variables:
VITE_SUPABASE_URL
VITE_SUPABASE_ANON_KEY
Then deploy!
π‘ Pro Tips & Gotchas
- Supabase Auth works best with a custom domain to prevent email blackholes
- You can use
Row Level Security
for extra protection on your tables - You can build edge functions directly with Supabase CLI
- Supabase storage lets you add file uploads (profile photos? PDFs?) quickly
π Final Thoughts
Supabase is a total game-changer for developers who want to iterate quickly and still maintain control.
You're using real SQL, you own your data, and you get Firebase-level power β‘οΈ without vendor lock-in.
Who should use Supabase?
- Startup devs who need MVPs fast
- Freelancers working for multiple clients
- Indie hackers looking to ship more
Have you tried Supabase? Tweet me your builds @CodeWizardDev π§ββοΈ
π Resources
Thanks for reading β time to stop writing backends and start building products! π
π If you need this done β we offer fullstack development services.
Top comments (0)