Vercel is the natural landing pad for an app that started on base44. Both lean React-first. Both prioritize fast deploys and zero-config hosting. The difference is that Vercel gives you an actual platform: previews, edge functions, environment variables that work, real CI, and a build log you can read.
This playbook covers the Vercel-specific work. If you have not picked a database yet, the Next.js + Supabase migration is the more opinionated path. Read this one if you already know your backend choice and want to focus on hosting and frontend cutover. If the destination is still open, the roundup of which alternative to move to prices Vercel against the other seven.
Why migrate to Vercel
Three reasons drive this migration:
- SSR and SEO you control. 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). What you do not control is that HTML: per-page meta descriptions are set by hand, and pages that depend on URL parameters do not get unique titles. Next.js on Vercel ships SSR or SSG by default, so every visitor and every crawler gets HTML you write. If your Base44 pages are missing from Google today, check the configuration causes first; the cause may be fixable without migrating.
- Real CI/CD. Vercel's preview deploys per pull request are a real productivity upgrade over base44's "publish" button. You see the diff. You share a URL with stakeholders. You revert atomically.
- Edge performance. Vercel's edge runtime puts your code in regions close to your users. Base44 runs out of one region. For global apps, latency can drop post-migration, no code change required.
You give up base44's AI agent, the in-browser editor, and the prompt-driven development loop. If those are your edge, this migration costs you that. If not, it pays back fast.
What you keep, what you rebuild
| Layer | What you keep | What you rebuild |
|---|---|---|
| React components | JSX, Tailwind, hooks | Anything calling @base44/sdk |
| Page routing | URL structure | Re-implement on Next.js App Router |
| Static assets | Images, fonts, files | Re-upload to Vercel public dir or your CDN |
| Environment variables | Names | Re-add via Vercel dashboard or CLI |
| Backend functions | Function bodies (mostly) | Wrap as Next.js Route Handlers |
| Database | Data | Schema + queries (depends on chosen DB) |
| Auth | User identifiers | Sessions (force re-issue) |
| Webhooks | Endpoint URLs (you must update senders) | Handler code |
| Scheduled tasks | None | Build with Vercel Cron or external scheduler |
| Domain + SSL | Domain | Reconfigure on Vercel (free SSL via Let's Encrypt) |
| Analytics | None | Vercel Analytics, Plausible, or Google Analytics |
The frontend ports cleanly. The backend layer between your React components and your data is what burns the time.
Architecture: source vs target
Base44 (current):
[browser] → CSR React (base44 hosted)
↓
@base44/sdk
↓
base44 backend (DB + Functions + Auth)
↓
single region, no SLA below Enterprise, opaque logs
Vercel + your backend (target):
[browser] → Next.js (SSR / RSC / Edge)
↓ ↓
app/api/* Route Handlers Edge Functions
↓ ↓
Supabase / Neon / PlanetScale / your DB
↓
multi-region, real logs, real CI
The shape changes from "client-side React calling a managed SDK" to "server-rendered React calling your own backend." That shift is what enables SSR, SEO, real-time, and proper observability.
Step-by-step migration plan
Phase 1 — Discovery (Week 1)
1. Export your base44 app
If you are on a paid plan, base44 supports GitHub export. The feature is still in beta and skips backend functions on some accounts. See our export code guide for the details.
# Once you have the export
git clone https://github.com/yourorg/your-base44-app.git
cd your-base44-app
npm install
npm run build # this will fail; the SDK won't connect from outside base44
You expect the build to fail or partially succeed. The point is to have the source code on disk.
2. Pick your backend stack
Decide before you start. Switching mid-migration throws away the data-layer work done so far.
| Backend | Best for | Trade-off |
|---|---|---|
| Supabase | Postgres + Auth + Storage + Realtime | Vendor lock-in to Supabase |
| Neon | Pure Postgres with branching | You build auth and storage yourself |
| PlanetScale | MySQL with branching | No Postgres features (RLS, pgvector) |
| MongoDB Atlas | Document data | Different query model than base44 |
| Self-hosted Postgres | Full control | You operate infra |
We default to Supabase unless the team has a strong reason otherwise.
3. Audit your SDK calls
grep -rn "base44\." src/ | tee migration/sdk-calls.txt
wc -l migration/sdk-calls.txt
This number is your effort estimate: every line is one replacement in step 8, and the count grows with the size of the app.
Phase 2 — Project setup (Week 1–2)
4. Stand up a clean Next.js project
Do not try to "convert" the export in place. Start a new Next.js project and port files into it.
npx create-next-app@latest my-app --typescript --tailwind --app --src-dir
cd my-app
npm install @vercel/analytics @vercel/speed-insights
Copy your component files (anything under src/components, src/pages from the export) into the new structure. Skip anything in the src/integrations/ folder if base44 generated one — those are SDK adapters you will replace.
5. Configure Vercel
npm install -g vercel
vercel link
vercel env pull .env.local
Set up production, preview, and development environments separately. Add your database URL, auth secrets, and third-party API keys.
6. Migrate routing to App Router
Base44's exported code uses React Router or its own routing layer. Convert to Next.js App Router conventions.
// before: src/pages/dashboard.tsx (React Router)
export default function Dashboard() {
const projects = useBase44(b => b.entities.Project.list());
return <ProjectList projects={projects} />;
}
// after: app/dashboard/page.tsx (Server Component)
import { createClient } from "@/lib/supabase/server";
export default async function DashboardPage() {
const supabase = createClient();
const { data: projects } = await supabase.from("projects").select("*");
return <ProjectList projects={projects ?? []} />;
}
The conversion is mostly mechanical. Server Components fetch data inline. Client Components keep React hooks.
Phase 3 — Backend rewrite (Weeks 2–4)
7. Port backend functions to Route Handlers
Each base44 backend function becomes one file under app/api/.
// app/api/create-invoice/route.ts
import { NextResponse } from "next/server";
import Stripe from "stripe";
import { createClient } from "@/lib/supabase/server";
export const runtime = "nodejs"; // or "edge" for Stripe webhooks
export async function POST(req: Request) {
const { project_id, amount } = await req.json();
const supabase = createClient();
const stripe = new Stripe(process.env.STRIPE_SECRET!);
const invoice = await stripe.invoices.create({ customer: "...", auto_advance: true });
await supabase.from("invoices").insert({ project_id, stripe_id: invoice.id, amount });
return NextResponse.json({ id: invoice.id });
}
Pick runtime = "edge" for fast, lightweight handlers. Use nodejs runtime for anything that needs the full Node API (file system, native modules, longer execution time).
8. Replace SDK calls in components
Mechanical work. For each base44.entities.X call:
// before
const tasks = await base44.entities.Task.filter({ projectId }, "-created_date");
// after (Server Component)
const { data: tasks } = await supabase
.from("tasks")
.select("*")
.eq("project_id", projectId)
.order("created_at", { ascending: false });
Do this in batches by route. Ship behind a feature flag (NEXT_PUBLIC_USE_NEW_BACKEND=true). Compare data parity before flipping.
9. Wire auth
Pick your auth provider. Supabase Auth, Clerk, NextAuth, and Auth.js all work cleanly on Vercel.
// middleware.ts (Supabase example)
import { createServerClient } from "@supabase/ssr";
import { NextResponse, type NextRequest } from "next/server";
export async function middleware(req: NextRequest) {
const res = NextResponse.next();
const supabase = createServerClient(/* ... */);
const { data: { session } } = await supabase.auth.getSession();
if (!session && req.nextUrl.pathname.startsWith("/dashboard")) {
return NextResponse.redirect(new URL("/login", req.url));
}
return res;
}
Force every existing user to reset their password via magic link. Base44 does not export password hashes.
Phase 4 — Cron and scheduled jobs (Week 4)
10. Configure Vercel Cron
// vercel.json
{
"crons": [
{ "path": "/api/cron/daily-digest", "schedule": "0 9 * * *" },
{ "path": "/api/cron/cleanup", "schedule": "0 3 * * *" }
]
}
// app/api/cron/daily-digest/route.ts
import { NextResponse } from "next/server";
export async function GET(req: Request) {
const auth = req.headers.get("authorization");
if (auth !== `Bearer ${process.env.CRON_SECRET}`) {
return NextResponse.json({ error: "unauthorized" }, { status: 401 });
}
// your job logic
return NextResponse.json({ ok: true });
}
Vercel Hobby caps cron at daily; Pro allows minute-level. For high-frequency jobs, layer Inngest or QStash on top.
Phase 5 — Deployment + cutover (Weeks 5–6)
11. Configure your domain on Vercel
Add the domain in Vercel's dashboard. Update DNS to point at cname.vercel-dns.com. Vercel issues SSL automatically. Keep base44's domain pointed at base44 until cutover is complete.
12. Dual-run window
Deploy your Vercel app on a staging subdomain (new.yourapp.com). Pipe a small percentage of traffic to it via your DNS or a reverse proxy. Monitor errors. Compare data writes between base44 and Vercel.
// during dual-run
async function createProject(payload) {
const [b44, vercel] = await Promise.allSettled([
base44.entities.Project.create(payload),
fetch("https://new.yourapp.com/api/projects", {
method: "POST",
body: JSON.stringify(payload),
}),
]);
if (b44.status === "rejected" || vercel.status === "rejected") {
await alertSlack("dual-write divergence", { b44, vercel });
}
return b44.value;
}
13. DNS cutover
When error rates and data parity look clean, swap DNS. Lower the TTL to 60 seconds twenty-four hours ahead of time. Then point the apex at Vercel. Total downtime: under five minutes if you do this on a Tuesday morning at 3am local time.
Phase 6 — Sunset (Weeks 6–8)
14. Read-only base44 + decommission
Lock the base44 app to read-only. Take a final export. Cancel the base44 plan after thirty days of stable production on Vercel.
Common pitfalls
1. Trying to deploy the export directly. It compiles, sometimes. It never runs against real data without an SDK rewrite. Plan to rewrite the data layer before deploying anything.
2. Edge runtime incompatibility. Some npm packages (Stripe SDK, certain database clients) do not run on Edge. Default to runtime = "nodejs" and only switch to edge for hot paths.
3. Environment variables forgotten. Base44 hides secrets in its own UI. Inventory every secret before cutover. Add them to Vercel for production, preview, and development separately.
4. Cron secret missing. Vercel Cron hits your endpoint with no built-in auth. Use a CRON_SECRET env var and check it in every cron route or anyone can hit /api/cron/* and trigger your jobs.
5. URL structure changes wipe SEO. If your URLs change shape from /app/dashboard to /dashboard, you lose Google's accumulated authority. Map every old URL to a new one and ship 301 redirects in next.config.js or vercel.json.
6. Webhook senders not updated. Stripe, Resend, GitHub, and any other webhook source still points at the old base44 URL. Update each one at the cutover moment, not before.
7. Vercel function size limits. Lambdas on Vercel have a 50MB compressed size limit. If your dependencies bloat past that, split into multiple smaller functions or move heavy compute to a separate service.
Timeline + team
Four to ten weeks with this team:
- One senior frontend engineer. Owns the export-to-Next.js port. Forty hours per week.
- One backend engineer (or the same person, if senior). Owns the data-layer rewrite. Twenty to forty hours per week.
- One ops/DNS person. Owns the cutover. Eight hours total over the project.
You can do it solo if you are a senior full-stack engineer and the app is small. Two engineers is the sweet spot for medium apps. Beyond that, parallelize by route.
Cost
Migration tiers from our practice:
| Tier | Price | What you get |
|---|---|---|
| Small | $6,000 | Up to 5 tables, 10 routes and single-role auth; data, users and uploaded files included; 2–3 weeks |
| Medium | $12,000 | Up 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 |
Every tier is fixed-price 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 four-to-ten-week range above is for a team doing the work in-house.
Vercel infrastructure: Vercel Pro at $20/user/mo. Database: $25–$100/mo depending on choice. Total ongoing cost: $50–$300/mo at small scale.
DIY cost is engineering time. Two senior engineers for six weeks is roughly $40,000–$60,000 in fully-loaded salary. Hiring the migration can cost less if you do not already have the team.
DIY vs hire decision
DIY this if:
- Your team has Next.js and your chosen backend on staff already.
- Your app has under thirty entities and standard auth.
- You can run a six-to-eight-week project without losing focus on other priorities.
Hire help if:
- You need to be live on the new stack in under six weeks.
- Your app has paying users and you cannot risk a botched cutover.
- Your team is base44-only and has never shipped a Next.js app to production.
- You tried the export, stared at the code, and realized you do not know where to start.
Want a free migration assessment?
Tell us what your app does and we will scope it. 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
Related migrations
- Base44 to Next.js + Supabase — the opinionated stack if you have not picked a backend yet.
- Base44 to self-hosted — full ownership, your own infrastructure.
- Base44 export code guide — how the export feature actually works.