How to Use the Supabase Service Role Secret Key in Next.js Routes

On my website,, I want users to be able to make purchases without them having a user account. The problem I ran into is that without user accounts, the server needs to be the one writing to the transactions table for the users on Supabase in order to bypass the Row Level Security.

My issue was similar to this GitHub issue: Using service role secret key with supabase-js on the server #1284

Because I am using Next.js Route Handlers for my server-side functions, I needed a way to load up the supabase client without having a user session running.

Typically on Route handlers, you would use createRouteHandlerClient() to initialize the client but then apparently that throws errors for the reasons pointed out by the user in this GitHub issue: Cannot bypass RLS using service_key #598

You cannot use service role with the auth-helpers, this would be a security issue. The auth-helpers by default doesn't allow you to use the service_rolesecret as this could lead to you leaking your service_rolesecret to the public. auth-helpers work in both the server and client side so there is no clear way to separate the key when using it in the client environment.

Luckily they also provided an alternative:

You can however create a separate Supabase client using the @supabase/supabase-jscreateClient method and pass it the service_role``secret. You will also need to turn some properties off since you are working in a server environment.
import { createClient } from '@supabase/supabase-js';

const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL;
const serviceRoleSecret = process.env.SUPABASE_SERVICE_ROLE_SECRET;

const supabase = createClient(supabaseUrl, serviceRoleSecret, {
  auth: {
    persistSession: false,
    autoRefreshToken: false,
    detectSessionInUrl: false,

And that solution seems to work just fine and now I'm sure that only my server route can add to the transactions table in the database.

Also, make sure to not publicly expose the supabase service role secret because that would be equivalent to giving anyone sudo access to your supabase instance.

Any key prefixed with "NEXT_PUBLIC" is exposed to the browser making it publicly accessible.