TechnicalApril 2026 · 11 min read

How to Add a Real Database to a ShipNative App

ShipNative generates apps with Supabase-shaped client code. To make it real, you create the Supabase project, define tables, add row-level security, and point the app at your credentials. This is the step-by-step walkthrough tuned specifically for a ShipNative export.

Quick path

Create a Supabase project → copy your data shape from the ShipNative export into SQL tables → enable RLS on every table → add per-user policies → set two .env values → restart the Expo dev build → verify. About 60–90 minutes.

Step 1: understand what ShipNative gave you

Open the exported project. You’ll typically see:

  • lib/supabase.ts — the Supabase client, reading env vars.
  • .env.example — the two values you need: EXPO_PUBLIC_SUPABASE_URL and EXPO_PUBLIC_SUPABASE_ANON_KEY.
  • Screen files that import from @/lib/supabase and query tables.
  • A README or comments listing the tables the app expects.

The AI has already written the client code. Your job is the server side.

Step 2: create the Supabase project

  1. Go to supabase.com → New project. Pick the region closest to your users.
  2. Wait 2–3 minutes for provisioning.
  3. Project Settings → API → copy the Project URL and the anon public key.
  4. Create a .env in the Expo project root:
EXPO_PUBLIC_SUPABASE_URL=https://xxx.supabase.co
EXPO_PUBLIC_SUPABASE_ANON_KEY=eyJhbGci...

Never commit .env. Add to .gitignore if not already there.

Step 3: create tables

Open Supabase → SQL Editor. Run the DDL for each table referenced in your ShipNative export. Example for a habit tracker:

create table habits (
  id uuid primary key default gen_random_uuid(),
  user_id uuid references auth.users not null,
  name text not null,
  emoji text,
  reminder_time time,
  created_at timestamptz default now()
);

create table check_ins (
  id uuid primary key default gen_random_uuid(),
  habit_id uuid references habits(id)
    on delete cascade not null,
  user_id uuid references auth.users not null,
  date date not null,
  created_at timestamptz default now(),
  unique (habit_id, date)
);

Step 4: enable row-level security

RLS is what keeps users from seeing each other’s data. The anon key in your Expo app lets anyone query — RLS is what stops them from seeing things they shouldn’t.

alter table habits enable row level security;
alter table check_ins enable row level security;

create policy "own habits select" on habits
  for select using (auth.uid() = user_id);
create policy "own habits insert" on habits
  for insert with check (auth.uid() = user_id);
create policy "own habits update" on habits
  for update using (auth.uid() = user_id);
create policy "own habits delete" on habits
  for delete using (auth.uid() = user_id);

-- Repeat for check_ins:
create policy "own checkins select" on check_ins
  for select using (auth.uid() = user_id);
create policy "own checkins insert" on check_ins
  for insert with check (auth.uid() = user_id);
-- update + delete policies similarly

Step 5: auth linkage

If your ShipNative export uses Supabase Auth, you’re done —auth.uid() just works.

If it uses Clerk (or another external auth), you need to pair them via a JWT template:

  1. In the Clerk dashboard, create a JWT template for Supabase.
  2. In Supabase, add Clerk’s JWK URL as an allowed signing source.
  3. Pass the Clerk token to Supabase on every request via supabase.auth.setSession() or an auth handler.

Full walkthrough in React Native Authentication 2026.

Step 6: restart and verify

  • Stop the Expo dev server. Env changes require a restart.
  • npx expo start --clear to clear the cache.
  • Sign up as a new user in the app.
  • Create a habit. Verify it appears in Supabase under habits with your user_id.
  • Sign up as a second user. Verify they don’t see the first user’s habit.
  • If both steps work, RLS is correctly configured.

Common pitfalls

  • Forgetting enable row level security. Default behavior denies all queries without policies — looks like a bug but is actually RLS working. Or (worse) if you disabled RLS in dev and forgot to re-enable, data is open.
  • Env vars not prefixed with EXPO_PUBLIC_. They won’t be available in the client.
  • Not restarting the dev server after editing .env.
  • Copy-pasting the service_role key instead of the anon key. Never put the service_role key in your app.
  • Skipping the two-user test. The only way to confirm RLS is working is to log in as a different user.

You’re done

Your ShipNative app now has real data persistence, real auth, and real security. From here, everything the AI generated now operates against your live backend. Next logical step: add offline support so the app stays useful when users are on spotty connections.

Frequently Asked Questions

Does ShipNative come with a real database wired?

When you describe your data in the prompt (e.g., "Supabase + RLS by user_id"), ShipNative scaffolds the client-side code assuming that backend. You still create the Supabase project yourself and set up tables. The JavaScript plumbing arrives ready.

Why Supabase specifically?

ShipNative defaults to Supabase because it has the best Expo compatibility, generous free tier, and the AI produces higher-quality code when the backend is a Postgres + RLS model. Firebase and others are viable but require more post-export wiring.

Do I need to know SQL?

Basic SELECT/INSERT/UPDATE/DELETE helps. RLS policies are SQL too. You don't need expert-level skills — the Supabase dashboard has a visual SQL editor, and you'll reuse the same patterns across tables.

Can I use a database other than Supabase?

Yes. Firebase, Convex, Appwrite, or your own API all work — you replace the Supabase client calls with the equivalent. Expect more manual wiring since ShipNative scaffolds for Supabase by default. See the broader walkthrough in Connecting an AI-Generated App to a Real Backend.

How long does this take start to finish?

About 60–90 minutes on a typical ShipNative export. Faster if you've done it before; slower the first time if you're learning Supabase for the first time.

Connecting AI App to Real Backend

The broader walkthrough across backends.

Read guide →

Supabase vs Firebase 2026

Why Supabase is the ShipNative default.

Read comparison →

Ship a real React Native app today

Describe, preview, and export Expo code — free to start.

Build with ShipNative →