Allow overriding of id field via custom field mappings to ease migrations #1132

Closed
opened 2026-03-13 08:24:13 -05:00 by GiteaMirror · 15 comments
Owner

Originally created by @mattpatagon on GitHub (Apr 29, 2025).

Background

When integrating an existing system that uses both id (for internal operations) and uid (for client-facing operations), it is not possible to hide the id in the get-session response. Our field-mapping layer correctly applies custom mappings for all fields except id, which is always sourced from its default location and ignores any override mappings. As a result, it is impossible both to integrate a system that uses both fields and also to fully migrate from legacy surrogate keys to new UID schemes without a complete database refactor.

Current Behavior

  • Custom mappings like
    {
      modelName: "user",
      fields: {
        id: "uid",          // NOT applied
        name: "first_name",
        emailVerified: "is_verified",
        createdAt: "created_at",
        updatedAt: "updated_at"
      }
    }
    
    are applied for every field except id.
  • The system disregards custom mapping for id first, but applies other mappings. Attempts to remap id simply fall back to the original numeric PK.

Describe the solution you'd like

Desired Behavior

  • Honor a mapping for the primary key/ID field just like any other field.
  • If fields.id is explicitly defined, use that column/property (e.g. uid) in place of the default.
  • Fall back to the original only if no id mapping is provided.

Use Case

We are migrating our authentication system to use UUIDs (uid) instead of integer PKs for security and cross-service consistency. Rather than refactoring several years worth of table schemas and foreign keys, we’d like to layer on a mapping adapter that simply swaps out iduid at the API boundary.

Describe alternatives you've considered

Proposed API

Extend the existing mapping configuration so that fields.id is treated identically to other mapped fields:

 modelName: "user",
 fields: {
-   id:     // reserved
+   id: "uid",
    name: "first_name",
    …
 }

Backwards Compatibility

  • If fields.id is absent, behavior remains unchanged.
  • If present, the mapping framework should apply it first, then fallback logic is not invoked.

Benefits

  • Enables seamless migration to UUID‐based IDs without wholesale database schema changes.
  • Brings id mapping in line with the rest of the field‐mapping abstraction for consistency.
Originally created by @mattpatagon on GitHub (Apr 29, 2025). ### Background When integrating an existing system that uses both `id` (for internal operations) and `uid` (for client-facing operations), it is not possible to hide the `id` in the get-session response. Our field-mapping layer correctly applies custom mappings for all fields except `id`, which is always sourced from its default location and ignores any override mappings. As a result, it is impossible both to integrate a system that uses both fields and also to fully migrate from legacy surrogate keys to new UID schemes without a complete database refactor. ### Current Behavior - Custom mappings like ```js { modelName: "user", fields: { id: "uid", // NOT applied name: "first_name", emailVerified: "is_verified", createdAt: "created_at", updatedAt: "updated_at" } } ``` are applied for every field **except** `id`. - The system disregards custom mapping for `id` first, but applies other mappings. Attempts to remap `id` simply fall back to the original numeric PK. ### Describe the solution you'd like ### Desired Behavior - Honor a mapping for the primary key/ID field just like any other field. - If `fields.id` is explicitly defined, use that column/property (e.g. `uid`) in place of the default. - Fall back to the original only if no `id` mapping is provided. ### Use Case We are migrating our authentication system to use UUIDs (`uid`) instead of integer PKs for security and cross-service consistency. Rather than refactoring several years worth of table schemas and foreign keys, we’d like to layer on a mapping adapter that simply swaps out `id` → `uid` at the API boundary. ### Describe alternatives you've considered ### Proposed API Extend the existing mapping configuration so that `fields.id` is treated identically to other mapped fields: ```diff modelName: "user", fields: { - id: // reserved + id: "uid", name: "first_name", … } ``` #### Backwards Compatibility - If `fields.id` is absent, behavior remains unchanged. - If present, the mapping framework should apply it first, then fallback logic is not invoked. ### Benefits - Enables seamless migration to UUID‐based IDs without wholesale database schema changes. - Brings `id` mapping in line with the rest of the field‐mapping abstraction for consistency.
Author
Owner

@arndesk3 commented on GitHub (May 1, 2025):

I am also waiting this. Need help

@arndesk3 commented on GitHub (May 1, 2025): I am also waiting this. Need help
Author
Owner

@keithj0nes commented on GitHub (May 11, 2025):

I am also trying to do this with user.iduser.user_id. Note: in my case, I'm using auto incremented id's

Here is more information on the error when changing the Prisma User schema id to user_id

Image

 
auth.ts

user: {
    fields: {
        id: 'user_id',
        emailVerified: 'email_verified',
        createdAt: 'created_at',
        updatedAt: 'updated_at',
    },
},
advanced: {
    database: {
        useNumberId: true,
    },
},

schema.prisma

model User {
    user_id        Int       @id @default(autoincrement())
   ...other_fields
}
@keithj0nes commented on GitHub (May 11, 2025): I am also trying to do this with `user.id` → `user.user_id`. Note: in my case, I'm using auto incremented id's Here is more information on the error when changing the Prisma User schema `id` to `user_id` <img width="641" alt="Image" src="https://github.com/user-attachments/assets/d0d08e3f-3616-4d4c-b9ff-c5c6dacaec65" /> &nbsp; **auth.ts** ``` user: { fields: { id: 'user_id', emailVerified: 'email_verified', createdAt: 'created_at', updatedAt: 'updated_at', }, }, advanced: { database: { useNumberId: true, }, }, ``` **schema.prisma** ``` model User { user_id Int @id @default(autoincrement()) ...other_fields } ```
Author
Owner

@ping-maxwell commented on GitHub (May 12, 2025):

It might be possible to implement this, but not 100%, it will definitely be really difficult because you guys want custom field ids across any table.

@ping-maxwell commented on GitHub (May 12, 2025): It *might* be possible to implement this, but not 100%, it will definitely be really difficult because you guys want custom field ids across any table.
Author
Owner

@rebasecase commented on GitHub (Jun 27, 2025):

Seems you've developed yourself into a corner, why are ids randomly generated strings? They're not even collision resistant.

https://github.com/better-auth/better-auth/pull/922

https://github.com/better-auth/utils/blob/67e06576b8504331fcc9cf51479719ce4fc6db24/src/random.ts#L20-L69

This is crazy given "Security handled - Battle-tested auth flows and security practices"

@rebasecase commented on GitHub (Jun 27, 2025): Seems you've developed yourself into a corner, why are ids randomly generated strings? They're not even collision resistant. https://github.com/better-auth/better-auth/pull/922 https://github.com/better-auth/utils/blob/67e06576b8504331fcc9cf51479719ce4fc6db24/src/random.ts#L20-L69 This is crazy given ["Security handled - Battle-tested auth flows and security practices"](https://www.better-auth.com/docs/comparison)
Author
Owner

@ping-maxwell commented on GitHub (Jul 1, 2025):

Hey guys, given the addition of createAdapter a little ago, this is definitely possible.

@ping-maxwell commented on GitHub (Jul 1, 2025): Hey guys, given the addition of `createAdapter` a little ago, this is definitely possible.
Author
Owner

@rebasecase commented on GitHub (Jul 1, 2025):

@ping-maxwell are you able to re run deploy task for 1.3 beta 3?

@rebasecase commented on GitHub (Jul 1, 2025): @ping-maxwell are you able to re run deploy task for 1.3 beta 3?
Author
Owner

@vcheeze commented on GitHub (Sep 30, 2025):

@ping-maxwell can you elaborate on how createAdapter can be used to address this? Do you simply mean we can write custom adapters to address this need to configure the id field? It seems slightly overkill in my use case: I'm using Xata, which has a Kysely adapter, and the default id column is xata_id instead of id, which results in an error for me like @mattpatagon mentioned, because the custom id field name is not applied.

Either way, it does seem like creating a custom adapter is the only way to address this for now, but would be nice if the simple config approach can work!

@vcheeze commented on GitHub (Sep 30, 2025): @ping-maxwell can you elaborate on how `createAdapter` can be used to address this? Do you simply mean we can write custom adapters to address this need to configure the `id` field? It seems slightly overkill in my use case: I'm using `Xata`, which has a Kysely adapter, and the default id column is `xata_id` instead of `id`, which results in an error for me like @mattpatagon mentioned, because the custom id field name is not applied. Either way, it does seem like creating a custom adapter is the only way to address this for now, but would be nice if the simple config approach can work!
Author
Owner

@ping-maxwell commented on GitHub (Sep 30, 2025):

No I mean it will be possible to be implemented on our side

@ping-maxwell commented on GitHub (Sep 30, 2025): No I mean it will be possible to be implemented on our side
Author
Owner

@vcheeze commented on GitHub (Sep 30, 2025):

Ah I see. I'll keep tabs on this then! Thank you :)

@vcheeze commented on GitHub (Sep 30, 2025): Ah I see. I'll keep tabs on this then! Thank you :)
Author
Owner

@shinebayar-g commented on GitHub (Oct 10, 2025):

Related https://github.com/better-auth/better-auth/pull/2248 uuid was removed without fallback options.

@shinebayar-g commented on GitHub (Oct 10, 2025): Related https://github.com/better-auth/better-auth/pull/2248 `uuid` was removed without fallback options.
Author
Owner

@ping-maxwell commented on GitHub (Oct 10, 2025):

Related #2248 uuid was removed without fallback options.

I believe you have the wrong idea. That PR relates to schema generation in our CLI - not the core of Better-Auth. We never removed uuid as a functionality of Better-Auth since it never was a functionality of Better-Auth, that PR was to fix a bug I introduced in our CLI package.

If you want uuid right now you can follow our docs here:
https://www.better-auth.com/docs/concepts/database#id-generation

@ping-maxwell commented on GitHub (Oct 10, 2025): > Related [#2248](https://github.com/better-auth/better-auth/pull/2248) `uuid` was removed without fallback options. I believe you have the wrong idea. That PR relates to schema generation in our CLI - not the core of Better-Auth. We never removed `uuid` as a functionality of Better-Auth since it never was a functionality of Better-Auth, that PR was to fix a bug I introduced in our CLI package. If you want `uuid` right now you can follow our docs here: https://www.better-auth.com/docs/concepts/database#id-generation
Author
Owner

@shinebayar-g commented on GitHub (Oct 10, 2025):

that PR was to fix a bug I introduced in our CLI package.

I see.. I missed that detail. At quick glance, before that PR it was generating uuid schema.

If you want uuid right now you can follow our docs here:

Yeah, unfortunately below code generates

    database: {
      generateId: () => crypto.randomUUID(),
    },

text fields instead of native uuid fields.

id: text('id')
@shinebayar-g commented on GitHub (Oct 10, 2025): > that PR was to fix a bug I introduced in our CLI package. I see.. I missed that detail. At quick glance, before that PR it was generating `uuid` schema. > If you want uuid right now you can follow our docs here: Yeah, unfortunately below code generates ```ts database: { generateId: () => crypto.randomUUID(), }, ``` text fields instead of native `uuid` fields. ```ts id: text('id') ```
Author
Owner

@ping-maxwell commented on GitHub (Oct 10, 2025):

When you use a custom generateId, you're responsible for the id types. In this case if you want an uuid field then you should change it to that

@ping-maxwell commented on GitHub (Oct 10, 2025): When you use a custom generateId, you're responsible for the `id` types. In this case if you want an `uuid` field then you should change it to that
Author
Owner

@shinebayar-g commented on GitHub (Oct 10, 2025):

Mhm. For now that's done manually until this feature request is implemented right?

@shinebayar-g commented on GitHub (Oct 10, 2025): Mhm. For now that's done manually until this feature request is implemented right?
Author
Owner

@dosubot[bot] commented on GitHub (Jan 9, 2026):

Hi, @mattpatagon. I'm Dosu, and I'm helping the better-auth team manage their backlog and am marking this issue as stale.

Issue Summary:

  • You requested support for overriding the primary key id field to facilitate migrations from integer IDs to UUIDs without extensive refactoring.
  • Other users have shared similar needs and related errors, highlighting the demand for this feature.
  • A maintainer acknowledged the challenge and mentioned the recent createAdapter addition as a possible way to implement this.
  • Current UUID support requires manual handling, with hopes for a simpler, config-based solution in the future.

Next Steps:

  • Please let me know if this issue is still relevant to the latest version of better-auth by commenting here to keep the discussion open.
  • If I don’t hear back within 7 days, this issue will be automatically closed.

Thanks for your understanding and contribution!

@dosubot[bot] commented on GitHub (Jan 9, 2026): Hi, @mattpatagon. I'm [Dosu](https://dosu.dev), and I'm helping the better-auth team manage their backlog and am marking this issue as stale. **Issue Summary:** - You requested support for overriding the primary key `id` field to facilitate migrations from integer IDs to UUIDs without extensive refactoring. - Other users have shared similar needs and related errors, highlighting the demand for this feature. - A maintainer acknowledged the challenge and mentioned the recent `createAdapter` addition as a possible way to implement this. - Current UUID support requires manual handling, with hopes for a simpler, config-based solution in the future. **Next Steps:** - Please let me know if this issue is still relevant to the latest version of better-auth by commenting here to keep the discussion open. - If I don’t hear back within 7 days, this issue will be automatically closed. Thanks for your understanding and contribution!
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#1132