Skip to content

Upgrade to SvelteKit 3 and Skeleton 5

@auth/svelte 0.11 moves the SvelteKit components to SvelteKit 3 and Skeleton 5, and @auth/nextjs 0.3 moves the Next.js components to Skeleton 5. Both releases also add the admin dashboard and redesign the emails, and the root layout now needs the admin items. This guide updates an app that installed an earlier version. New apps follow SvelteKit or Next.js instead.

Commit or stash your work first. jsrepo shows a diff for every file it changes, and Git lets you compare the result with your own edits.

Changes in both frameworks

ChangeWhat it means for the upgrade
The root layout (base) mounts ImpersonationBannerbase now depends on admin/lib, which depends on admin/convex, so you add the admin items. The dashboard stays off until you set admin: true.
The generated Better Auth schema moved to src/convex/betterAuth/generatedSchema.ts and gained the admin plugin’s fieldssrc/convex/betterAuth/schema.ts builds on it and adds the search indexes the dashboard uses. To regenerate the schema, run npx auth generate --output generatedSchema.ts in src/convex/betterAuth.
The emails take the brand from brandName and brandTagline in auth.constants.tsThe BRAND_NAME and BRAND_TAGLINE environment variables are no longer read. BRAND_LOGO_URL stays an environment variable.
auth.ts (config) registers the admin plugin, turns off session refresh inside Convex queries, and deletes a user’s API keys and organization logos with the userIt calls the new betterAuth/user.ts (users/convex) and betterAuth/organization.ts (organizations/convex), so update all three together.
The emails are redesignedThe email-change message goes to the current address and asks the user to confirm the change. The magic-link subject names the brand.
requestDeviceCode (device-authorization/convex) takes an optional scope and no longer asks for read:orgs read:themesA device client that relied on that scope in the token response passes it itself.
In the organization members list, owners and admins can change and remove other admins on small screens too, as on large screens and on the serverNothing to do; it comes with organizations/lib.

When jsrepo update config shows the diff for src/convex/auth.constants.ts, keep your own file. It holds your feature flags.

SvelteKit (@auth/svelte 0.11)

1. Upgrade the app

Run the SvelteKit 3 migration in your app:

It moves the kit options from svelte.config.js into sveltekit() in vite.config.ts, adds #lib to the imports in package.json, and rewrites every $lib to #lib, including the one in jsrepo.config.ts. The SvelteKit migration guide covers what it can’t do for you.

2. Point jsrepo at src/lib

After the migration, paths.lib in jsrepo.config.ts reads '#lib'. Set it to the folder itself:

jsrepo.config.ts

jsrepo finds aliases such as $lib or #lib through the paths in tsconfig.json, which SvelteKit 3 no longer generates. With an alias left in place, jsrepo update writes the components into a new folder named #lib at the project root and leaves src/lib unchanged. With ./src/lib, jsrepo rewrites the components’ #lib/... imports to relative paths.

3. Map the Convex imports

The components now import your Convex code through #convex/... instead of $convex/.... Add the mapping to package.json:

package.json

Replace $convex/ with #convex/ in your own imports, then delete the alias that sv migrate moved into sveltekit() in vite.config.ts. SvelteKit 3 deprecates alias.

4. Upgrade Skeleton

Install @skeletonlabs/skeleton 5. If you edited the auth theme or added your own theme, migrate it:

Skeleton 5 renames the theme tokens, for example to --typo-* and --color-root-bg-*. The updated auth theme uses the new names.

5. Add the admin items

admin/routes adds the /admin page. Leave it out if you don’t want the dashboard; base needs only admin/lib and admin/convex.

6. Update the Auth UI files

These files in base may already exist in your app. Merge their diffs instead of accepting them:

  • src/env.ts declares PUBLIC_CONVEX_URL and PUBLIC_CONVEX_SITE_URL. SvelteKit 3 only exposes environment variables declared in this file, so keep your own declarations next to these two.
  • src/hooks.ts calls initConvex(PUBLIC_CONVEX_URL). The components read the Convex URL from there, so keep this call next to your own hooks such as reroute or transport.
  • vite.config.ts adds the Tailwind and SvelteKit plugins Auth UI needs. Keep your own plugins, adapter and sveltekit() options.

The components follow Skeleton 5’s defaults, so badges render as bold pills and preset-tonal buttons turn neutral.

7. Move the brand variables

If you set BRAND_NAME or BRAND_TAGLINE in Convex, follow Move the brand variables below.

8. Check the app

Keep npx convex dev running so it deploys the new functions and schema, then run:

If check reports Cannot find module '#convex/...', the mapping from step 3 is missing. Then start the app and sign in once to confirm the session still loads. If pages fail with Convex URL not set, src/hooks.ts is missing the initConvex() call.

Next.js (@auth/nextjs 0.3)

1. Upgrade Skeleton

Install @skeletonlabs/skeleton 5. If you edited the auth theme or added your own theme, migrate it:

The registry is built against Next.js 16.4, React 19.3, Convex 1.46 and @convex-dev/better-auth 0.12.5. Upgrade your app if it’s on older versions.

2. Add the admin items

admin/routes adds the /admin page. Leave it out if you don’t want the dashboard; base needs only admin/lib and admin/convex.

3. Update the Auth UI files

In base, src/app/layout.tsx changed: it now mounts ImpersonationBanner. If you edited your layout, merge that diff instead of accepting it. next.config.mjs no longer sets turbopack.root, and base now installs @tailwindcss/postcss itself.

The device approval page moved from /device-authorization/[code] to /device?user_code=<code>, the URL Better Auth sends users to. Delete src/app/device-authorization after the update.

The components follow Skeleton 5’s defaults, so badges render as bold pills and preset-tonal buttons turn neutral. Slack and Salesforce icons now ship as local components in primitives/ui/brand-icons, because Simple Icons removed them.

4. Move the brand variables

If you set BRAND_NAME or BRAND_TAGLINE in Convex, follow Move the brand variables below.

5. Check the app

Keep npx convex dev running so it deploys the new functions and schema, then run:

Then start the app and sign in once to confirm the session still loads.

Move the brand variables

Put the values in auth.constants.ts:

src/convex/auth.constants.ts

Then remove the variables from each deployment that has them:

Also remove them from the Environment Variable Defaults in your Convex project settings, if you put them there.

Turn on the admin dashboard

The upgrade installs the admin items but leaves the dashboard off. To use it, set admin: true in auth.constants.ts and give the first admin access through the ADMIN_USER_IDS Convex variable, a comma-separated list of Better Auth user ids:

That admin can promote others from /admin. The default layout doesn’t link to the dashboard; add the AdminButton component to your navigation if you want an entry point.