0.10 and earlier
Breaking changes from 0.7 through 0.10 — locked secret fields, server-assigned roles, the passkey login client and more — with the steps for each.
Every release from 0.7 to 0.10 carried its own breaking change. Apply each section between your version and 0.11, oldest first. The CHANGELOG has the full detail.
0.10: secret fields are locked
Secret fields on the plugin's managed collections are locked by default (secureSecretFields on betterAuthCollections()). Session tokens, TOTP secrets and backup codes, verification values, stored OAuth tokens, hashed passwords and API keys, JWKS private keys and OAuth client secrets are no longer readable through Payload's REST/GraphQL API or the admin.
This only matters if you read them there, or through a Local API call that passes overrideAccess: false. Opt out with secureSecretFields: false, or unlock a model with an empty array. See Secret fields.
0.10 also fixed the plugin under a non-default routes.api; see Custom API route.
0.9: passkey client, roles, password changes
Passkey in the admin login. The default LoginView no longer imports @better-auth/passkey. On the auto-injected admin login, use the passkey wrapper (0.9.1+); see Passkeys. If you render LoginView yourself, pass an authClient:
import { createAuthClient, payloadAuthPlugins } from '@delmaredigital/payload-better-auth/client'
import { passkeyClient } from '@better-auth/passkey/client'
const authClient = createAuthClient({ plugins: [...payloadAuthPlugins, passkeyClient()] })
// <LoginView authClient={authClient} ... />Roles. If you stored multiple roles as a comma-separated string ("admin,editor"), switch the field to an array. A comma string is now a single role.
Password changes. canUpdateOwnFields denies updates that touch password fields. Move any change-password UI to authClient.changePassword({ currentPassword, newPassword }).
starts_with / ends_with are now anchored correctly. If you relied on the old, over-broad matching, adjust.
0.8: server-assigned roles, Node and peer ranges
Make role server-only. Set input: false on the role field in Better Auth:
user: { additionalFields: { role: { type: 'string', defaultValue: 'user', input: false } } }Set the default self-sign-up role on the collections plugin instead of the login view. LoginView's defaultSignUpRole is ignored:
betterAuthCollections({ firstUserAdmin: { defaultRole: 'user', adminRole: 'admin' } })Assign specific roles to non-first users from a trusted context (the Payload admin, a seed script, or your own access-gated hook), not the public sign-up endpoint.
Runtime. Node 18 support was dropped. Current releases require Node >=22.23.4.
API keys. Keys sent as x-api-key are scope-enforced. If you relied on such requests bypassing scope checks under allowSessionOrPermission, that no longer happens.
Two-factor schema. Regenerate collections and types if you use twoFactor, to pick up failedVerificationCount and lockedUntil.
0.7: client typing
payloadAuthPlugins and createPayloadAuthClient() are typed as BetterAuthClientPlugin[]. They work at runtime, but plugin methods aren't typed on the returned client. List plugins inline when you need them typed; see Client.

