Skip to content
Home/Resources/Build guides/First web app with Cloudflare and Supabase
Build guide

Build and Deploy Your First Web App for Free: React, Supabase and Cloudflare Pages, Step by Step

By Younus FardeenUpdated 31 Oct 20264 min read
Short answer

Create a React app with Vite, add a Supabase project for sign-in and a notes table protected by row-level security, push the code to GitHub and connect the repository to Cloudflare Pages. Every service used here has a free plan, and the whole build takes about three hours.

You will buildA notes app: users sign in with email, create, edit and delete their own notes, and nobody can see anyone else's. Live on a public URL.
TimeAbout 3 hours
Cost₹0 on free plans
LevelBeginner (you know basic HTML and JavaScript)

Tools you need

The 11 steps

01

Install the basics

Install Node.js LTS, Git and VS Code. Create a free GitHub account if you do not have one. Check with node -v and git --version.

02

Create the React app

Run npm create vite@latest my-notes -- --template react, then cd my-notes, npm install and npm run dev. Open the local URL to confirm the starter page loads.

03

Create a Supabase project

Sign in to Supabase, create a new project on the free plan and wait for it to provision. In Project Settings, open the API section and copy the Project URL and the anon (publishable) key.

04

Create the notes table with row-level security

In the SQL editor run:

create table notes (
  id uuid primary key default gen_random_uuid(),
  user_id uuid not null default auth.uid() references auth.users,
  content text not null,
  created_at timestamptz default now()
);
alter table notes enable row level security;
create policy "own notes" on notes
  for all using (auth.uid() = user_id) with check (auth.uid() = user_id);

Row-level security is what stops users reading each other's notes.

05

Connect the app to Supabase

Run npm install @supabase/supabase-js. Create .env.local with VITE_SUPABASE_URL and VITE_SUPABASE_ANON_KEY, and add .env.local to .gitignore. Create src/supabase.js:

import { createClient } from '@supabase/supabase-js'
export const supabase = createClient(
  import.meta.env.VITE_SUPABASE_URL,
  import.meta.env.VITE_SUPABASE_ANON_KEY
)
06

Add sign-in

In Supabase, under Authentication, keep the Email provider enabled. In the app, add a form that calls supabase.auth.signInWithOtp({ email }) for a magic link, and listen with supabase.auth.onAuthStateChange to know when the user is signed in.

07

Build the notes screen

After sign-in, load notes with supabase.from('notes').select('*').order('created_at', { ascending: false }), insert with .insert({ content }) and delete with .delete().eq('id', id). Render a list with a text box and a delete button.

08

Push to GitHub

Run git init, commit, create an empty repository on GitHub and push. Confirm .env.local is not in the repository.

09

Deploy on Cloudflare Pages

In the Cloudflare dashboard open Workers & Pages, create a Pages project and connect your GitHub repository. Set the build command to npm run build and the output directory to dist. Add the two environment variables from step 5. Save and deploy; you get a *.pages.dev URL.

10

Allow the live URL in Supabase

In Supabase Authentication, open URL Configuration and set the Site URL and a redirect URL to your Pages URL. Without this, magic links send users back to localhost.

11

Test and share

Open the live URL in a private window, sign in, add a note, sign out, sign in as a second email and confirm you cannot see the first user's notes. Put the link in your README and resume.

Make it yours

  • A todo list with due dates and a completed filter.
  • An expense tracker with a monthly total per user.
  • A habit tracker with a streak count.
  • A shared list: add a team_id column and a policy that checks membership.

Troubleshooting

ProblemFix
Blank page after deployThe output directory is wrong. Vite builds to dist; set that in Pages.
Magic link sends me to localhostAdd the Pages URL in Supabase URL Configuration (step 10).
Insert fails with a policy errorRow-level security is on but the policy is missing or the user is not signed in. Re-run the policy SQL and check the session.
Keys committed to GitHubRotate the anon key in Supabase and remove the file from history; the anon key is public by design but rotate anyway if a service key leaked.

Frequently asked questions

Is Cloudflare Pages free?

Yes. The free plan covers unlimited static requests and hundreds of builds a month, enough for student and portfolio projects.

Is Supabase free?

Supabase has a free plan with a Postgres database, auth and storage limits that cover small apps. Projects on the free plan pause after a period of inactivity; open the dashboard to resume.

Do I need a backend server?

No. Supabase provides the database and auth; row-level security policies enforce who can read and write.

Can I use Next.js instead of Vite?

Yes. Cloudflare Pages supports Next.js; the Supabase steps are the same.

Learn this with mentors

Programmes for builders and engineers with admissions open: live classes, mentors and project work.

Continue learning

Project guide · Software

Software projects

Full-stack apps with auth, tests, real-time features and CI.

Open guide →23 ideas
Free tools

Free cloud credits and hosting

Credits and always-free tiers to host real projects.

See the list →12 tools
Learning path

Software Development learning path

One language, DSA, full-stack, tests and deployment.