Skip to main content
In this tutorial, you’ll build a complete todo application with user authentication and real-time database updates using Supabase.

What You’ll Build

A todo app with the following features:
  • User authentication (sign up/login)
  • Create, read, update, and delete todos
  • Mark todos as complete
  • Row Level Security (RLS) to protect user data
  • Real-time updates

Prerequisites

Before you begin, make sure you have:
  • A Supabase account (sign up here)
  • Node.js 16+ installed
  • Basic knowledge of React and JavaScript
1

Create a Supabase Project

  1. Go to supabase.com/dashboard
  2. Click New Project
  3. Fill in your project details:
    • Name: Todo App
    • Database Password: Choose a strong password
    • Region: Select the closest region to your users
  4. Click Create new project
Wait for your database to finish setting up (this takes about 2 minutes).
2

Set Up the Database

In the SQL Editor, run the “Todo List” quickstart:
  1. Navigate to SQL Editor in the sidebar
  2. Scroll down and select TODO LIST: Build a basic todo list with Row Level Security
  3. Click Run to execute the SQL
This creates a todos table with the following schema:
3

Get Your API Keys

  1. Go to Project Settings (the cog icon)
  2. Click on API
  3. Find your URL and anon public key
  4. Save these for the next step
The anon key is safe to use in a browser. It allows “anonymous access” until the user logs in. Never expose your service_role key in client-side code.
4

Create a Next.js App

Create a new Next.js application:
Install Supabase dependencies:
5

Configure Environment Variables

Create a .env.local file in your project root:
Replace your-project-url and your-anon-key with the values from Step 3.
6

Initialize Supabase Client

Create lib/initSupabase.ts:
7

Create the Todo Component

Create components/TodoList.tsx:
8

Create the Main Page

Update pages/index.tsx:
9

Run Your App

Start the development server:
Open http://localhost:3000 in your browser.

Understanding Row Level Security

Row Level Security (RLS) ensures users can only access their own todos. The policies we created automatically filter queries based on the authenticated user’s ID. When a user is logged in:
  • auth.uid() returns their user ID
  • Policies check if auth.uid() = user_id
  • Only matching rows are returned

Next Steps

Add Real-time Updates

Subscribe to database changes for instant updates

User Management

Build user profiles and avatar uploads

Deploy to Vercel

Deploy your app to production

Example Code

Explore more database examples

Troubleshooting

Check that:
  • You’re logged in
  • RLS policies are enabled
  • The user_id matches auth.uid()
Verify:
  • Environment variables are set correctly
  • Email confirmation is disabled in Auth settings (for testing)
  • Check the browser console for detailed errors
Make sure your Supabase URL is correct and matches the project URL exactly.