| November 15, 2025 |

I’m using:
AuthForm as the UIMy goal was straightforward: let users sign up and log in without setting up a separate backend server. Next.js + Supabase is perfect for this — as long as you understand which part runs where.

The architecture turns out to be really clean once you see the pattern:
Everything else is just glue.
This is what the user sees. It’s a normal client component with a form and a button:
<form action={handleSubmit}>When the form submits, I use startTransition() so the UI stays smooth while the server action runs:
startTransition(async () => {
const email = formData.get(”email”) as string;
const password = formData.get(”password”) as string;
const result = await loginAction(email, password);
});startTransition() was new to me, but I love what it does:
let React know this is not urgent UI work → no freezing, no jank.
This is where Next.js feels like cheating — I don’t need Express, routes, or API endpoints. I just write a function:
“use server”;
export const loginAction = async (email, password) => {
const { auth } = await createClient();
const { error } = await auth.signInWithPassword({ email, password });
if (error) throw error;
return { errorMessage: null };
};
Anything inside “use server” runs on the backend automatically.
Supabase handles the heavy lifting — I just pass the credentials along and catch errors.
I used Supabase’s SSR helper to create a server-side client that automatically syncs with cookies:
const client = createServerClient(
process.env.SUPABASE_URL,
process.env.SUPABASE_ANON_KEY,
{
cookies: {
getAll() { ... },
setAll() { ... },
},
}
);This is what makes login “stick.” Supabase updates the auth cookies, and my app can read them later with:
const user = await getUser();No token juggling. No localStorage. Just clean SSR auth.
I also explored Supabase + Next middleware, which lets me refresh sessions automatically on every request. Mine isn’t fully wired up yet, but it’s cool to know what’s possible:
It’s a nice bonus for when the app grows.
Now that basic auth works, I’m moving on to:
getUser()/actions/* architecture as the app expandsIt finally feels like the pieces are clicking.
And it’s fun to watch the project slowly turn into something real :)