Tutorial10 min readSep 28, 2025

How to Build a Web Application with Next.js and Supabase

Next.js and Supabase together form a powerful foundation for web applications. This guide walks through the architecture, authentication, database access, and deployment for a production-ready application.

UL

Ullass Engineering Team

Ullass — Software Development & Digital Products

Why Next.js and Supabase?

Next.js and Supabase pair well together for web application development. Next.js provides the full-stack application framework. Supabase provides a hosted PostgreSQL database, authentication, storage, and real-time subscriptions with a straightforward API.

Setting Up the Project

Install the required packages:

bash
npx create-next-app@latest my-app --typescript --tailwind --app cd my-app npm install @supabase/supabase-js @supabase/ssr

Configure environment variables in .env.local:

NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key

Supabase Client Configuration

Server client (for Server Components and Server Actions):

typescript
// lib/supabase/server.ts import { createServerClient } from "@supabase/ssr"; import { cookies } from "next/headers"; export function createClient() { const cookieStore = cookies(); return createServerClient( process.env.NEXT_PUBLIC_SUPABASE_URL!, process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!, { cookies: { getAll: () => cookieStore.getAll(), setAll: (cookiesToSet) => { cookiesToSet.forEach(({ name, value, options }) => cookieStore.set(name, value, options) ); }, }, } ); }

Authentication

Sign-in Server Action:

typescript
"use server"; import { createClient } from "@/lib/supabase/server"; import { redirect } from "next/navigation"; export async function signIn(formData: FormData) { const supabase = createClient(); const { error } = await supabase.auth.signInWithPassword({ email: formData.get("email") as string, password: formData.get("password") as string, }); if (error) throw new Error(error.message); redirect("/dashboard"); }

Database Access

typescript
// Server Component const supabase = createClient(); const { data: posts } = await supabase .from("posts") .select("id, title, created_at") .eq("user_id", user.id) .order("created_at", { ascending: false });

Row Level Security

Enable RLS on every table and define policies:

sql
ALTER TABLE posts ENABLE ROW LEVEL SECURITY; CREATE POLICY "Users can read their own posts" ON posts FOR SELECT USING (auth.uid() = user_id);

Deployment

Deploy Next.js to Vercel:

bash
vercel --prod

Add the Supabase environment variables to the Vercel project settings.

Summary

Next.js and Supabase provide a complete foundation for production web applications. Row Level Security enforces data access at the database level, and the SSR package maintains session state across server and client components.

Related Articles

Ullass — Software Development Company

We build web apps, SaaS platforms, and digital products

Ullass designs, engineers, and scales software products for ambitious businesses. Also try our free online tools at tools.ullass.com. Questions? hello@ullass.com