How to Move from Base44 to a Self-Hosted Stack (React + Supabase + Vercel)
Base44 is a fully managed AI app platform — your frontend, backend, database, auth, integrations, and automations all live under one roof. That's its superpower. But some teams reach a point where they need the raw control of owning their own infrastructure: custom database queries, specific compliance requirements, unlimited server customization, or simply wanting to eliminate platform dependency.
This guide walks through migrating your Base44 application to a fully self-hosted stack: React + Vite (frontend), Supabase (database + auth), Deno/Node.js (backend functions), and Vercel (deployment).
What You're Replacing
| Base44 Component | Self-Hosted Equivalent |
|---|---|
| Entities (database) | Supabase PostgreSQL tables |
| Built-in auth | Supabase Auth |
| Backend functions | Deno Deploy / Vercel Edge Functions / Node.js API |
| Automations (scheduled) | GitHub Actions / Supabase pg_cron |
| Automations (entity triggers) | Supabase Webhooks + Edge Functions |
| OAuth connectors | Manual OAuth setup per provider |
| InvokeLLM integration | Anthropic / OpenAI SDK directly |
| File uploads | Supabase Storage or AWS S3 |
| Hosting | Vercel (frontend) + Supabase (backend) |
Step 1: Export Your Base44 Frontend Code
Base44 apps are standard React + Vite + Tailwind projects. To export:
- In your Base44 app, open the code editor
- Download all source files (pages, components, lib, hooks)
- Note your entities schema — you'll recreate these as Supabase tables
The React code (components, pages, Tailwind classes, shadcn/ui) will work as-is. Only the data layer needs to change.
Step 2: Export Your Data
- In Base44, go to the admin panel for each Entity
- Export all records as CSV
- Save with clear filenames:
users.csv,products.csv, etc.
Step 3: Create a Supabase Project
- Create a free project at supabase.com
- For each Base44 Entity, create the equivalent Supabase table
Example — a Base44 Product entity becomes a Supabase migration:
CREATE TABLE products (id UUID DEFAULT gen_random_uuid() PRIMARY KEY, name TEXT NOT NULL, price NUMERIC, description TEXT, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW(), created_by UUID REFERENCES auth.users(id) );
-- Row Level Security ALTER TABLE products ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Users can read all products" ON products FOR SELECT USING (true);
CREATE POLICY "Users can insert their own products" ON products FOR INSERT WITH CHECK (auth.uid() = created_by);
CREATE POLICY "Users can update their own products" ON products FOR UPDATE USING (auth.uid() = created_by);
Step 4: Import Your Data into Supabase
- In Supabase → Table Editor → select your table
- Click Import from CSV
- Upload the exported CSV from Base44
- Map columns and confirm import
Step 5: Replace Base44 SDK Calls with Supabase Client
This is the main code migration step. Every Base44 SDK call needs a Supabase equivalent.
Install Supabase client:
npm install @supabase/supabase-js
npm install @supabase/auth-ui-react
Create a Supabase client file:
// src/lib/supabase.tsimport { createClient } from '@supabase/supabase-js';
export const supabase = createClient( import.meta.env.VITE_SUPABASE_URL, import.meta.env.VITE_SUPABASE_ANON_KEY );
SDK migration reference:
| Base44 SDK | Supabase Equivalent |
|---|---|
base44.entities.Product.list() | supabase.from('products').select('*') |
base44.entities.Product.filter({status: 'active'}) | supabase.from('products').select('*').eq('status', 'active') |
base44.entities.Product.create(data) | supabase.from('products').insert(data) |
base44.entities.Product.update(id, data) | supabase.from('products').update(data).eq('id', id) |
base44.entities.Product.delete(id) | supabase.from('products').delete().eq('id', id) |
base44.auth.me() | supabase.auth.getUser() |
base44.auth.logout() | supabase.auth.signOut() |
Step 6: Replace Base44 Auth
Base44's auth system is replaced with Supabase Auth. Update your auth context:
// src/lib/auth.tsimport { supabase } from './supabase';
export async function signIn(email: string, password: string) { const { data, error } = await supabase.auth.signInWithPassword({ email, password }); if (error) throw error; return data; }
export async function signUp(email: string, password: string) { const { data, error } = await supabase.auth.signUp({ email, password }); if (error) throw error; return data; }
export async function getCurrentUser() { const { data: { user } } = await supabase.auth.getUser(); return user; }
Step 7: Migrate Backend Functions
Base44 backend functions are Deno scripts. They can migrate to:
- Supabase Edge Functions (also Deno — near-identical migration)
- Vercel Serverless Functions (Node.js)
- Cloudflare Workers
For Supabase Edge Functions (recommended for minimal changes):
supabase functions new my-functionCopy your Base44 function logic into supabase/functions/my-function/index.ts
supabase functions deploy my-function
Step 8: Migrate Automations
Scheduled automations → GitHub Actions:
# .github/workflows/daily-job.yml
name: Daily Automation on: schedule: - cron: '0 9 *' # 9am daily jobs: run: runs-on: ubuntu-latest steps: - name: Call function run: curl -X POST https://your-project.supabase.co/functions/v1/daily-job
Entity automations → Supabase Webhooks:
- Supabase Dashboard → Database → Webhooks
- Create webhook for INSERT/UPDATE/DELETE on your table
- Point it to your Edge Function URL
Step 9: Deploy to Vercel
npm install -g vercelvercel login vercel
Add env vars:
vercel env add VITE_SUPABASE_URL vercel env add VITE_SUPABASE_ANON_KEY
The Honest Tradeoff
You gain complete infrastructure control and eliminate platform lock-in. You lose Base44's AI-powered development experience, built-in integrations, and zero-DevOps environment. For most teams, Base44 is the more productive choice unless you have specific compliance, customization, or cost reasons to self-host.