We ran the same workload through 42 models via AI Gateway and compared costs
/Auth/From Supabase

Migrate from Supabase to Neon

Switch from Supabase Auth and Database to Neon in a few steps

Beta

The Managed Better Auth is in Beta. Share your feedback on Discord or via the Neon Console.

Managed Better Auth provides a Supabase-compatible API, and Neon Data API provides PostgreSQL database access. This guide shows how to migrate from Supabase to Neon.

About user migration

Existing password-based users cannot migrate due to different hashing algorithms. They'll need to create new accounts or re-authenticate via OAuth. This guide works best for new projects, early development, or rebuilding your app.

Prerequisites

  • A Neon project (create one here)
  • Data API enabled (Managed Better Auth is enabled by default when you enable Data API):
    • Go to Postgres database > Data API in the Neon Console and enable it
    • In Data API → Configuration, verify it's configured with Managed Better Auth
    • Copy your Neon connection host and database name from Connect in the Console. The SDK derives both the Auth and Data API URLs from this single base URL. See Initialize the client for the derivation rules, or use the separate Auth and Data API base URLs instead if you'd rather configure them explicitly
  1. Install Neon SDK

    Replace the Supabase SDK with Neon's:

    Terminal
    npm uninstall @supabase/supabase-js
    npm install @neondatabase/neon-js@latest
  2. Update environment variables

    Replace your Supabase credentials with a single Neon base URL. createClient() derives both the Auth and Data API URLs from it automatically:

    .env
    # Remove these:
    # VITE_SUPABASE_URL=https://your-project.supabase.co
    # VITE_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
    
    # Add this:
    VITE_NEON_URL=https://ep-xxx.c-2.us-east-2.aws.neon.build/dbname

    Get your URL:

    Your Neon base URL is the host and database name from your Neon connection string, served over https://. Find these values under Connect in the Neon Console.

    note

    The VITE_ prefix is for Vite. Use NEXT_PUBLIC_ for Next.js, or no prefix for Node.js.

    tip

    If you already copied separate Auth and Data API base URLs from the Console (for example, from an earlier setup), you can still pass them explicitly with the object form. See Initialize the client for both forms.

  3. Update client initialization

    Find your Supabase client file, typically src/supabase.ts or src/lib/supabase.ts, and update it:

    Before (Supabase):

    src/supabase.ts
    import { createClient } from '@supabase/supabase-js';
    
    export const supabase = createClient(
      process.env.VITE_SUPABASE_URL!,
      process.env.VITE_SUPABASE_ANON_KEY!
    );

    After (Neon):

    src/auth.ts
    import { createClient, SupabaseAuthAdapter } from '@neondatabase/neon-js';
    
    export const client = createClient(import.meta.env.VITE_NEON_URL, {
      auth: { adapter: SupabaseAuthAdapter() },
    });

    This example renames the file to auth.ts and the variable to client for a provider-agnostic setup. You can use any naming, just stay consistent throughout your codebase.

    Find all files that import this client and update them:

    // Before
    import { supabase } from './supabase';
    
    // After
    import { client } from './auth';
  4. Your auth code stays the same

    After updating imports, use find/replace to change all instances throughout your codebase:

    supabase.client.

    Your authentication methods, parameters, and responses work identically. Your components, hooks, and auth flows don't change.

    Auth methods
    // Sign up
    await client.auth.signUp({ email, password });
    
    // Sign in with password
    await client.auth.signInWithPassword({ email, password });
    
    // OAuth sign in
    await client.auth.signInWithOAuth({ provider: 'google' });
    
    // Get current user
    const {
      data: { user },
    } = await client.auth.getUser();
    
    // Get session
    const {
      data: { session },
    } = await client.auth.getSession();
    
    // Sign out
    await client.auth.signOut();
  5. Your database queries stay the same

    Your existing client.from() queries work without any code changes:

    // Same as Supabase - no changes needed
    const { data: posts } = await client.from('posts').select('*');
    const { data: user } = await client.from('users').select('*').eq('id', userId).single();

    note

    For production apps, use Row Level Security (RLS) to secure your data. See our RLS with Drizzle guide for the recommended setup.

  6. Test the migration

    Run your app:

    Terminal
    npm run dev

    Test your app:

    1. Sign up a new user
    2. Sign in with that user
    3. Verify the session persists across page reloads
    4. If you enabled Data API: Test user actions that involve database queries (creating posts, loading lists, etc.)

    Your authentication and database queries should work the same as they did with Supabase.

    Verify users in Neon Console:

    Go to Auth → Users in the Neon Console to see your newly created users, or query directly:

    SQL Editor
    SELECT id, email, "createdAt"
    FROM neon_auth.user
    ORDER BY "createdAt" DESC;

What changed?

FeatureSupabaseNeon
User ID typeUUIDUUID
Client configURL + anon keySingle base URL (auto-derives Auth + Data API URLs)
Environment variablesSUPABASE_URL, SUPABASE_ANON_KEYNEON_URL
SDK package@supabase/supabase-js@neondatabase/neon-js

API compatibility

Managed Better Auth supports most Supabase Auth methods including sign up, sign in (password and OAuth), session management, user updates, and email verification. See the Neon TypeScript SDK for the complete API.

Not supported:

MethodDetails
signInWithPhone()Phone authentication (SMS/WhatsApp)
SAML SSO methodsEnterprise SAML authentication
Web3 authenticationBlockchain wallet sign-in

Different behavior:

MethodNotes
updateUser()Does not support password or email parameters
Email verificationUnlike Supabase's automatic verification flow, Managed Better Auth requires you to build the verification UI in your app. See Email Verification for implementation details.

If you're using any unsupported methods or verification flows, you'll need to adjust your implementation.

Need help?

Join our Discord Server to ask questions or see what others are doing with Neon. For paid plan support options, see Support.

Was this page helpful?
Edit on GitHub