BASE44DEVS

MIGRATION · BASE44 → NEXT.JS + SUPABASE

Base44 to Next.js + Supabase: Technical Migration Reference

This reference covers the technical surface of a base44 to Next.js + Supabase migration: SDK call equivalents, schema mapping rules, RLS translation tables, Edge Function porting, and the library substitutions that make the new stack work. For the engagement-level narrative (when to migrate, team workflow, week-by-week plan, fixed-scope pricing), read the companion playbook: /blog/base44-to-nextjs-supabase-migration-playbook.

Last verified
2026-10-17
Difficulty
HARD
Est. effort
~360h
Target
Next.js + Supabase

This page is the technical reference for a base44 to Next.js + Supabase migration: the SDK-to-Supabase call mapping, the schema translation rules, the RLS porting templates, and the library equivalents you will reach for during a rebuild. It is what you keep open in a second tab while you work.

If you want the engagement-level narrative — when to migrate, how a /migrate engagement is phased, timelines and costs, the team workflow, and the cutover runbook — read the Base44 to Next.js Supabase migration playbook. That document is the project plan; this one is the porting manual.

If you are still deciding whether to leave at all, read when to leave base44 first, then come back. If you have decided to leave but not where to go, which alternative to move to prices all eight destinations against each other.

Why migrate to Next.js + Supabase

You are leaving base44 for one of three reasons, and all three lead here:

  1. You want code ownership. Base44's exported code is locked to the base44 SDK. Every database call, auth check, and file upload goes through @base44/sdk. Even after export, your code does not run anywhere else without a rewrite. This is the vendor lock-in problem.
  2. You hit a production ceiling. Rate limits, no uptime SLA below Enterprise, the February 2026 outage, regression loops, and search visibility you only partly control all push real apps off the platform.
  3. You need realtime beyond record changes. Base44's documented realtime is record-change subscriptions through entities.subscribe() (docs.base44.com, read 25 Sep 2026). Supabase Realtime adds Broadcast and Presence channels for chat, cursors and who-is-online state (supabase.com).

Next.js + Supabase is the destination because it inverts every base44 weakness. Server-side rendering by default. Full SQL. RLS that works the same way as base44's row-level rules. Edge Functions on Deno (the same runtime base44 uses for backend functions, so most function code ports with light edits). Free local development. Deterministic deploys. Real Git.

The trade is real, though. You give up the AI agent, the all-in-one editor, and the prompt-to-prototype speed. If those are your edge, this is not your migration.

What you keep, what you rebuild

Be honest about scope before you start. The frontend mostly carries; the backend always rebuilds.

LayerWhat you keepWhat you rebuild
React componentsJSX, Tailwind, hooksAnything calling base44.entities.* or base44.functions.*
RoutingPage structureRe-implement on Next.js App Router
Schema definitionsField names + types as referenceRecreate as SQL DDL or Prisma schema
Database rowsYes (export + backfill)None
AuthenticationEmail addresses, user IDs (as legacy keys)Sessions, password hashes (force re-issue), OAuth client IDs
RLS rulesLogic as pseudocodeRewrite as Postgres CREATE POLICY
Backend functionsFunction bodies (Deno code mostly portable)Wrap as Supabase Edge Functions or Next.js route handlers
File uploadsFiles themselves (re-upload to Supabase Storage)Upload paths, signed URLs
WebhooksExternal webhook URLsEndpoint code; update sender configs
Scheduled jobsAutomation schedules and triggers, as referenceRebuild with Supabase pg_cron or Vercel cron
Real-timeentities.subscribe() call sites, as referenceRewrite on Supabase Realtime
Email integrationTemplates as textRe-wire to Resend, Postmark, or SES
Third-party integrationsCredentialsOAuth flows, token refresh logic

Plan for every file that touches data to be rewritten. The frontend illusion of "it's just React" hides the fact that every data fetch is a base44 SDK call.

Architecture: source vs target

Base44 (current):

[browser] → CSR React bundle
              ↓
        @base44/sdk (auth + entities + functions)
              ↓
     base44 platform (managed DB + Deno + Storage + Auth)
              ↓
            you have no idea

Everything runs on base44 infrastructure. You have no SQL access, no logs you control, no way to add a sidecar service, no way to run a cron, and no way to test offline.

Next.js + Supabase (target):

[browser] → Next.js (SSR + RSC + Client Components)
              ↓
       @supabase/ssr + @supabase/supabase-js
              ↓
   Supabase (Postgres + Auth + Storage + Edge Functions + Realtime)
              ↓
       you own the schema, the SQL, the logs, the deploys

You can develop locally with supabase start. You can run migrations with supabase migration new. You can read every query in the dashboard. You can attach Datadog. You can fork your dev DB. You can write SQL.

Step-by-step migration plan

This is the order we run it in. Skip a step at your own risk.

Phase 1 — Discovery (Week 1)

1. Inventory every entity, function, and integration

Open base44 and list every entity, every backend function, every integration, every scheduled prompt, every external webhook. Capture row counts per entity. Capture call volumes per function from the platform metrics if you have them.

# A simple inventory file
mkdir -p migration && cd migration
cat > inventory.md <<'EOF'
## Entities
- users (~12,400 rows)
- projects (~8,200 rows)
- tasks (~94,300 rows)
...

## Functions
- POST /functions/createInvoice (Stripe)
- POST /functions/sendDigest (cron-style)
...

## Integrations
- Stripe (subscriptions)
- Resend (transactional email)
- Slack webhook (alerts)
EOF

Expect the inventory to turn up surface area you did not know about. Do this in week one or you will miss things at cutover.

2. Map every base44 SDK call

Grep your exported codebase for every SDK reference:

grep -rn "base44\." src/ > sdk-calls.txt
wc -l sdk-calls.txt

The line count is your effort estimate: time yourself rewriting a handful of calls, then multiply.

3. Decide on parallel-run vs hard cutover

Parallel-run means you dual-write from base44 to Supabase for one to two weeks, validate parity, then redirect users. Hard cutover means you stop the world, migrate, and reopen in the new stack.

Choose parallel-run if you have paying users or production data. Choose hard cutover if you have under fifty active users and acceptable downtime. We default to parallel-run.

Phase 2 — Schema (Week 2)

4. Stand up Supabase and mirror the schema

npx create-next-app@latest my-app --typescript --tailwind --app
cd my-app
npm install @supabase/supabase-js @supabase/ssr
npx supabase init
npx supabase start

Translate each base44 entity to a Postgres table. Base44's "fields" map to columns. Be aggressive about converting string fields to proper types (uuid, timestamptz, numeric, text with constraints).

-- supabase/migrations/0001_init.sql
create table public.projects (
  id uuid primary key default gen_random_uuid(),
  owner_id uuid not null references auth.users(id) on delete cascade,
  name text not null,
  status text not null default 'draft' check (status in ('draft','active','archived')),
  created_at timestamptz not null default now(),
  updated_at timestamptz not null default now()
);

create index projects_owner_id_idx on public.projects(owner_id);

5. Rebuild RLS

Base44's row-level rules become Postgres policies. The mental model is the same; the syntax is different.

alter table public.projects enable row level security;

create policy "owner_can_select" on public.projects
  for select using (auth.uid() = owner_id);

create policy "owner_can_insert" on public.projects
  for insert with check (auth.uid() = owner_id);

create policy "owner_can_update" on public.projects
  for update using (auth.uid() = owner_id);

create policy "owner_can_delete" on public.projects
  for delete using (auth.uid() = owner_id);

Test every policy with at least two users before moving on. An RLS bug that ships at cutover leaks one user's rows to another.

Phase 3 — Auth (Week 3)

6. Re-issue auth

You cannot migrate password hashes from base44; the platform does not expose them. You have two choices:

  1. Force a password reset on every user. Send a one-time email with a magic link to set a new password on Supabase. This is our default.
  2. Keep base44 sessions live during dual-run. Validate base44 JWT in your Next.js middleware as a fallback while users gradually migrate. Cut off after thirty days.

For OAuth users (Google, GitHub), point Supabase Auth at the same OAuth client IDs and they re-link by email automatically.

// app/auth/migrate/route.ts
import { createClient } from "@/lib/supabase/server";
import { NextResponse } from "next/server";

export async function POST(req: Request) {
  const { email } = await req.json();
  const supabase = createClient();
  const { error } = await supabase.auth.admin.inviteUserByEmail(email, {
    data: { migrated_from: "base44" },
  });
  if (error) return NextResponse.json({ error: error.message }, { status: 400 });
  return NextResponse.json({ ok: true });
}

Phase 4 — Data backfill (Week 4)

7. Export from base44, transform, load to Supabase

Use base44's export endpoint or the SDK to dump every entity to JSON. Transform to match your new schema. Load via Supabase service-role key.

// scripts/backfill-projects.ts
import { createClient } from "@supabase/supabase-js";
import projects from "./export/projects.json";

const sb = createClient(process.env.SUPABASE_URL!, process.env.SUPABASE_SERVICE_ROLE!);

for (const batch of chunk(projects, 500)) {
  const { error } = await sb.from("projects").insert(
    batch.map((p) => ({
      id: p.id,
      owner_id: p.user_id,
      name: p.name,
      status: p.status ?? "draft",
      created_at: p.createdAt,
    }))
  );
  if (error) {
    console.error("batch failed", error);
    process.exit(1);
  }
}

Run on staging first. Validate row counts match. Spot-check ten random rows per entity.

Phase 5 — API rebuild (Weeks 5–7)

8. Port backend functions to Supabase Edge Functions

Base44 backend functions run on Deno. Supabase Edge Functions also run on Deno. Most function bodies port with two changes: replace base44.entities.X.create() with a Supabase client call, and read secrets from Deno.env.

// supabase/functions/create-invoice/index.ts
import { createClient } from "jsr:@supabase/supabase-js@2";
import Stripe from "npm:stripe@14";

Deno.serve(async (req) => {
  const { project_id, amount } = await req.json();
  const sb = createClient(Deno.env.get("SUPABASE_URL")!, Deno.env.get("SUPABASE_SERVICE_ROLE")!);
  const stripe = new Stripe(Deno.env.get("STRIPE_SECRET")!);

  const invoice = await stripe.invoices.create({ customer: "...", auto_advance: true });
  await sb.from("invoices").insert({ project_id, stripe_id: invoice.id, amount });
  return new Response(JSON.stringify({ id: invoice.id }), {
    headers: { "content-type": "application/json" },
  });
});

Deploy with supabase functions deploy create-invoice. Every function is independently deployable, version-controlled, and locally testable. This alone is worth the migration.

9. Replace base44.entities.* calls in the frontend

The mechanical work. For every base44.entities.X.filter() or .list() call, replace it with a Supabase query.

// before
const projects = await base44.entities.Project.filter({ ownerId: user.id });

// after
const { data: projects } = await supabase
  .from("projects")
  .select("*")
  .eq("owner_id", user.id);

Do this in batches by route. Ship behind a feature flag. Compare outputs against the base44 production data. Difference of zero, you can flip the flag.

Phase 6 — Cutover (Week 8)

10. Dual-write window

For ten to fourteen days, every write hits both base44 and Supabase. Reads still come from base44. Compare row counts daily.

async function createProject(payload) {
  const [b44, sb] = await Promise.allSettled([
    base44.entities.Project.create(payload),
    supabase.from("projects").insert(payload),
  ]);
  if (b44.status === "rejected" || sb.status === "rejected") {
    await alertSlack("dual-write divergence", { b44, sb });
  }
  return b44.value; // base44 still source of truth
}

11. Read cutover

Flip read traffic to Supabase one entity at a time. Watch error rates. Roll back at any sign of trouble. Once all reads are on Supabase and stable for forty-eight hours, you are ready for write cutover.

12. Write cutover and freeze

Stop dual-writing. All traffic on Supabase. Lock the base44 app to read-only. Take a final snapshot of base44 data and store it in cold storage.

Phase 7 — Sunset (Weeks 9–10)

13. Validate, monitor, decommission

Run every business workflow end-to-end on the new stack. Compare aggregate metrics (signups, MRR, retention) against the prior week. If everything looks normal for two weeks, cancel the base44 plan.

Keep the read-only base44 export for ninety days. It is cheap insurance: if something turns out to be missing after cutover, the export is where you recover it.

Common pitfalls

1. Underestimating SDK call volume. Guessing the call count is how migrations get underscoped. Grep first.

2. Forgetting RLS on backfill. If you load with the service-role key, RLS is bypassed. Re-enable and test policies before opening reads to users.

3. Auth re-issue surprises. Users who never log in during the dual-run window get locked out at write cutover. Send a "your account is moving" email two weeks before.

4. Missed scheduled jobs. Scheduled work can live in base44 automations, frontend timers or external services like Cron-job.org. Document them all and rebuild on Supabase pg_cron or Vercel cron.

5. Realtime expectations. Once you migrate, users will ask for real-time updates because Supabase makes it trivial. Decide upfront whether you are scoping real-time in or out, or scope creep eats your timeline.

6. Stripe webhook endpoints. Update the endpoint URL in your Stripe dashboard at write cutover. Forget this and subscription renewals fail silently for hours. Same for any webhook from external systems.

7. SEO regression. Base44 apps render client-side for visitors, but Base44 serves search engines and AI crawlers a prerendered version of each page — real headings, content, meta tags and structured data — refreshed when you publish (docs.base44.com, read 23 Sep 2026). So your pages may already be indexed and ranking. Next.js with SSR gives every visitor HTML you own and puts every page's metadata in code, but URL structure changes can wipe the rankings you already have. Map every old URL to a new one and ship 301 redirects on day one. If pages were missing from Google before the move, rule out the configuration causes first.

Timeline + team

Plan eight to twelve weeks with this team:

  • One senior full-stack engineer. Owns the rebuild end-to-end. Forty hours per week.
  • One part-time DBA or backend specialist. Owns schema, RLS, and backfill. Ten hours per week.
  • One product owner from your side. Validates feature parity. Five hours per week.

Smaller team works for smaller apps. Two weeks of one engineer can move a tiny CRUD app. Beyond medium scope, do not try this with one part-time engineer; you will burn months and ship nothing.

Cost

Pricing tiers from our migration practice:

TierPriceWhat you get
Small$6,000Up to 5 tables, 10 routes and single-role auth; data, users and uploaded files included; 2–3 weeks
Medium$12,000Up to 20 tables, multi-role auth, Stripe; 4–5 weeks
Enterprise$25,000+Multi-tenant, SOC 2- or HIPAA-compatible target, custom integrations, phased cutover; written proposal within one week

Each tier is fixed-price, quoted in writing after a free 15-minute call. Every tier includes schema design, backfill scripts, dual-run setup and cutover, and ships with zero data loss, your Base44 app kept live as the fallback, a 14-day rollback window after cutover, and a 30-day defects warranty on the migrated code. The eight-to-twelve-week range above is for a team doing the work in-house.

You can start with the $497 production audit to confirm the tier before committing. The $497 fee is credited in full against any fix, build, migration or written-recommendation engagement booked within 30 days. If you ordered the audit for a specific bug and we cannot reproduce it, we refund the fee; otherwise it is non-refundable.

DIY costs nothing in cash. It costs one senior engineer eight to twelve weeks of focused time, paid at their fully-loaded salary. Either way, you are spending money. Decide which currency you have more of.

DIY vs hire decision

DIY this if:

  • Your app has under twenty entities and standard auth.
  • You have a senior engineer with React, Next.js, and Postgres experience already on the team.
  • You can spare eight weeks of their focused time without missing other commitments.
  • You do not have paying users who will churn during downtime.

Hire help if:

  • Your app has over fifty entities, custom integrations, or complex RLS.
  • You are running on revenue that depends on the app being live.
  • Your team is full-stack JavaScript but has no Postgres or RLS experience.
  • You tried the migration once and got stuck.

The most expensive migration is one you start, abandon, and restart six months later.

Want a free migration assessment?

We will look at your base44 app, count your SDK calls, identify the risk hotspots, and give you a fixed-price scope. Free 15-minute call with the engineer who would lead the work. Written fixed-price proposal within one business day.

Book a free migration assessment

QUERIES

Frequently asked questions

Q.01How long does it actually take to migrate a base44 app to Next.js and Supabase?
A.01

Eight to twelve weeks for a single production app with one to two engineers. A small CRUD app with a dozen entities and email auth is closer to four to six weeks. An app with custom integrations, complex RLS rules, scheduled jobs, and external webhooks is twelve to sixteen weeks. The variable that matters most is how many base44 SDK calls live in your frontend; every one of them has to be rewritten.

Q.02Will my exported base44 code work as-is on Next.js?
A.02

No. The exported code is React + Tailwind which mostly carries over, but every component that calls the base44 SDK is broken until you rewrite the data layer. The frontend folder is reusable. The backend folder, schema definitions, and auth integration all need replacement. Scope it by counting SDK calls: the data-access layer is rebuilt in full, while presentational components carry over with light edits.

Q.03Can I migrate the database without downtime?
A.03

Yes, with a dual-write window. Stand up Supabase, mirror the schema, backfill historical data, then dual-write from base44 to Supabase for one to two weeks while you validate. Cut over reads first, then writes. Total downtime can be under five minutes if you do this carefully. A fifteen-to-thirty-minute maintenance window is the simpler option if your users can tolerate it.

Q.04What does Supabase replace in base44?
A.04

Supabase Postgres replaces base44's database. Supabase Auth replaces base44 Auth, including OAuth and magic links. Supabase Storage replaces base44 file storage. Supabase Edge Functions (Deno) replace base44 backend functions, with the bonus that you can run them locally. Supabase Realtime replaces base44's record-change subscriptions through entities.subscribe() (docs.base44.com, read 25 Sep 2026) and adds Broadcast and Presence channels for chat, cursors and who-is-online state.

Q.05How much does this migration cost if I hire it out?
A.05

Our small migration is $6,000 fixed for up to 5 tables, 10 routes and single-role auth, delivered in 2–3 weeks. Medium is $12,000 for up to 20 tables, multi-role auth and Stripe, in 4–5 weeks. Enterprise starts at $25,000 for multi-tenant apps, SOC 2- or HIPAA-compatible targets and phased cutovers. Every tier moves your data, users and uploaded files with zero data loss, keeps the Base44 app live as the fallback, and carries a 14-day rollback window and a 30-day defects warranty. DIY is free in cash but costs an engineer two to three months of focused time.

Q.06What do I lose by leaving base44?
A.06

You lose the AI agent that generates code from prompts, the all-in-one editor, and the platform-managed deploys. You gain code ownership, deterministic deploys, real version control, the ability to scale without rate limits, Broadcast and Presence channels, and full SQL. If code ownership is why you are leaving, that is the trade you are making on purpose.

Q.07Should I migrate to Supabase or build my own Postgres?
A.07

Supabase if you want fast wins on auth, storage, RLS, and edge functions without operating infrastructure. Self-hosted Postgres if you have compliance constraints (data residency, on-prem) or already run Kubernetes. Unless one of those constraints applies, Supabase is the right answer. See our self-hosted playbook if Supabase does not fit.

NEXT STEP

Plan your migration with engineers who have done it before.

Free 15-minute call with the engineer who would lead the work. Written fixed-price proposal within one business day.