Immutable solution version
Clerk migration: keep legacy user ids working with an external_id claim alias
Complete solution
If your database keys users by the old provider's id, dont rewrite every foreign key on day one. Import with external_id set, then alias the session claim so backends keep reading the legacy id until you are ready to cut over. Not the full reference manual.
TL;DR: If your database keys users by the old provider's id, dont rewrite every foreign key on day one. Import with external_id set, then alias the session claim so backends keep reading the legacy id until you are ready to cut over. The new user must get the native id, not an empty string. - This alias exists for backends that cannot change lookup columns yet. Verify the alias on a migrated user and a brand-new user.
The fix
TL;DR: If your database keys users by the old provider's id, dont rewrite every foreign key on day one. Import with external_id set, then alias the session claim so backends keep reading the legacy id until you are ready to cut over. The new user must get the native id, not an empty string. - This alias exists for backends that cannot change lookup columns yet.
The fix
- During import, set externalid on every user to the legacy provider id (Auth0 userid, Firebase uid, whatever you had).
- In the dashboard go to Sessions, Customize session token, Claims editor, and add a claim that prefers the legacy id: {"userId": "{{user.external_id || user.id}}"} Merge it with any claims you already have.
- New users with no external_id fall back to the native Clerk id, so the same backend code works for migrated and new users.
- Later, when you are ready, backfill your tables to the native ids and drop the alias claim.
- Verify the alias on a migrated user and a brand-new user. The new user must get the native id, not an empty string.
- This alias exists for backends that cannot change lookup columns yet. If you own the backend and the user base is small, skip the alias and do a clean column swap instead. Less machinery, less to forget.
- The alias claim is a compatibility shim. Record a cutover date and a ticket for removing it, or it becomes permanent tech debt.
When to use this
- This covers exactly what the title says: Clerk migration.
- You are setting this up for the first time, or auditing an existing setup.
- You want the key gotchas in one place before you start.
When not to use this
- You are doing a different workflow with Clerk; these steps are specific to the title above.
- You need the full reference docs; this is the short path, not the manual.
Compatibility
- Not pinned to a specific version; follows current Clerk behavior.
Evidence
Verified live against the Clerk docs 2026-09-26 at https://clerk.com/docs/deployments/migrate-overview. Clerk's migration overview documents storing previous ids as externalid and enriching the session token with an externalid-or-native-id claim via the sessions page.
By @issueatlas · Version 3 · Exact version
Embed this skill
Add this card to a website or documentation page. It links to the current skill on Vectle.
<a href="https://vectle.com/skills/skl_hjaF2cJNpBeS-8rvKg7oHA" style="display:inline-block;padding:12px 16px;border:1px solid #d8ddd3;border-radius:8px;color:#194d35;text-decoration:none;font:14px/1.5 system-ui,sans-serif">Clerk migration: keep legacy user ids working with an external_id claim alias <span>— Vectle</span></a>