Skip to main content
Supabase provides multiple ways to register new users. This guide covers email/password signup, email confirmation, and user metadata.

Email and Password Sign Up

The most common authentication method is email and password:
const { data, error } = await supabase.auth.signUp({
  email: 'example@email.com',
  password: 'example-password',
})

if (error) {
  console.error('Error signing up:', error.message)
} else {
  console.log('User created:', data.user)
}

With User Metadata

Store additional user information during signup:
const { data, error } = await supabase.auth.signUp({
  email: 'example@email.com',
  password: 'example-password',
  options: {
    data: {
      first_name: 'John',
      last_name: 'Doe',
      age: 27,
      avatar_url: 'https://example.com/avatar.jpg'
    }
  }
})

// Access metadata
const user = data.user
console.log(user.user_metadata.first_name) // 'John'
User metadata is stored in the raw_user_meta_data column and is accessible in the JWT token. Don’t store sensitive information here.

Email Confirmation

By default, Supabase requires email confirmation. Users receive a confirmation email with a link:

Enable/Disable Email Confirmation

  1. Go to Authentication > Settings in your Supabase dashboard
  2. Toggle “Enable email confirmations”

Handle Confirmation Callback

app/auth/confirm/route.ts
import { createServerClient } from '@supabase/ssr'
import { NextResponse } from 'next/server'
import { cookies } from 'next/headers'

export async function GET(request: Request) {
  const requestUrl = new URL(request.url)
  const token_hash = requestUrl.searchParams.get('token_hash')
  const type = requestUrl.searchParams.get('type')
  const next = requestUrl.searchParams.get('next') ?? '/'

  if (token_hash && type) {
    const cookieStore = await cookies()
    const supabase = createServerClient(
      process.env.NEXT_PUBLIC_SUPABASE_URL!,
      process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
      {
        cookies: {
          getAll() {
            return cookieStore.getAll()
          },
          setAll(cookiesToSet) {
            cookiesToSet.forEach(({ name, value, options }) =>
              cookieStore.set(name, value, options)
            )
          },
        },
      }
    )

    const { error } = await supabase.auth.verifyOtp({
      type,
      token_hash,
    })

    if (!error) {
      return NextResponse.redirect(new URL(next, request.url))
    }
  }

  // Return to an error page
  return NextResponse.redirect(new URL('/error', request.url))
}

Phone Sign Up

Register users with their phone number:
const { data, error } = await supabase.auth.signUp({
  phone: '+13334445555',
  password: 'example-password',
})
Phone authentication requires setting up an SMS provider in your Supabase dashboard under Authentication > Settings > Phone Auth.

Anonymous Sign Up

Allow users to explore your app without registration:
const { data, error } = await supabase.auth.signInAnonymously()

// Later, convert to permanent account
const { data: userData, error: updateError } = await supabase.auth.updateUser({
  email: 'user@example.com',
  password: 'new-password'
})

Email Redirects

Customize where users are redirected after email confirmation:
const { data, error } = await supabase.auth.signUp({
  email: 'example@email.com',
  password: 'example-password',
  options: {
    emailRedirectTo: 'https://example.com/welcome',
  }
})

Complete Sign-Up Form Example

React Component
import { useState } from 'react'
import { createClient } from '@/lib/supabase/client'

export default function SignUpForm() {
  const [email, setEmail] = useState('')
  const [password, setPassword] = useState('')
  const [firstName, setFirstName] = useState('')
  const [loading, setLoading] = useState(false)
  const [message, setMessage] = useState('')
  
  const supabase = createClient()

  const handleSignUp = async (e) => {
    e.preventDefault()
    setLoading(true)
    setMessage('')

    const { data, error } = await supabase.auth.signUp({
      email,
      password,
      options: {
        data: {
          first_name: firstName,
        },
        emailRedirectTo: `${window.location.origin}/auth/callback`,
      }
    })

    if (error) {
      setMessage(error.message)
    } else {
      setMessage('Check your email to confirm your account!')
    }
    
    setLoading(false)
  }

  return (
    <form onSubmit={handleSignUp}>
      <input
        type="text"
        placeholder="First Name"
        value={firstName}
        onChange={(e) => setFirstName(e.target.value)}
        required
      />
      <input
        type="email"
        placeholder="Email"
        value={email}
        onChange={(e) => setEmail(e.target.value)}
        required
      />
      <input
        type="password"
        placeholder="Password"
        value={password}
        onChange={(e) => setPassword(e.target.value)}
        required
        minLength={6}
      />
      <button type="submit" disabled={loading}>
        {loading ? 'Signing up...' : 'Sign Up'}
      </button>
      {message && <p>{message}</p>}
    </form>
  )
}

Password Requirements

Enforce strong passwords in your Supabase dashboard:
  • Minimum length (default: 6 characters)
  • Require uppercase letters
  • Require lowercase letters
  • Require numbers
  • Require special characters

Error Handling

Common signup errors:
Error CodeDescriptionSolution
user_already_existsEmail is already registeredDirect user to sign in
invalid_emailEmail format is invalidValidate email on client
weak_passwordPassword doesn’t meet requirementsShow password requirements
email_provider_disabledEmail auth is disabledEnable in dashboard

Next Steps

Sign In Users

Learn how to authenticate existing users

OAuth Providers

Add social login to your app