Skip to content

Upgrading from 1.6 to 1.7.5 or newer

Upgrade directly to 1.7.5 or a later compatible 1.x release. The core account schema is unchanged from 1.6; no issuer column or identity backfill is needed.

Back up the database and rehearse on a copy with existing users, accounts, and sessions. Keep the same auth secret.

Resolve duplicate provider/account ID pairs using your configured table names. Never merge users by email alone.

These integrations need manual preparation. Follow the corresponding upstream instructions:

Integration Before deploying
Microsoft / Entra Pause sign-in and linking; map old subject IDs to verified object IDs or a trusted directory export.
Custom OAuth / SSO Map existing subjects to verified immutable provider IDs.
Legacy OIDC / MCP Convert client registrations and legacy token tables. Schema migrations do not copy these records.
SCIM Stop old provisioning and follow the reprovisioning procedure. D1 cannot support the new transaction requirements.
Device Authorization Resolve duplicate device/user codes; use bounded strings on MySQL and SQL Server.

Update the Alchemy Better Auth package to a release supporting 1.7.5, then align Better Auth and its synchronized plugins/adapters:

Terminal window
npx auth@1.7.5 upgrade

Use Node.js 22.12 or newer and the CLI version matching your target release. Review workspace catalogs and overrides.

The command updates dependencies, not application code or identity data.

For SQL layers with automatic migrations, the wrapper stays unchanged:

import { BetterAuth } from "@alchemy.run/better-auth";
export const makeAuth = BetterAuth({
emailAndPassword: { enabled: true },
});

After any manual preparation, deploy:

Terminal window
alchemy deploy

The schema is applied before the new host. Ordinary email/password accounts need no identity conversion when upgrading directly from 1.6.

Drizzle users own schema migrations. Generate and review the auth schema:

Terminal window
npx auth@1.7.5 generate --config ./auth.cli.ts

The CLI configuration exports an upstream Better Auth instance with the same plugins and schema options, using the Relations v2 adapter:

import { drizzleAdapter } from "@better-auth/drizzle-adapter/relations-v2";

Omit the adapter CLI flag, which selects the legacy generator:

npx auth@1.7.5 generate --config ./auth.cli.ts --adapter drizzle
npx auth@1.7.5 generate --config ./auth.cli.ts

Apply the schema through Drizzle’s migration tooling and include the generated auth relations when constructing the database. See the complete Drizzle configuration.

With automatic migrations disabled, apply your schema before deploying too.

Generic OAuth now uses the social APIs:

import { createAuthClient } from "better-auth/client";
import { genericOAuthClient } from "better-auth/client/plugins";
const authClient = createAuthClient({ plugins: [genericOAuthClient()] });
authClient.signIn.social({ provider: "my-provider" });
authClient.linkSocial({ provider: "my-provider" });

Update registered callback URLs:

/api/auth/oauth2/callback/:id
/api/auth/callback/:id

Token/profile operations select a local account row, rather than a provider:

{ accountId: "local-account-row-id" }
// Or select the account from its cookie:
{ useAccountCookie: true }

Move joins into the database options:

experimental: { joins: true }
advanced: { database: { joins: true } }

Custom secondary storage needs atomic operations:

increment(key, ttl)
getAndDelete(key)

The TTL is required, in seconds; subsequent increments must preserve the original expiration. Custom rate-limit storage now uses an atomic consume operation instead of separate reads and writes.

Check the upstream guide for SSO, MCP, mobile, and proxy changes.

Test an existing session, existing-user sign-in, new-user sign-up, and sign-out. Exercise every configured provider and account link/list/refresh/unlink flow.

Confirm user IDs are preserved and no duplicate users appear.

Deploy again to confirm the migration is a no-op:

Terminal window
alchemy deploy