BASE44DEVS

ARTICLE · 11 MIN READ

Base44 Vendor Lock-In: What's Actually Locked, What's Portable

Base44's lock-in is not a single thing. It is a stack of bindings: the SDK that calls home to base44.com, the entity layer with no portable schema, the integrations bound to platform credentials, the rendering layer assuming Base44's runtime, and the auth tokens issued by Base44's identity service. Each binding has different escape costs. This article walks each one with realistic estimates of what you can take with you and what you have to rebuild.

Last verified
2026-05-01
Published
2026-05-01
Read time
11 min
Words
2,055
  • LOCK-IN
  • MIGRATION
  • PORTABILITY
  • SDK

Why this matters

Vendor lock-in discussions usually devolve into religious arguments. This one will not, because we will be specific about which parts of Base44 are locked in, which are portable, and what each costs to escape. The goal: give you a realistic dollar and time estimate for "what if we leave?" so the question stops being scary and starts being a budget item.

We have run six client migrations off Base44 in the last twelve months. The numbers in this article come from those engagements, not from theory.

The five bindings

Base44 lock-in is not one thing. It is five layered bindings, each with its own escape cost. Naming them precisely lets you plan migration phase by phase rather than as one terrifying lump.

  1. SDK binding — every API call goes through @base44/sdk to base44.com.
  2. Entity binding — your data is in a managed Postgres you don't have direct access to.
  3. Integration binding — your Stripe, Twilio, OpenAI calls go through platform-managed credentials.
  4. Rendering binding — your app assumes Base44's hosted shell and CSR runtime.
  5. Identity binding — your users authenticate against Base44's identity service.

Some are easier to escape than others. We will walk each.

Binding 1: the SDK

What's locked. Every entity CRUD call (Entity.list, Entity.create, etc.), every user auth call, every backend function invocation, every integration call. The SDK is closed-source and only works against base44.com.

What it looks like in code:

import { base44 } from "@base44/sdk";

const todos = await base44.entities.Todo.list({ user_id });
const me = await base44.User.me();
const result = await base44.functions.processPayment(payload);

Escape cost. Every SDK call site needs to be replaced with your new stack's equivalent. For a typical app:

  • 50–200 entity call sites.
  • 5–20 auth call sites.
  • 10–50 backend function calls (these mostly become direct fetch to your new backend).
  • 5–30 integration calls.

The replacements are mechanical but extensive. Sed/regex won't do it cleanly because the new stack's API doesn't map 1:1.

The pattern that helps. If you are still on Base44 and might leave eventually, wrap the SDK in a thin internal module today:

// src/lib/data.ts
import { base44 } from "@base44/sdk";

export const data = {
  todos: {
    list: (filter: TodoFilter) => base44.entities.Todo.list(filter),
    create: (todo: TodoInput) => base44.entities.Todo.create(todo),
    update: (id: string, patch: Partial<Todo>) => base44.entities.Todo.update(id, patch),
  },
  users: {
    me: () => base44.User.me(),
  },
};

Now your components import data.todos.list instead of base44.entities.Todo.list. When you migrate, you change one file. We have seen this single pattern cut migration time by 30–40%.

Realistic estimate to fully replace: 30–80 hours for a small app, 100–250 hours for a midsize app.

Binding 2: the entity layer (data)

What's locked. Your data lives in Base44's managed Postgres, but you do not have direct SQL access. Schemas are defined through the IDE. There is no pg_dump equivalent. Migration requires reading every record through the SDK and writing it to your new database.

What you can take.

  • Record data, via Entity.list() with pagination.
  • Field types, by inspection of the schema in the IDE.
  • Created/updated timestamps.
  • File URLs (but the files themselves live in Base44 storage, see binding 4).

What you cannot take.

  • Indexes the platform set up for you.
  • RLS rules (you must rebuild them in your new stack).
  • Stored procedures or triggers (Base44 does not expose these).
  • The exact column types — Postgres types and Base44 types don't always align cleanly.

The migration mechanics. A backend function that exports each entity to JSONL, then a script in your new environment that imports JSONL into your target schema:

// Export side (Base44 backend function)
export default async function handler(req: Request) {
  const PAGE_SIZE = 1000;
  let cursor: string | null = null;
  const results = [];

  while (true) {
    const filter: Record<string, unknown> = {};
    if (cursor) filter.created_date = { $gt: cursor };
    const batch = await base44.entities.Todo.list(filter, "created_date", PAGE_SIZE);
    if (batch.length === 0) break;
    results.push(...batch);
    cursor = batch[batch.length - 1].created_date;
  }

  return new Response(JSON.stringify(results), { status: 200 });
}
// Import side (Supabase, run from a script with service-role key)
import { createClient } from "@supabase/supabase-js";

const supabase = createClient(URL, SERVICE_ROLE_KEY);
const records = await fetchExportFromBase44();

const BATCH = 500;
for (let i = 0; i < records.length; i += BATCH) {
  const slice = records.slice(i, i + BATCH);
  const { error } = await supabase.from("todos").insert(slice);
  if (error) throw error;
}

Realistic estimate. 20–80 hours for a small app, 100–300 hours for a midsize app, including schema design, validation, and verification that record counts match.

Binding 3: integrations

What's locked. When you use base44.integrations.invokeLLM, sendEmail, generateImage, you are using credentials managed by the platform. You don't have an OpenAI API key; Base44 does. Same for the email sender, the image model, etc.

Escape cost. You sign up for the underlying providers directly, get your own keys, and replace every integration call with a direct API call from a backend function.

// Was:
const response = await base44.integrations.invokeLLM({ prompt });

// Becomes:
const openai = new OpenAI({ apiKey: Deno.env.get("OPENAI_API_KEY") });
const completion = await openai.chat.completions.create({
  model: "gpt-4o-mini",
  messages: [{ role: "user", content: prompt }],
});
const response = completion.choices[0].message.content;

Cost implication. Direct provider rates are sometimes cheaper than Base44's credit equivalent (you skip the platform markup), sometimes more expensive (you lose volume discounts the platform negotiates). Run the math before assuming either.

Realistic estimate. 10–40 hours for a typical app. Mostly straightforward; the gotchas are in error handling and rate limiting that the platform's wrapper hid.

Binding 4: rendering and runtime

What's locked. The Base44 IDE generates a React app that runs inside a Base44-hosted shell. The shell handles auth state, layout chrome, and platform integration UI. Custom domains are supported on Pro tier and above.

Escape cost. The React component tree itself is portable. The shell, the build pipeline, and the deployment infrastructure are not.

For a Next.js destination, the migration is:

  1. Export the React app from Base44.
  2. Set up a Next.js project with App Router.
  3. Drop the exported components into the Next.js routing structure.
  4. Replace the Base44 shell layout with Next.js layout.tsx files.
  5. Move backend function logic into Next.js API routes or Server Actions.
  6. Replace Base44's environment variable access with Next.js's process.env.
  7. Set up your CDN and deployment.

File storage migration. Files uploaded to Base44 storage have URLs at base44.app. After migration, those URLs still work (for now), but you should re-host the files at your own bucket so the platform can't yank them later. A backend function downloads each file and re-uploads to S3/R2.

Realistic estimate. 40–120 hours for a small app, 150–400 hours for a midsize app, depending on how much business logic the agent inlined into components vs. abstracted out.

Binding 5: identity

What's locked. Users authenticated to Base44 hold tokens issued by Base44's identity service. You do not have access to the password hashes or to the OAuth refresh tokens.

Escape cost. This is the trickiest binding. You cannot migrate sessions; users will need to re-authenticate after migration. For OAuth users (Google), they re-link their Google account to your new Auth0/Clerk/Supabase Auth identity. For email/password users, you have two options:

  1. Force password reset. Email every user a reset link, they set a new password against your new identity service. Simple, but it is a friction event for users.
  2. Lazy migration. When a user logs in for the first time after the migration, prompt them to set a new password (their old one no longer works). Spreads the friction over time.

For SSO users, you reconnect SSO at the IdP level.

Realistic estimate. 20–60 hours including communications, plus a few weeks of elevated support load.

Total realistic migration cost

Adding up the bindings for a midsize SaaS app (50+ entities, multi-tenant, 3–5 integrations, 1,000–10,000 users):

BindingHours
SDK replacement100–250
Data migration100–300
Integrations10–40
Rendering/runtime150–400
Identity20–60
Testing, QA, cutover50–120
Total430–1,170 hours

At $150/hour agency rate, that's roughly $65,000–175,000 for a full migration of a midsize app. At an internal team rate of $100/hour effective cost, $43,000–117,000. These are real numbers from real engagements.

For smaller apps, divide by 3–5x. For larger apps with custom integrations, multiply by 2x.

What you do not save when you leave

A common assumption: "we'll save the Base44 subscription." That's true. The cash savings are real. But you take on:

  • Hosting costs (Vercel, AWS, etc.) — typically $50–500/month for an equivalent app.
  • Database costs (Supabase, RDS) — $25–250/month.
  • Third-party services you used to get bundled — email, image gen, monitoring — $100–400/month.
  • Engineering ownership of the stack you now run.

The cost delta in cash is usually positive (you save money), but the operational cost delta in engineering attention is more nuanced. You trade "fight the platform's quirks" for "own the platform yourself." Which is better depends on your team.

When migration is the right call

We see five clear signals that migration pays for itself:

  1. Spending more than $1,500/month on Base44 for a single app. Migration payback is typically under 24 months.
  2. Regulatory requirements the platform cannot meet (HIPAA, SOC 2 for customers).
  3. Performance ceilings — you've optimized everything and INP is still 400ms+.
  4. A planned multi-region rollout — Base44's single-region hosting won't scale.
  5. Team friction with the AI agent — you've moved to the code editor for everything anyway, and the agent is no longer adding value.

If three or more apply, migrate. If one or two, run the math and the is base44 production ready framework.

When migration is the wrong call

Equally clear signals to stay:

  1. You are pre-product-market-fit. Migration time competes with finding-customers time, and customers always win.
  2. Your app is not the bottleneck. If the platform is fine and the bottleneck is sales or distribution, leave it alone.
  3. You have a clear ceiling on the app's scope. Internal tools, single-customer apps, and 50-user dashboards are fine to leave on Base44 indefinitely.
  4. You have not yet hardened the existing app. Migration of an unhardened app is harder than migration of a hardened one. Harden first.

Common lock-in mistakes

Treating "we'll just export the code" as a migration plan. Export is one of fifteen steps. The rest is the work.

Underestimating the SDK replacement. Counting call sites and assuming linear effort. Reality is 1.5–2x the linear estimate because of edge cases.

Skipping the data validation pass. Migrating data without a record-count and field-value verification is how you discover data loss six weeks later.

Cutting over without a fallback. Run dual-stack for at least a week. Be ready to revert.

Ignoring identity migration. Users having to reset passwords is annoying. Plan the communication and support load explicitly.

Forgetting external integrations. Webhook URLs change. Update every external system that points at your old Base44 webhook.

Lock-in mitigation if you stay

If you decide to stay on Base44 but want to reduce lock-in over time:

  1. Wrap the SDK in a project-local module (the data.ts pattern above).
  2. Use direct API calls for integrations, not platform-managed wrappers, where possible.
  3. Mirror your data to an external store as a backup and to enable optionality later.
  4. Keep your auth flows portable — use Auth0 or Clerk via a backend function rather than Base44's native auth.
  5. Minimize unique-to-Base44 features in your codebase. Anything you can do generically, do generically.

These add some upfront cost but cut migration cost dramatically if you ever exercise the option.

Want us to scope a migration for you?

Our $497 audit produces a written migration plan with phased estimates, identified risks, and a recommended target stack. If you proceed with us, we discount the audit fee against the migration engagement. Order an audit or book a free 15-minute call to discuss the migration roadmap.

QUERIES

Frequently asked questions

Q.01Can I export my Base44 app and run it elsewhere without changes?
A.01

No. The export gives you the React frontend code, but it still imports @base44/sdk, which only works against base44.com. Running independently requires replacing every SDK call (entities, auth, integrations, files) with your new stack's equivalent. The frontend tree is portable; the SDK boundary is not. Estimate one to three weeks of engineering work for a small app, two to four months for a midsize app, plus the data migration.

Q.02What's actually portable from a Base44 app?
A.02

Portable: React components, page structure, business logic that doesn't call the SDK, design assets, content. Semi-portable: entity schemas (you can recreate them in Postgres but the column types and constraints don't translate 1:1), backend function logic (Deno code, but with platform-specific imports). Not portable: SDK calls, platform-managed integrations, auth tokens, file storage URLs, custom domain TLS. The portable percentage by code volume is typically 40–60% of a typical app's source.

Q.03Why is the SDK considered the main lock-in?
A.03

Because the SDK is everywhere. A typical Base44 app has 50–500 SDK call sites scattered across components and backend functions. Each one is a binding to base44.com. There is no abstraction layer between your app and the SDK; the agent emits direct calls. To leave, you replace every call with your new stack's equivalent (Supabase, Firebase, custom API). The SDK is also closed-source, so you cannot run it independently or stub it out — you must replace it.

Q.04Can I migrate the data without migrating the app?
A.04

Partly. You can dual-write: keep Base44 as the primary data store, and replicate writes to Postgres or Supabase in parallel. This gives you a copy of the data outside the platform without affecting the running app. It does not solve the SDK lock-in for reads, but it gives you a recovery point if Base44 has an outage. We recommend this pattern as a migration de-risking step even if you have no current plan to leave.

Q.05How much does a full migration cost in 2026?
A.05

For a small app (10–20 entities, basic auth, 1–2 integrations): roughly $6,000–12,000 in agency rates, or 80–160 engineering hours. For a midsize app (50+ entities, multi-tenant, 3–5 integrations): $12,000–25,000, or 200–400 hours. For a complex app with custom integrations and significant business logic: $25,000–60,000, or 400–800 hours. The bulk of the cost is data migration and SDK replacement; the React frontend port is the cheap part.

Q.06What's the lowest-risk migration target from Base44?
A.06

Next.js + Supabase, by a wide margin in our experience. The reasons: Supabase's data model is close enough to Base44's entity model that the migration is mechanical, not architectural. Postgres-backed Supabase gives you SQL, transactions, RLS, and proper indexing. Next.js handles the rendering. The combined stack is at least order-of-magnitude more flexible than Base44 with no significant cost increase at small scale. We have a step-by-step playbook in [Base44 to Next.js + Supabase migration](/migrate/base44-to-nextjs-supabase).

NEXT STEP

Need engineers who actually know base44?

Book a free 15-minute call or order a $497 audit.