Skip to main content

How to Use Supabase in React Native

ยท 4 min read
Full Stack Developer
Last updated on May 6, 2026

supabase-react-native

Supabase can be a strong backend for React Native apps when you want PostgreSQL, SQL, Row Level Security, Auth, Storage, and Edge Functions. The key React Native detail is session persistence: configure storage and URL handling before building screens on top of the Supabase client.

Quick Answerโ€‹

Install @supabase/supabase-js, add a URL polyfill, persist auth sessions with AsyncStorage, use a publishable key in the app, and protect tables with Row Level Security. Never put a Supabase secret key or service role key in a React Native bundle.

If you are comparing with Firebase, read:

Install Supabase for React Nativeโ€‹

yarn add @supabase/supabase-js
yarn add @react-native-async-storage/async-storage react-native-url-polyfill
cd ios && pod install

If you use Expo, follow the Supabase Expo quickstart for package installation. The app code below still applies to the core Supabase client setup.

Mega Bundle Sale is ON! Get ALL of our React Native codebases at 90% OFF discount ๐Ÿ”ฅ

Get the Mega Bundle

Initialize the Supabase Clientโ€‹

Create lib/supabase.ts:

import { AppState, Platform } from 'react-native';
import 'react-native-url-polyfill/auto';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { createClient, processLock } from '@supabase/supabase-js';

const supabaseUrl = process.env.EXPO_PUBLIC_SUPABASE_URL;
const supabasePublishableKey =
process.env.EXPO_PUBLIC_SUPABASE_PUBLISHABLE_KEY;

if (!supabaseUrl || !supabasePublishableKey) {
throw new Error('Missing Supabase environment variables');
}

export const supabase = createClient(
supabaseUrl,
supabasePublishableKey,
{
auth: {
...(Platform.OS !== 'web' ? { storage: AsyncStorage } : {}),
autoRefreshToken: true,
persistSession: true,
detectSessionInUrl: false,
lock: processLock,
},
}
);

if (Platform.OS !== 'web') {
AppState.addEventListener('change', state => {
if (state === 'active') {
supabase.auth.startAutoRefresh();
} else {
supabase.auth.stopAutoRefresh();
}
});
}

Use the publishable key from your Supabase project settings. The secret key and service role key belong on trusted servers only.

Sign Up and Sign Inโ€‹

export async function signUpWithEmail(email: string, password: string) {
const { data, error } = await supabase.auth.signUp({
email,
password,
});

if (error) {
throw error;
}

return data;
}

export async function signInWithEmail(email: string, password: string) {
const { data, error } = await supabase.auth.signInWithPassword({
email,
password,
});

if (error) {
throw error;
}

return data;
}

Listen for auth changes once near the app root:

useEffect(() => {
const {
data: { subscription },
} = supabase.auth.onAuthStateChange((_event, session) => {
setSession(session);
});

return () => subscription.unsubscribe();
}, []);

Create a Table with Row Level Securityโ€‹

Example todo table:

create table public.todos (
id uuid primary key default gen_random_uuid(),
user_id uuid not null references auth.users(id) on delete cascade,
title text not null,
completed boolean not null default false,
created_at timestamptz not null default now()
);

alter table public.todos enable row level security;

create policy "Users can read their own todos"
on public.todos
for select
using (auth.uid() = user_id);

create policy "Users can insert their own todos"
on public.todos
for insert
with check (auth.uid() = user_id);

RLS is not optional for client-side apps. The publishable key is expected to be public, so database policies must enforce the real permissions.

Query Data from React Nativeโ€‹

export async function fetchTodos() {
const { data, error } = await supabase
.from('todos')
.select('*')
.order('created_at', { ascending: false });

if (error) {
throw error;
}

return data;
}

export async function addTodo(title: string, userId: string) {
const { data, error } = await supabase
.from('todos')
.insert({ title, user_id: userId })
.select()
.single();

if (error) {
throw error;
}

return data;
}

Storage Notesโ€‹

Supabase Storage can handle profile photos and user uploads, but it needs bucket policies just like database tables need RLS policies. Store metadata in Postgres, keep files in Storage, and use signed URLs when files should not be public.

Useful Referencesโ€‹

Looking for a custom mobile application?

Our team of expert mobile developers can help you build a custom mobile app that meets your specific needs.

Get in Touch

Conclusionโ€‹

Supabase works well in React Native when the client is initialized correctly and the database is protected with Row Level Security. Treat the publishable key as public, persist sessions with AsyncStorage, and keep privileged operations in Edge Functions or another trusted backend.