Supabase integration in mobile app

NOVASOLUTIONS.TECHNOLOGY is engaged in the development, support and maintenance of iOS, Android, PWA mobile applications. We have extensive experience and expertise in publishing mobile applications in popular markets like Google Play, App Store, Amazon, AppGallery and others.
Development and support of all types of mobile applications:
Information and entertainment mobile applications
News apps, games, reference guides, online catalogs, weather apps, fitness and health apps, travel apps, educational apps, social networks and messengers, quizzes, blogs and podcasts, forums, aggregators
E-commerce mobile applications
Online stores, B2B apps, marketplaces, online exchanges, cashback services, exchanges, dropshipping platforms, loyalty programs, food and goods delivery, payment systems.
Business process management mobile applications
CRM systems, ERP systems, project management, sales team tools, financial management, production management, logistics and delivery management, HR management, data monitoring systems
Electronic services mobile applications
Classified ads platforms, online schools, online cinemas, electronic service platforms, cashback platforms, video hosting, thematic portals, online booking and scheduling platforms, online trading platforms

These are just some of the types of mobile applications we work with, and each of them may have its own specific features and functionality, tailored to the specific needs and goals of the client.

Showing 1 of 1 servicesAll 1735 services
Supabase integration in mobile app
Medium
~3-5 business days
FAQ
Our competencies:
Development stages
Latest works
  • image_mobile-applications_feedme_467_0.webp
    Development of a mobile application for FEEDME
    756
  • image_mobile-applications_xoomer_471_0.webp
    Development of a mobile application for XOOMER
    624
  • image_mobile-applications_rhl_428_0.webp
    Development of a mobile application for RHL
    1050
  • image_mobile-applications_zippy_411_0.webp
    Development of a mobile application for ZIPPY
    947
  • image_mobile-applications_affhome_429_0.webp
    Development of a mobile application for Affhome
    862
  • image_mobile-applications_flavors_409_0.webp
    Development of a mobile application for the FLAVORS company
    445

Supabase Integration in Mobile Applications

Supabase positions itself as open-source Firebase alternative. Under the hood — PostgreSQL, PostgREST for REST API auto-generation, Realtime via WebSocket (based on Phoenix Channels), GoTrue for authentication, and S3-compatible object storage. Key difference from Firebase: relational database with full SQL, foreign keys, and RLS (Row Level Security).

Initialization in React Native

import { createClient } from '@supabase/supabase-js';
import AsyncStorage from '@react-native-async-storage/async-storage';
import 'react-native-url-polyfill/auto'; // mandatory for RN

export const supabase = createClient(
  process.env.SUPABASE_URL!,
  process.env.SUPABASE_ANON_KEY!,
  {
    auth: {
      storage: AsyncStorage, // session storage
      autoRefreshToken: true,
      persistSession: true,
      detectSessionInUrl: false, // disable for RN (not browser)
    },
  }
);

react-native-url-polyfill is mandatory: Supabase uses URL API which doesn't exist in Hermes/JSC without polyfill. Without it — silent error on first request.

Authentication and AppState

Supabase GoTrue refreshes JWT automatically. But on iOS when in background for long, refresh request may not execute. On return to foreground must explicitly check session:

useEffect(() => {
  const subscription = AppState.addEventListener('change', async (nextState) => {
    if (nextState === 'active') {
      // Force refresh on return from background
      await supabase.auth.getSession();
    }
  });

  const { data: authListener } = supabase.auth.onAuthStateChange((event, session) => {
    if (event === 'TOKEN_REFRESHED') {
      updateGlobalSession(session);
    }
    if (event === 'SIGNED_OUT') {
      clearLocalData();
      navigateToLogin();
    }
  });

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

Typed Requests via Generated Types

Supabase CLI generates TypeScript types from DB schema:

npx supabase gen types typescript --project-id YOUR_PROJECT_ID > database.types.ts
import type { Database } from './database.types';

const { data: posts, error } = await supabase
  .from<Database['public']['Tables']['posts']['Row']>('posts')
  .select('id, title, content, created_at, user_id')
  .eq('user_id', userId)
  .order('created_at', { ascending: false })
  .limit(20);

Typing works at compiler level — wrong column name gives TypeScript error, not runtime. After schema change need to regenerate types.

Realtime Subscriptions

Supabase Realtime listens PostgreSQL WAL (Write-Ahead Log) via logical replication and broadcasts changes to clients:

useEffect(() => {
  const channel = supabase
    .channel(`posts:${userId}`)
    .on(
      'postgres_changes',
      {
        event: '*', // INSERT | UPDATE | DELETE
        schema: 'public',
        table: 'posts',
        filter: `user_id=eq.${userId}`,
      },
      (payload) => {
        if (payload.eventType === 'INSERT') {
          setPosts(prev => [payload.new as Post, ...prev]);
        } else if (payload.eventType === 'DELETE') {
          setPosts(prev => prev.filter(p => p.id !== payload.old.id));
        } else if (payload.eventType === 'UPDATE') {
          setPosts(prev => prev.map(p => p.id === payload.new.id ? payload.new as Post : p));
        }
      }
    )
    .subscribe();

  return () => { supabase.removeChannel(channel); };
}, [userId]);

Important: Realtime sends only changed rows, but payload.new contains only fields allowed via RLS. If RLS restricts columns — some fields will be null in payload.

Row Level Security: Database-Level Protection

RLS is access policies at PostgreSQL level. Even if client has anon key — without matching policy data is inaccessible:

-- Enable RLS for table
ALTER TABLE posts ENABLE ROW LEVEL SECURITY;

-- User sees only own posts
CREATE POLICY "user_can_read_own_posts"
ON posts FOR SELECT
USING (auth.uid() = user_id);

-- User creates only own posts
CREATE POLICY "user_can_insert_own_posts"
ON posts FOR INSERT
WITH CHECK (auth.uid() = user_id);

RLS works at PostgreSQL level — not bypassed even by direct SQL query. Fundamentally important for mobile where anon key is in code and can be extracted via reverse engineering.

File Upload to Storage

import * as FileSystem from 'expo-file-system'; // or react-native-fs

const uploadFile = async (localUri: string, path: string) => {
  const base64 = await FileSystem.readAsStringAsync(localUri, {
    encoding: FileSystem.EncodingType.Base64,
  });

  const { data, error } = await supabase.storage
    .from('avatars') // bucket name
    .upload(path, decode(base64), {
      contentType: 'image/jpeg',
      upsert: true, // overwrite if exists
    });

  if (error) throw error;

  const { data: { publicUrl } } = supabase.storage
    .from('avatars')
    .getPublicUrl(path);

  return publicUrl;
};

decode from base64-arraybuffer package. Supabase Storage accepts ArrayBuffer, not string. On large files use FormData with fetch directly instead of base64 (base64 increases size by 33%).

Estimation

Supabase integration (Auth + PostgreSQL CRUD + Realtime + Storage) with RLS and TypeScript types: 3–5 weeks. Self-hosted Supabase with custom PostgreSQL config: +1–2 weeks.