MainSDK
Search⌘K
How-to

Migrate from Auth.js

Move Auth.js (NextAuth) sessions and adapters onto the MainSDK auth and db interfaces, with the codemod and a pull request.

Planned for 0.7

Status Status is where the work is: Planned (in a milestone, not started), Building (tickets in progress), Preview (usable, may change), then the stability it ships at.

Stability The promise an interface ships with.

  • Stable Follows semantic versioning; breaking changes need a new major, 12 months of overlap and a codemod.
  • Beta Usable in production; may change before it becomes stable.
  • Experimental May change or go away; needs an explicit opt-in in main.yaml.
Stability levels
Updated 2026-10-28

Move Auth.js (NextAuth) sessions and adapters onto the MainSDK auth and db interfaces, with the codemod and a pull request. Your Auth.js account stays; nothing here deletes it.

Before you start:

  • A git repository with a clean working tree. mainsdk migrate works on a branch and never touches yours.
  • Node 22 and npx mainsdk. No main.yaml yet? migrate writes one; or start with Adopt an existing app.
  • Your Auth.js keys stay where they are. Move them to secret: references when the driver is chosen (see Secrets).

1. Read the report

text
npx mainsdk migrate authjs --report-only

The report writes no file. It sorts every Auth.js call in your code into three lists: mapped (an interface call replaces it), raw (it stays behind raw(), with the reason) and needs a person (a policy, a rule file or a call with no interface). Add --json for a machine-readable report.

For the sample app of this guide (packages/cli/test/fixtures/migrate/authjs), the report finds 2 mapped, 0 raw and 1 for a person.

2. What the codemod changes

WhereBeforeAfter
app/api/auth/[...nextauth]/route.ts:4const handler = NextAuth({ providers: [GitHub] })auth.handlers()
app/dashboard/page.tsx:4const session = await getServerSession()auth.require(req)

Each rewrite is mechanical and one line at a time. Imports of Auth.js go when no call needs them, and mainsdk is added to package.json.

3. What stays behind raw()

  • Nothing in the sample stays behind raw().

A call behind raw() keeps working through the Auth.js host on your network allow list, and mainsdk check still sees it. Each one has a marker comment, // mainsdk migrate: ..., so you can find it later.

4. What needs a person

  • lib/db.ts:3: no interface call for PrismaAdapter; a person decides

The codemod leaves these lines alone and marks them. No tool should guess a policy.

5. Stateful moves are guided jobs

Data does not move with the code. Each stateful move is a job with steps and a rollback, listed in the pull request and never run by the codemod.

sessions-and-accounts: Move the user, account and session tables the adapter owns

  1. Read the adapter tables (User, Account, Session) with the same database connection.
  2. Copy users and linked accounts to the new auth driver; sessions are not copied, people sign in again.
  3. Switch for 1% of sign-ins, then all.

Rollback: Keep the adapter tables untouched; set auth.driver back to authjs.

6. Open the pull request

text
npx mainsdk migrate authjs

This records your sign-in and checkout flows as locked flows first, then creates the branch migrate/authjs, applies the codemods, adds .github/workflows/mainsdk-migrate.yml, runs mainsdk check and the locked flows, commits, pushes and opens one pull request with gh. If a gate fails, the branch is kept and no pull request opens (MAIN-MIGRATE-0001). --no-pr stops after the commit.

Locked flows run again in CI: npx mainsdk migrate flows.

Where you end

You end at the reference architecture mainsdk/saas-web: the same shape, with its tests, benchmark and chaos drills.

text
npx mainsdk init --template mainsdk/saas-web

Was this page helpful?

↑↓ moveEnter openEsc close

Not decided yet