---
title: "Adopt an existing app"
description: "Bring a Lovable, Bolt, v0 or Cursor app onto MainSDK with mainsdk check and mainsdk adopt, one module and one pull request at a time, no rewrite."
section: "getting-started"
status: "Building for 0.5"
spec: "migration-skill"
canonical: "https://mainsdk.dev/docs/getting-started/existing-app"
updated: "2026-10-28"
---

# Adopt an existing app

> Bring a Lovable, Bolt, v0 or Cursor app onto MainSDK with mainsdk check and mainsdk adopt, one module and one pull request at a time, no rewrite.

Status: Building for 0.5 · Canonical: https://mainsdk.dev/docs/getting-started/existing-app · Updated: 2026-10-28

The quickstart started from an empty folder. Most apps already exist, and you don't rewrite yours to use MainSDK: you check it, see the gaps, lock what works, and close the gaps one pull request at a time. Your coding agent can do the work through the migration skill, or you can run `mainsdk adopt` yourself.

Phase 1 covers Next.js and Node apps, including those generated by Lovable, Bolt and v0. Other stacks are reported as unsupported, never half-migrated. MainSDK is pre-release; these commands are the planned design and do not run yet. `init`, `check` and the framework adapters are planned for 0.2; `mainsdk adopt` and the migration skill are planned for 0.5.

## Start with a check

Run it in the app's root. No account, nothing sent anywhere.

```bash
npx mainsdk check
```

On a typical generated app, the first run finds things like a payment key in client code or a raw database client:

```text
$ npx mainsdk check
mainsdk check · my-lovable-app · env dev · Main 27
✗ secrets    1 finding
  MAIN-SECRET-0002  critical  src/lib/stripe.ts:4
  fix: Move the key to secrets and use secret:STRIPE_SECRET_KEY
✗ data       1 finding
  MAIN-DATA-0001  high  src/lib/db.ts:12
  fix: Route queries through MainSDK (withPrisma, withDrizzle or db.<model>.for(user))
✓ config  ✓ network
2 gates failed · exit 1
```

## Adopt, step by step

Plain `npx mainsdk adopt` runs the next step each time and is safe to re-run. The steps below run each one by name. Progress is kept in `.mainsdk/adopt.json` (git-ignored); `main.yaml` stays the source of truth.

### 1. Scan

```bash
npx mainsdk adopt scan
```

A deterministic scan maps sign-in, data access, secrets and outbound calls, and writes a `main.yaml` describing the app as it is. It changes no code; the same repo always gives the same file.

It keeps what you already run. An app on Clerk and OpenFGA stays on them:

```yaml title="main.yaml (written by adopt scan)"
schema: 1
project: prj_01JC8Q4W7ZK3M5N8P2R6T9V0XY
baseline: main27
auth: { driver: clerk }      # byo-identity: users, sessions and MFA stay in Clerk
access: { driver: openfga }  # byo-policy: your model and tuples stay in place
pay: { driver: stripe }
overlays: { order: [market, segment, env] }
exceptions: []
```

### 2. Report

```bash
npx mainsdk adopt report
```

A plain-language gap report against Main 27, ordered by risk: secrets first, then access, then data, then the rest. Each item names the rule and the fix. Add `--json` for tools.

### 3. Lock key flows

```bash
npx mainsdk adopt lock
```

Records the app's key flows, such as sign-in and checkout, as locked flows before anything changes. `adopt next` refuses to run until they exist (`MAIN-ADOPT-0001 lock flows first`), so migration can't silently change what your users see.

### 4. Migrate one module per pull request

```bash
npx mainsdk adopt next --module secrets
```

Each step is one branch and one pull request, limited to one module, that must pass `mainsdk check` and every locked flow. If a step breaks a locked flow it's marked failed, the branch is kept for review, and your main branch is untouched.

A secrets step, before and after:

```ts title="src/lib/stripe.ts (before)"
import Stripe from "stripe";
export const stripe = new Stripe("sk_live_…");
```

```ts title="src/lib/checkout.ts (after)"
import { pay } from "mainsdk";

export function checkout(orderId: string, amountInCents: number) {
  return pay.checkout({ order: orderId, amount: amountInCents, currency: "USD",
    successUrl: "/orders/done", cancelUrl: "/cart" });
}
```

Code that can't move to an interface yet stays behind that interface's escape hatch, `raw()`, and `check` lists every use.

### 5. Finish

```bash
npx mainsdk adopt finish
```

Produces the launch report: the app meets Main 27, or the report lists exactly what remains, with file and line.

## Hono, Express and Node

If your app is a Hono or Express server rather than Next.js, three commands put it under the check:

```bash
npx mainsdk init
```

```ts title="src/server.ts"
import express from "express";
import { mainsdk } from "mainsdk/express";   // Hono: import { mainsdk } from "mainsdk/hono"; app.use("*", mainsdk())

const app = express();
app.use(mainsdk());
// … your routes
app.use(mainsdk.errors());   // last
```

```bash
npx mainsdk check
```

The adapters give every request a trace, its user and market context, and errors as problem details (see [installation](https://mainsdk.dev/docs/getting-started/installation)). What is and isn't specified for adopting these apps:

- The adapters for Hono, Express and Node workers, and `withPrisma` and `withDrizzle` for the database, are specified for 0.2.
- The adopt steps are scoped to "Next.js and Node apps". Hono and Express servers are Node apps, but the migration spec doesn't name them or say that `adopt scan` recognises their routes: [TBD].
- Until that is settled, wire the adapter and run `check` yourself, and use `adopt` for Next.js apps.

## Let your agent do it

The migration skill runs the same five steps through the MainSDK MCP server (`adopt.scan`, `adopt.report`, `adopt.lock`, `adopt.plan_module`, `adopt.verify_module`, `adopt.finish`). It works in Claude Code, Cursor and any MCP-capable agent, and intent checks run on your own agent and keys.

```text
Bring this app onto MainSDK with the mainsdk-adopt skill. Start with secrets.
```

See [Use MainSDK with your coding agent](https://mainsdk.dev/docs/getting-started/with-your-agent).

> **Note:** `mainsdk migrate <from>` with guides and codemods for Supabase, Firebase, Clerk, Auth0, Auth.js, Better Auth and Stripe direct arrives in phase 2. Adopting across many repos at once is also phase 2.

## Next

- [Migrate from raw provider SDKs](https://mainsdk.dev/docs/guides/migrate-from-raw-providers)
- [Interfaces and drivers](https://mainsdk.dev/docs/concepts/interfaces-and-drivers)
- [Main 27 and the Main mark](https://mainsdk.dev/docs/concepts/main27)
