A modern todo application demonstrating Supabase integration with React, TypeScript, and TanStack Query. This project showcases best practices for building a full-stack application with authentication, real-time database operations, and type-safe development.
- Authentication: Email/password authentication with Supabase Auth
- Todo Management: Create, read, update, and delete todos with real-time updates
- Type Safety: Auto-generated TypeScript types from your Supabase schema
- State Management: TanStack Query for efficient server state management
- Protected Routes: Route protection with authentication guards
- Modern UI: Clean, minimalist interface built with TailwindCSS
- Frontend: React 19 + TypeScript + Vite
- Backend: Supabase (PostgreSQL + Auth)
- Styling: TailwindCSS v3
- Data Fetching: TanStack Query v5
- Routing: React Router v7
- Type Generation: Supabase CLI
- Node.js 18+ and npm
- A Supabase account and project (sign up free)
git clone <your-repo-url>
cd supabase-vite-demo
npm install- Create a new project at supabase.com
- In your Supabase dashboard, go to SQL Editor and run:
-- Create todos table
create table todos (
id uuid default gen_random_uuid() primary key,
user_id uuid references auth.users not null,
title text not null,
description text,
completed boolean default false,
image_url text,
created_at timestamp with time zone default timezone('utc'::text, now()) not null,
updated_at timestamp with time zone default timezone('utc'::text, now())
);
-- Enable Row Level Security
alter table todos enable row level security;
-- Create policies
create policy "Users can view their own todos"
on todos for select
using (auth.uid() = user_id);
create policy "Users can create their own todos"
on todos for insert
with check (auth.uid() = user_id);
create policy "Users can update their own todos"
on todos for update
using (auth.uid() = user_id);
create policy "Users can delete their own todos"
on todos for delete
using (auth.uid() = user_id);Create a .env file in the project root:
VITE_SUPABASE_URL=your-project-url
VITE_SUPABASE_PUBLISHABLE_KEY=your-anon-keyFind these values in your Supabase dashboard under Settings > API.
Generate type-safe types from your database schema:
npm run types:generateSee TYPE_GENERATION_GUIDE.md for detailed instructions.
npm run devVisit http://localhost:5173 to see your app!
src/
βββ components/ # Reusable React components
β βββ AuthForm.tsx
β βββ ErrorBoundary.tsx
β βββ ProtectedRoute.tsx
β βββ TodoForm.tsx
βββ contexts/ # React context providers
β βββ auth-context.ts
β βββ AuthContext.tsx
βββ hooks/ # Custom React hooks
β βββ useAuth.ts # Authentication mutations
β βββ useTodos.ts # Todo CRUD operations
βββ lib/ # Configuration and utilities
β βββ supabase.ts # Supabase client setup
βββ pages/ # Page components
β βββ LoginPage.tsx
β βββ TodosPage.tsx
βββ types/ # TypeScript type definitions
β βββ supabase.ts # Auto-generated from DB schema
βββ App.tsx # Main app component with routing
βββ main.tsx # Application entry point
This app uses TanStack Query for all server state management:
- Automatic caching and background refetching
- Optimistic updates for better UX
- Query invalidation on mutations
- Loading and error states
All database operations are fully typed using auto-generated types from your Supabase schema:
import type { Todo, TodoInsert, TodoUpdate } from "./lib/supabase";
// TypeScript knows the exact shape of your data
const newTodo: TodoInsert = {
title: "Learn Supabase",
completed: false
};- Protected routes redirect unauthenticated users to login
- Auth state is managed with React Context
- Automatic session persistence with Supabase
npm run dev- Start development servernpm run build- Build for productionnpm run preview- Preview production buildnpm run lint- Run ESLintnpm run types:generate- Generate TypeScript types from Supabase schema
MIT