diff --git a/.changeset/twenty-snakes-smile.md b/.changeset/twenty-snakes-smile.md
new file mode 100644
index 00000000000..a845151cc84
--- /dev/null
+++ b/.changeset/twenty-snakes-smile.md
@@ -0,0 +1,2 @@
+---
+---
diff --git a/packages/upgrade/src/versions/core-3/changes/after-switch-organization-url-removed.md b/packages/upgrade/src/versions/core-3/changes/after-switch-organization-url-removed.md
new file mode 100644
index 00000000000..fe52255587c
--- /dev/null
+++ b/packages/upgrade/src/versions/core-3/changes/after-switch-organization-url-removed.md
@@ -0,0 +1,14 @@
+---
+title: '`afterSwitchOrganizationUrl` removed from `OrganizationSwitcher`'
+matcher: 'afterSwitchOrganizationUrl'
+category: 'deprecation-removal'
+---
+
+The `afterSwitchOrganizationUrl` prop has been removed from `OrganizationSwitcher`. Use `afterSelectOrganizationUrl` instead:
+
+```diff
+
+```
diff --git a/packages/upgrade/src/versions/core-3/changes/appearance-layout-to-options.md b/packages/upgrade/src/versions/core-3/changes/appearance-layout-to-options.md
new file mode 100644
index 00000000000..6e850dbeb54
--- /dev/null
+++ b/packages/upgrade/src/versions/core-3/changes/appearance-layout-to-options.md
@@ -0,0 +1,20 @@
+---
+title: '`appearance.layout` renamed to `appearance.options`'
+matcher: 'appearance[\\s\\S]*?\\.layout'
+matcherFlags: 'm'
+category: 'breaking'
+---
+
+The `appearance.layout` property has been renamed to `appearance.options`. Update all instances in your codebase:
+
+```diff
+
+```
diff --git a/packages/upgrade/src/versions/core-3/changes/billing-props-removed.md b/packages/upgrade/src/versions/core-3/changes/billing-props-removed.md
new file mode 100644
index 00000000000..39f591cd421
--- /dev/null
+++ b/packages/upgrade/src/versions/core-3/changes/billing-props-removed.md
@@ -0,0 +1,14 @@
+---
+title: 'Unstable billing props removed'
+matcher:
+ - '__unstable_manageBillingUrl'
+ - '__unstable_manageBillingLabel'
+ - '__unstable_manageBillingMembersLimit'
+category: 'deprecation-removal'
+---
+
+The following unstable properties have been removed. If you were relying on these, please reach out to support.
+
+- `__unstable_manageBillingUrl`
+- `__unstable_manageBillingLabel`
+- `__unstable_manageBillingMembersLimit`
diff --git a/packages/upgrade/src/versions/core-3/changes/checkout-api-changed.md b/packages/upgrade/src/versions/core-3/changes/checkout-api-changed.md
new file mode 100644
index 00000000000..1db1aceebf8
--- /dev/null
+++ b/packages/upgrade/src/versions/core-3/changes/checkout-api-changed.md
@@ -0,0 +1,35 @@
+---
+title: '`useCheckout` and `Clerk.checkout()` return value changed'
+matcher:
+ - 'useCheckout'
+ - 'Clerk\\.checkout'
+ - '\.checkout\('
+category: 'breaking'
+---
+
+The return values of `useCheckout` hook and `Clerk.checkout()` have been updated.
+
+### React Hook
+
+```diff
+- const { id, plan, status, start, confirm, paymentSource } = useCheckout({ planId: "xxx", planPeriod: "annual" });
++ const { checkout, errors, fetchStatus } = useCheckout({ planId: "xxx", planPeriod: "annual" });
++ // Access properties via checkout object
++ checkout.plan
++ checkout.status
++ checkout.start()
++ checkout.confirm()
+```
+
+### Vanilla JS
+
+```diff
+- const { getState, subscribe, confirm, start, clear, finalize } = Clerk.checkout({ planId: "xxx", planPeriod: "annual" });
+- getState().isStarting
+- getState().checkout
++ const { checkout, errors, fetchStatus } = Clerk.checkout({ planId: "xxx", planPeriod: "annual" });
++ checkout.plan
++ checkout.status
++ checkout.start()
++ checkout.confirm()
+```
diff --git a/packages/upgrade/src/versions/core-3/changes/clerk-types-deprecation.md b/packages/upgrade/src/versions/core-3/changes/clerk-types-deprecation.md
new file mode 100644
index 00000000000..25fad15101a
--- /dev/null
+++ b/packages/upgrade/src/versions/core-3/changes/clerk-types-deprecation.md
@@ -0,0 +1,17 @@
+---
+title: '`@clerk/types` deprecated in favor of `@clerk/shared/types`'
+matcher: "from\\s+['\"]@clerk/types['\"]"
+category: 'deprecation'
+warning: true
+---
+
+The `@clerk/types` package is deprecated. All type definitions have been consolidated into `@clerk/shared/types`.
+
+Update your imports:
+
+```diff
+- import type { ClerkResource, UserResource } from '@clerk/types';
++ import type { ClerkResource, UserResource } from '@clerk/shared/types';
+```
+
+The `@clerk/types` package will continue to re-export types from `@clerk/shared/types` for backward compatibility, but new types will only be added to `@clerk/shared/types`.
diff --git a/packages/upgrade/src/versions/core-3/changes/client-active-sessions-removed.md b/packages/upgrade/src/versions/core-3/changes/client-active-sessions-removed.md
new file mode 100644
index 00000000000..8604cd5eeb9
--- /dev/null
+++ b/packages/upgrade/src/versions/core-3/changes/client-active-sessions-removed.md
@@ -0,0 +1,12 @@
+---
+title: '`Client.activeSessions` removed'
+matcher: '\\.activeSessions'
+category: 'deprecation-removal'
+---
+
+The `activeSessions` property has been removed from the `Client` object. Use `sessions` instead:
+
+```diff
+- const sessions = client.activeSessions;
++ const sessions = client.sessions;
+```
diff --git a/packages/upgrade/src/versions/core-3/changes/color-ring-backdrop-opacity.md b/packages/upgrade/src/versions/core-3/changes/color-ring-backdrop-opacity.md
new file mode 100644
index 00000000000..fc9591626ce
--- /dev/null
+++ b/packages/upgrade/src/versions/core-3/changes/color-ring-backdrop-opacity.md
@@ -0,0 +1,21 @@
+---
+title: '`colorRing` and `colorModalBackdrop` now render at full opacity'
+matcher:
+ - 'colorRing'
+ - 'colorModalBackdrop'
+category: 'breaking'
+warning: true
+---
+
+The `colorRing` and `colorModalBackdrop` CSS variables now render at full opacity when modified via the appearance prop or CSS variables. Previously, provided colors were rendered at 15% opacity.
+
+If you were relying on the previous behavior, you may need to adjust your color values to include the desired opacity:
+
+```diff
+appearance={{
+ variables: {
+- colorRing: '#6366f1',
++ colorRing: 'rgba(99, 102, 241, 0.15)',
+ }
+}}
+```
diff --git a/packages/upgrade/src/versions/core-3/changes/deprecated-redirect-props-removed.md b/packages/upgrade/src/versions/core-3/changes/deprecated-redirect-props-removed.md
new file mode 100644
index 00000000000..b07e204336d
--- /dev/null
+++ b/packages/upgrade/src/versions/core-3/changes/deprecated-redirect-props-removed.md
@@ -0,0 +1,29 @@
+---
+title: 'Legacy redirect props removed'
+matcher:
+ - 'afterSignInUrl'
+ - 'afterSignUpUrl'
+ - 'afterSignOutUrl'
+ - 'redirectUrl'
+category: 'deprecation-removal'
+---
+
+The legacy redirect props `afterSignInUrl`, `afterSignUpUrl`, and `redirectUrl` have been removed from components. Use the newer redirect options:
+
+```diff
+
+```
+
+For forced redirects that ignore the `redirect_url` query parameter:
+
+```diff
+
+```
diff --git a/packages/upgrade/src/versions/core-3/changes/experimental-prefix-aligned.md b/packages/upgrade/src/versions/core-3/changes/experimental-prefix-aligned.md
new file mode 100644
index 00000000000..e895308c086
--- /dev/null
+++ b/packages/upgrade/src/versions/core-3/changes/experimental-prefix-aligned.md
@@ -0,0 +1,17 @@
+---
+title: 'Experimental method prefix standardized to `__experimental_`'
+matcher:
+ - 'experimental__'
+ - 'experimental_'
+category: 'breaking'
+---
+
+All experimental methods now use the `__experimental_` prefix consistently. Update any references:
+
+```diff
+- experimental__someMethod
++ __experimental_someMethod
+
+- experimental_someMethod
++ __experimental_someMethod
+```
diff --git a/packages/upgrade/src/versions/core-3/changes/expo-min-version.md b/packages/upgrade/src/versions/core-3/changes/expo-min-version.md
new file mode 100644
index 00000000000..55b8ad93629
--- /dev/null
+++ b/packages/upgrade/src/versions/core-3/changes/expo-min-version.md
@@ -0,0 +1,24 @@
+---
+title: 'Minimum Expo version increased to 53'
+packages: ['expo']
+matcher: "expo\":\\s*\"(?:^|~|>|=|\\s)*(?:50|51|52)\\..*?"
+matcherFlags: 'm'
+category: 'version'
+---
+
+Support for Expo 50, 51, and 52 has been dropped. Update your project to Expo 53 or later:
+
+```diff
+{
+ "dependencies": {
+- "expo": "~52.0.0",
++ "expo": "~53.0.0",
+ }
+}
+```
+
+Run the Expo upgrade command:
+
+```bash
+npx expo install expo@latest
+```
diff --git a/packages/upgrade/src/versions/core-3/changes/hide-slug-removed.md b/packages/upgrade/src/versions/core-3/changes/hide-slug-removed.md
new file mode 100644
index 00000000000..e3f0718d934
--- /dev/null
+++ b/packages/upgrade/src/versions/core-3/changes/hide-slug-removed.md
@@ -0,0 +1,15 @@
+---
+title: '`hideSlug` prop removed'
+matcher: 'hideSlug'
+category: 'deprecation-removal'
+---
+
+The `hideSlug` prop has been removed. Organization slugs are now managed through the Clerk Dashboard under Organization Settings.
+
+```diff
+
+```
+
+To hide organization slugs, update your settings in the Clerk Dashboard → Organization Settings → Slug.
diff --git a/packages/upgrade/src/versions/core-3/changes/min-node-version.md b/packages/upgrade/src/versions/core-3/changes/min-node-version.md
new file mode 100644
index 00000000000..d99762422d7
--- /dev/null
+++ b/packages/upgrade/src/versions/core-3/changes/min-node-version.md
@@ -0,0 +1,17 @@
+---
+title: 'Upgrade Node.js to v20.9.0 or higher'
+category: 'version'
+matcher: "engines\":\\s*{[\\s\\S]*?\"node\":\\s*\"(?:^|~|>|=|\\s)*(?:14|16|18)\\..*?"
+matcherFlags: 'm'
+---
+
+All Clerk packages now require Node.js 20.9.0 or later. Update your Node.js version and ensure your `package.json` engines field reflects this requirement.
+
+```diff
+{
+ "engines": {
+- "node": ">=18.0.0"
++ "node": ">=20.9.0"
+ }
+}
+```
diff --git a/packages/upgrade/src/versions/core-3/changes/nextjs-encryption-key-required.md b/packages/upgrade/src/versions/core-3/changes/nextjs-encryption-key-required.md
new file mode 100644
index 00000000000..4cf72d7087e
--- /dev/null
+++ b/packages/upgrade/src/versions/core-3/changes/nextjs-encryption-key-required.md
@@ -0,0 +1,17 @@
+---
+title: 'Encryption key required when passing `secretKey` at runtime'
+packages: ['nextjs']
+matcher: 'clerkMiddleware\([\\s\\S]*?secretKey'
+matcherFlags: 'm'
+category: 'breaking'
+---
+
+When passing `secretKey` as a runtime option to `clerkMiddleware()`, you must now also provide a `CLERK_ENCRYPTION_KEY` environment variable.
+
+Add the encryption key to your environment:
+
+```env
+CLERK_ENCRYPTION_KEY=your-encryption-key
+```
+
+More information: https://clerk.com/docs/reference/nextjs/clerk-middleware#dynamic-keys
diff --git a/packages/upgrade/src/versions/core-3/changes/nuxt-getauth-removed.md b/packages/upgrade/src/versions/core-3/changes/nuxt-getauth-removed.md
new file mode 100644
index 00000000000..e24369980ce
--- /dev/null
+++ b/packages/upgrade/src/versions/core-3/changes/nuxt-getauth-removed.md
@@ -0,0 +1,21 @@
+---
+title: '`getAuth()` helper removed'
+packages: ['nuxt']
+matcher: 'getAuth\\('
+category: 'deprecation-removal'
+---
+
+The deprecated `getAuth()` helper has been removed. Use `event.context.auth()` in your server routes instead:
+
+```diff
+- import { getAuth } from '@clerk/nuxt/server';
+
+export default defineEventHandler((event) => {
+- const { userId } = getAuth(event);
++ const { userId } = event.context.auth();
+
+ return {
+ userId,
+ };
+});
+```
diff --git a/packages/upgrade/src/versions/core-3/changes/nuxt-routing-strategy-default-path.md b/packages/upgrade/src/versions/core-3/changes/nuxt-routing-strategy-default-path.md
new file mode 100644
index 00000000000..dccc973b30e
--- /dev/null
+++ b/packages/upgrade/src/versions/core-3/changes/nuxt-routing-strategy-default-path.md
@@ -0,0 +1,28 @@
+---
+title: 'Routing strategy now defaults to `path`'
+packages: ['nuxt']
+matcher:
+ - '`
+- ``
+- ``
+- ``
+- ``
+- ``
+
+If you were relying on the previous `hash` routing behavior, explicitly set the routing prop:
+
+```vue
+
+```
diff --git a/packages/upgrade/src/versions/core-3/changes/saml-account-renamed.md b/packages/upgrade/src/versions/core-3/changes/saml-account-renamed.md
new file mode 100644
index 00000000000..dc5cae2799f
--- /dev/null
+++ b/packages/upgrade/src/versions/core-3/changes/saml-account-renamed.md
@@ -0,0 +1,15 @@
+---
+title: '`samlAccount` renamed to `enterpriseAccount`'
+matcher: 'samlAccount'
+category: 'deprecation-removal'
+---
+
+The `samlAccount` property has been renamed to `enterpriseAccount`. Update your code:
+
+```diff
+- user.samlAccounts
++ user.enterpriseAccounts
+
+- verification.samlAccount
++ verification.enterpriseAccount
+```
diff --git a/packages/upgrade/src/versions/core-3/changes/saml-to-enterprise-sso.md b/packages/upgrade/src/versions/core-3/changes/saml-to-enterprise-sso.md
new file mode 100644
index 00000000000..6ee8fdafdb4
--- /dev/null
+++ b/packages/upgrade/src/versions/core-3/changes/saml-to-enterprise-sso.md
@@ -0,0 +1,12 @@
+---
+title: '`saml` strategy renamed to `enterprise_sso`'
+matcher: 'saml'
+category: 'deprecation-removal'
+---
+
+The `saml` authentication strategy has been renamed to `enterprise_sso`. Update any references in your code:
+
+```diff
+- strategy: 'saml'
++ strategy: 'enterprise_sso'
+```
diff --git a/packages/upgrade/src/versions/core-3/changes/set-active-before-emit-removed.md b/packages/upgrade/src/versions/core-3/changes/set-active-before-emit-removed.md
new file mode 100644
index 00000000000..fe40a61a229
--- /dev/null
+++ b/packages/upgrade/src/versions/core-3/changes/set-active-before-emit-removed.md
@@ -0,0 +1,22 @@
+---
+title: '`setActive({ beforeEmit })` changed to `setActive({ navigate })`'
+matcher: 'beforeEmit'
+category: 'deprecation-removal'
+---
+
+The `beforeEmit` callback in `setActive()` has been replaced with `navigate`. The callback signature has also changed:
+
+```diff
+await setActive({
+ session: sessionId,
+- beforeEmit: () => {
+- // Called before session is set
+- }
++ navigate: ({ session }) => {
++ // Called with the session object
++ return '/dashboard';
++ }
+});
+```
+
+The `navigate` callback receives an object with the `session` property and should return the URL to navigate to.
diff --git a/packages/upgrade/src/versions/core-3/changes/show-optional-fields-default.md b/packages/upgrade/src/versions/core-3/changes/show-optional-fields-default.md
new file mode 100644
index 00000000000..d8abea6332e
--- /dev/null
+++ b/packages/upgrade/src/versions/core-3/changes/show-optional-fields-default.md
@@ -0,0 +1,20 @@
+---
+title: '`showOptionalFields` now defaults to `false`'
+matcher: 'showOptionalFields'
+category: 'behavior-change'
+warning: true
+---
+
+The default value of `appearance.layout.showOptionalFields` (now `appearance.options.showOptionalFields`) has changed from `true` to `false`. Optional fields are now hidden by default during sign up.
+
+To restore the previous behavior, explicitly set the option:
+
+```jsx
+
+```
diff --git a/packages/upgrade/src/versions/core-3/changes/ui-themes-export-path.md b/packages/upgrade/src/versions/core-3/changes/ui-themes-export-path.md
new file mode 100644
index 00000000000..190cd0e2c8a
--- /dev/null
+++ b/packages/upgrade/src/versions/core-3/changes/ui-themes-export-path.md
@@ -0,0 +1,16 @@
+---
+title: 'UI themes moved to `@clerk/ui/themes/experimental`'
+matcher:
+ - '__experimental_createTheme'
+ - 'experimental_createTheme'
+category: 'breaking'
+---
+
+The `createTheme` theme utility has been moved to a new export path. Update your imports:
+
+```diff
+- import { __experimental_createTheme } from '@clerk/ui';
++ import { createTheme } from '@clerk/ui/themes/experimental';
+```
+
+Note: The `__experimental_` prefix has been removed from the method since they're now in the `/themes/experimental` subpath.
diff --git a/packages/upgrade/src/versions/core-3/changes/unstable-to-internal.md b/packages/upgrade/src/versions/core-3/changes/unstable-to-internal.md
new file mode 100644
index 00000000000..b9685b236c2
--- /dev/null
+++ b/packages/upgrade/src/versions/core-3/changes/unstable-to-internal.md
@@ -0,0 +1,25 @@
+---
+title: '`__unstable_*` methods renamed to `__internal_*`'
+matcher: '__unstable_'
+category: 'breaking'
+---
+
+All `__unstable_*` methods have been renamed to `__internal_*`. These are internal APIs not intended for public use.
+
+### @clerk/clerk-js
+
+- `__unstable__environment` → `__internal_environment`
+- `__unstable__updateProps` → `__internal_updateProps`
+- `__unstable__setEnvironment` → `__internal_setEnvironment`
+- `__unstable__onBeforeRequest` → `__internal_onBeforeRequest`
+- `__unstable__onAfterResponse` → `__internal_onAfterResponse`
+- `__unstable__onBeforeSetActive` → `__internal_onBeforeSetActive`
+- `__unstable__onAfterSetActive` → `__internal_onAfterSetActive`
+
+### @clerk/nextjs
+
+- `__unstable_invokeMiddlewareOnAuthStateChange` → `__internal_invokeMiddlewareOnAuthStateChange`
+
+### @clerk/chrome-extension
+
+- `__unstable__createClerkClient` → `createClerkClient` (exported from `@clerk/chrome-extension/background`)
diff --git a/packages/upgrade/src/versions/core-3/changes/user-settings-saml-renamed.md b/packages/upgrade/src/versions/core-3/changes/user-settings-saml-renamed.md
new file mode 100644
index 00000000000..af007f768a5
--- /dev/null
+++ b/packages/upgrade/src/versions/core-3/changes/user-settings-saml-renamed.md
@@ -0,0 +1,13 @@
+---
+title: '`UserSettings.saml` renamed to `enterpriseSSO`'
+matcher: 'UserSettings[\\s\\S]*?saml'
+matcherFlags: 'm'
+category: 'deprecation-removal'
+---
+
+The `saml` property on `UserSettings` has been renamed to `enterpriseSSO`:
+
+```diff
+- userSettings.saml
++ userSettings.enterpriseSSO
+```
diff --git a/packages/upgrade/src/versions/core-3/changes/userbutton-signout-props-removed.md b/packages/upgrade/src/versions/core-3/changes/userbutton-signout-props-removed.md
new file mode 100644
index 00000000000..b1ff7b0f4fc
--- /dev/null
+++ b/packages/upgrade/src/versions/core-3/changes/userbutton-signout-props-removed.md
@@ -0,0 +1,26 @@
+---
+title: '`UserButton` sign-out redirect props removed'
+matcher: ''
+matcherFlags: 'm'
+category: 'deprecation-removal'
+---
+
+The `UserButton` component no longer accepts sign-out redirect override props. Configure sign-out redirects using one of these methods:
+
+**Global configuration:**
+
+```jsx
+
+```
+
+**Per-button with SignOutButton:**
+
+```jsx
+Sign Out
+```
+
+**Programmatic:**
+
+```js
+clerk.signOut({ redirectUrl: '/signed-out' });
+```