Skip to main content
RapidDev - Software Development Agency
supabase-tutorial

How to Fix Supabase Sign Up Not Working

When Supabase sign up is not working, the most common causes are the default SMTP email rate limit (2 emails per hour), email confirmation being enabled without proper redirect URL configuration, missing or incorrect API keys, and RLS policies blocking profile creation triggers. Work through the checklist: verify API keys, check email confirmation settings, configure custom SMTP, and ensure your redirect URLs are correct in Dashboard > Authentication > URL Configuration.

What you'll learn

  • How to diagnose the most common signup failure causes in Supabase
  • How to check and fix email confirmation and SMTP settings
  • How to verify API key configuration and redirect URLs
  • How to debug RLS and trigger issues that silently block signups
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Beginner9 min read10-15 minSupabase (all plans), @supabase/supabase-js v2+March 2026RapidDev Engineering Team
TL;DR

When Supabase sign up is not working, the most common causes are the default SMTP email rate limit (2 emails per hour), email confirmation being enabled without proper redirect URL configuration, missing or incorrect API keys, and RLS policies blocking profile creation triggers. Work through the checklist: verify API keys, check email confirmation settings, configure custom SMTP, and ensure your redirect URLs are correct in Dashboard > Authentication > URL Configuration.

Systematic Debugging Checklist for Supabase Signup Failures

Supabase sign up failures are frustrating because they often fail silently — the signUp() method may return a user object without a session, return an error, or appear to succeed while the confirmation email never arrives. This tutorial provides a systematic checklist to identify and fix every common cause, from the 2 emails/hour SMTP limit to misconfigured RLS policies on profile tables.

Prerequisites

  • A Supabase project with Authentication enabled
  • Access to the Supabase Dashboard
  • Your frontend code calling supabase.auth.signUp()
  • A test email address for debugging

Step-by-step guide

1

Check the signUp response for error details

Start by examining the exact response from supabase.auth.signUp(). The response contains a user object, a session object, and an error object. If session is null but user exists, email confirmation is enabled and the user needs to verify their email. If error is not null, the error message tells you exactly what went wrong. Log the full response to understand the state.

typescript
1const { data, error } = await supabase.auth.signUp({
2 email: 'test@example.com',
3 password: 'securepassword123',
4})
5
6// Log the full response for debugging
7console.log('User:', data.user)
8console.log('Session:', data.session)
9console.log('Error:', error)
10
11// Common scenarios:
12// 1. user exists, session is null → Email confirmation is enabled, check inbox
13// 2. user is null, error exists → Check error.message
14// 3. user exists, session exists → Signup succeeded, email confirmation is disabled
15
16// Common error messages:
17// 'User already registered' → Email is taken
18// 'Password should be at least 6 characters' → Password too short
19// 'Signups not allowed for this instance' → Signups are disabled
20// 'Email rate limit exceeded' → Too many emails sent

Expected result: The console output reveals whether the issue is an error, missing session (email confirmation), or something else.

2

Verify your Supabase URL and anon key

Incorrect API keys are a common cause of signup failures. Go to Dashboard > Settings > API and verify that the URL and anon key in your code match exactly. The anon key (not the service role key) should be used in frontend code. Check for trailing spaces, incorrect project references, or accidentally using keys from a different project.

typescript
1// Verify these match Dashboard > Settings > API
2const supabase = createClient(
3 'https://your-project-ref.supabase.co', // Must match exactly
4 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...' // Anon key, NOT service role key
5)
6
7// Common mistakes:
8// - Using 'http://' instead of 'https://'
9// - Trailing slash on the URL
10// - Using the service role key (starts with 'eyJ' but different value)
11// - Using keys from a different Supabase project
12// - Environment variables not loaded (undefined values)

Expected result: The Supabase URL and anon key match exactly what is shown in the Dashboard.

3

Check email confirmation settings and SMTP limits

By default, Supabase enables email confirmation for hosted projects. When enabled, signUp() returns a user with a null session, and a confirmation email is sent. The default SMTP has a 2 emails per hour limit — if you have been testing signups, you may have hit this limit. Check Dashboard > Authentication > Providers > Email to see if 'Confirm email' is enabled, and check Dashboard > Authentication > Settings for SMTP configuration.

typescript
1# Check these Dashboard settings:
2
3# 1. Dashboard > Authentication > Providers > Email
4# - Is 'Confirm email' enabled? If yes, users must click the email link
5# - For testing, you can temporarily disable it
6
7# 2. Dashboard > Authentication > Settings > SMTP
8# - Default SMTP: 2 emails/hour limit
9# - Configure custom SMTP (Resend, SendGrid, Mailgun) for production
10
11# 3. Dashboard > Authentication > URL Configuration
12# - Site URL: your production URL (e.g., https://myapp.com)
13# - Redirect URLs: add localhost for development
14# e.g., http://localhost:3000/auth/callback
15
16# Quick test: disable 'Confirm email' temporarily
17# If signup works with it disabled, the issue is email delivery

Expected result: Email confirmation settings are verified and SMTP is configured to handle your signup volume.

4

Verify redirect URLs are configured

If email confirmation is enabled, the confirmation email contains a link that redirects to your application. If the redirect URL is not configured in the Supabase Dashboard, the confirmation flow will fail. Go to Dashboard > Authentication > URL Configuration and add both your production URL and localhost development URL to the Redirect URLs list.

typescript
1// Dashboard > Authentication > URL Configuration
2// Site URL: https://myapp.com
3// Redirect URLs:
4// - http://localhost:3000/auth/callback
5// - https://myapp.com/auth/callback
6// - https://myapp.vercel.app/auth/callback
7
8// In your signUp call, specify the redirect:
9const { data, error } = await supabase.auth.signUp({
10 email: 'test@example.com',
11 password: 'securepassword123',
12 options: {
13 emailRedirectTo: 'http://localhost:3000/auth/callback',
14 },
15})
16
17// The callback page should handle the auth token exchange:
18// This is needed for PKCE flow used by SSR apps
19// See: how-to-set-up-supabase-auth-with-next-js

Expected result: Redirect URLs are configured for both development and production environments.

5

Check for RLS issues on profile tables and triggers

Many Supabase apps use a trigger to automatically create a profile row when a new user signs up. If the trigger function fails (often due to RLS policies on the profiles table), the signup itself may appear to succeed but downstream operations fail. Check Dashboard > Database > Functions for your trigger function and ensure RLS allows the trigger to insert into the profiles table.

typescript
1-- Check if your trigger function has the correct security mode
2-- Security definer bypasses RLS (needed for triggers that insert into other tables)
3create or replace function public.handle_new_user()
4returns trigger
5language plpgsql
6security definer set search_path = ''
7as $$
8begin
9 insert into public.profiles (id, email)
10 values (new.id, new.email);
11 return new;
12end;
13$$;
14
15-- The trigger should be on auth.users
16create trigger on_auth_user_created
17 after insert on auth.users
18 for each row execute function public.handle_new_user();
19
20-- If using security invoker (default), you need an INSERT policy:
21create policy "Allow profile creation"
22on profiles for insert
23to authenticated
24with check (auth.uid() = id);
25
26-- Check if the trigger exists:
27-- Dashboard > Database > Triggers
28-- Or run in SQL Editor:
29select * from information_schema.triggers
30where trigger_name = 'on_auth_user_created';

Expected result: The trigger function creates profile rows successfully when new users sign up.

Complete working example

debug-signup.ts
1// Complete signup debugging script
2// Run this in your browser console or a test file
3
4import { createClient } from '@supabase/supabase-js'
5
6const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL
7const supabaseKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY
8
9// Step 1: Verify environment variables are loaded
10console.log('Supabase URL:', supabaseUrl ? 'SET' : 'MISSING')
11console.log('Supabase Key:', supabaseKey ? 'SET' : 'MISSING')
12
13if (!supabaseUrl || !supabaseKey) {
14 throw new Error('Missing Supabase environment variables')
15}
16
17const supabase = createClient(supabaseUrl, supabaseKey)
18
19async function debugSignup() {
20 const testEmail = `test-${Date.now()}@example.com`
21 const testPassword = 'testpassword123'
22
23 console.log('Testing signup with:', testEmail)
24
25 // Step 2: Attempt signup
26 const { data, error } = await supabase.auth.signUp({
27 email: testEmail,
28 password: testPassword,
29 })
30
31 if (error) {
32 console.error('Signup error:', error.message)
33 console.error('Error status:', error.status)
34
35 if (error.message.includes('rate limit')) {
36 console.log('FIX: Configure custom SMTP in Dashboard > Auth > Settings')
37 } else if (error.message.includes('not allowed')) {
38 console.log('FIX: Enable signups in Dashboard > Auth > Providers > Email')
39 } else if (error.message.includes('already registered')) {
40 console.log('FIX: This email is already in use')
41 }
42 return
43 }
44
45 // Step 3: Check session status
46 if (data.session) {
47 console.log('Signup successful with immediate session')
48 console.log('Email confirmation is DISABLED')
49 } else if (data.user) {
50 console.log('Signup successful but no session')
51 console.log('Email confirmation is ENABLED — check inbox')
52 console.log('User ID:', data.user.id)
53 console.log('Email confirmed:', data.user.email_confirmed_at ? 'Yes' : 'No')
54 }
55
56 // Step 4: Check if profile was created (if using trigger)
57 if (data.user) {
58 const { data: profile, error: profileError } = await supabase
59 .from('profiles')
60 .select('*')
61 .eq('id', data.user.id)
62 .single()
63
64 if (profileError) {
65 console.warn('Profile not created:', profileError.message)
66 console.log('Check trigger function and RLS policies on profiles table')
67 } else {
68 console.log('Profile created successfully:', profile)
69 }
70 }
71}
72
73debugSignup()

Common mistakes when fixing Supabase Sign Up Not Working

Why it's a problem: Assuming signup failed because session is null, when actually email confirmation is enabled and working correctly

How to avoid: When email confirmation is enabled, signUp() returns a user with session: null. This is expected behavior. The user must click the confirmation link before a session is created.

Why it's a problem: Hitting the default SMTP 2 emails/hour rate limit during development testing

How to avoid: Configure a custom SMTP provider (Resend, SendGrid, Mailgun) in Dashboard > Authentication > Settings > SMTP. The free tier of Resend allows 100 emails/day.

Why it's a problem: Not adding localhost to the redirect URLs list, causing confirmation links to fail in development

How to avoid: Add http://localhost:3000 (or your dev port) to Dashboard > Authentication > URL Configuration > Redirect URLs.

Best practices

  • Always destructure and check both data and error from supabase.auth.signUp() responses
  • Configure a custom SMTP provider before starting development to avoid the 2 emails/hour limit
  • Add all development and production URLs to the redirect URLs list in Dashboard > Authentication > URL Configuration
  • Use security definer on trigger functions that create profiles on signup to avoid RLS permission issues
  • Test signup with a unique email each time (use timestamp-based emails) to avoid 'already registered' errors
  • Check the Supabase Auth logs (Dashboard > Logs > Auth) for server-side error details when client-side errors are vague
  • Temporarily disable email confirmation during early development for faster iteration, then re-enable for production

Still stuck?

Copy one of these prompts to get a personalized, step-by-step explanation.

ChatGPT Prompt

My Supabase signup is not working. The signUp() call returns a user object but session is null, and I never receive the confirmation email. Walk me through a debugging checklist including SMTP settings, email confirmation configuration, redirect URLs, and how to check the auth logs for errors.

Supabase Prompt

Debug my Supabase signup flow. The signUp function returns no error but the user is not being created. Show me how to check the auth logs in Dashboard, verify the API keys are correct, check if email confirmation is blocking the flow, and confirm that my profiles trigger function is working.

Frequently asked questions

Why does signUp return a user but session is null?

This means email confirmation is enabled. The user record is created but the session is not issued until the user clicks the confirmation link in their email. Check Dashboard > Authentication > Providers > Email to see the 'Confirm email' setting.

Why am I not receiving the confirmation email?

The most common cause is the default SMTP rate limit of 2 emails per hour. If you have been testing signups, you may have exhausted this limit. Configure a custom SMTP provider in Dashboard > Authentication > Settings to fix this.

Can I disable email confirmation for development?

Yes. Go to Dashboard > Authentication > Providers > Email and uncheck 'Confirm email'. This gives you an immediate session on signup. Remember to re-enable it for production.

Why do I get 'Signups not allowed for this instance'?

This means public signups are disabled. Go to Dashboard > Authentication > Settings and check that 'Allow new users to sign up' is enabled. This may have been disabled if the project was set to invite-only.

Why does my profile trigger fail after signup?

The most common cause is that the trigger function uses security invoker (default) and there is no INSERT policy on the profiles table. Use security definer on the trigger function or create an INSERT policy that allows the new user to create their profile row.

How do I check if signups are being rate limited?

Check Dashboard > Logs > Auth for rate limit errors. The error message will say 'Email rate limit exceeded'. The default limit is 2 emails per hour. Configure custom SMTP to raise this limit.

Can RapidDev help fix signup issues in my Supabase app?

Yes. RapidDev can diagnose and fix authentication flows including signup, email confirmation, SMTP configuration, and trigger functions for profile creation in your Supabase project.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.