[GH-ISSUE #3602] Optional data field in auth.api.createUser() is non-functional #9659

Closed
opened 2026-04-13 05:16:15 -05:00 by GiteaMirror · 8 comments
Owner

Originally created by @eaoliver on GitHub (Jul 25, 2025).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/3602

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

The optional data field in the auth.api.createUser function enabled by the admin plugin does not appear to function.

Following the example on: https://www.better-auth.com/docs/plugins/admin#create-user

const newUser = await auth.api.createUser({
    body: {
        email: "user@example.com", // required
        password: "some-secure-password", // required
        name: "James Smith", // required
        role: "user",
        data: { customField: "customValue" },
    },
});

No custom data is stored.

I tried adding a data column to the users table and a column corresponding to the customField.

Current vs. Expected behavior

Any custom data when creating a new is not stored.

What version of Better Auth are you using?

1.3.3

Provide environment information

Node 20

Which area(s) are affected? (Select all that apply)

Backend

Auth config (if applicable)

import { betterAuth } from "better-auth"
export const auth = betterAuth({
  emailAndPassword: {  
    enabled: true
  },
  database: drizzleAdapter(db, {
    //debugLogs: true,
    provider: "pg",
    schema: {
      users: users,
      accounts: accounts,
      sessions: sessions,
      verifications: verifications,
      two_factors: twoFactors,
      apikeys: apikeys,
    },
    usePlural: true,
  }),
  plugins: [
    apiKey(),
    twoFactor(),
    admin(),
  ]
});

Additional context

No response

Originally created by @eaoliver on GitHub (Jul 25, 2025). Original GitHub issue: https://github.com/better-auth/better-auth/issues/3602 ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce The optional data field in the `auth.api.createUser` function enabled by the `admin` plugin does not appear to function. Following the example on: https://www.better-auth.com/docs/plugins/admin#create-user ``` const newUser = await auth.api.createUser({ body: { email: "user@example.com", // required password: "some-secure-password", // required name: "James Smith", // required role: "user", data: { customField: "customValue" }, }, }); ``` No custom data is stored. I tried adding a `data` column to the `users` table and a column corresponding to the customField. ### Current vs. Expected behavior Any custom data when creating a new is not stored. ### What version of Better Auth are you using? 1.3.3 ### Provide environment information ```bash Node 20 ``` ### Which area(s) are affected? (Select all that apply) Backend ### Auth config (if applicable) ```typescript import { betterAuth } from "better-auth" export const auth = betterAuth({ emailAndPassword: { enabled: true }, database: drizzleAdapter(db, { //debugLogs: true, provider: "pg", schema: { users: users, accounts: accounts, sessions: sessions, verifications: verifications, two_factors: twoFactors, apikeys: apikeys, }, usePlural: true, }), plugins: [ apiKey(), twoFactor(), admin(), ] }); ``` ### Additional context _No response_
GiteaMirror added the lockedbug labels 2026-04-13 05:16:15 -05:00
Author
Owner

@dosubot[bot] commented on GitHub (Jul 25, 2025):

The reason custom data from the data field in createUser isn't being stored is that Better Auth only persists fields that are explicitly defined in your user schema. Just adding a column to your database isn't enough—custom fields must be registered in your auth config using the additionalFields property. This applies whether you want a single JSON data column or individual custom fields.

To store custom data, update your auth config like this:

export const auth = betterAuth({
  // ...other config
  user: {
    additionalFields: {
      // For a JSON 'data' column:
      data: { type: "json", required: false },
      // Or for individual fields:
      customField: { type: "string", required: false }
    }
  }
});

After updating your config, run the Better Auth CLI to update your database schema:

npx @better-auth/cli generate
# or, if using the built-in Kysely adapter:
npx @better-auth/cli migrate

Now, when you call createUser with a data property (or any custom field you've defined), it will be persisted as expected. You can find more details and examples in the official documentation.

If you want to store arbitrary JSON data, define a data field of type "json" in additionalFields. If you want to store individual custom fields, define each one separately. The admin plugin's data property is just a convenience for passing these extra fields, but they must be present in your schema to be saved source.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other  Chat with Dosu Join Discord Share on X

<!-- gh-comment-id:3115436689 --> @dosubot[bot] commented on GitHub (Jul 25, 2025): <!-- Answer --> The reason custom data from the `data` field in `createUser` isn't being stored is that Better Auth only persists fields that are explicitly defined in your user schema. Just adding a column to your database isn't enough—custom fields must be registered in your auth config using the `additionalFields` property. This applies whether you want a single JSON `data` column or individual custom fields. To store custom data, update your auth config like this: ```typescript export const auth = betterAuth({ // ...other config user: { additionalFields: { // For a JSON 'data' column: data: { type: "json", required: false }, // Or for individual fields: customField: { type: "string", required: false } } } }); ``` After updating your config, run the Better Auth CLI to update your database schema: ``` npx @better-auth/cli generate # or, if using the built-in Kysely adapter: npx @better-auth/cli migrate ``` Now, when you call `createUser` with a `data` property (or any custom field you've defined), it will be persisted as expected. You can find more details and examples in the [official documentation](https://better-auth.com/docs/concepts/database). If you want to store arbitrary JSON data, define a `data` field of type `"json"` in `additionalFields`. If you want to store individual custom fields, define each one separately. The admin plugin's `data` property is just a convenience for passing these extra fields, but they must be present in your schema to be saved [source](https://better-auth.com/docs/concepts/database). <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/36cadb8a-58a3-4794-8e3b-532919707b4d?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/36cadb8a-58a3-4794-8e3b-532919707b4d?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/36cadb8a-58a3-4794-8e3b-532919707b4d?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/36cadb8a-58a3-4794-8e3b-532919707b4d?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/36cadb8a-58a3-4794-8e3b-532919707b4d?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/36cadb8a-58a3-4794-8e3b-532919707b4d?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/36cadb8a-58a3-4794-8e3b-532919707b4d?feedback_type=other)</sup>&nbsp;&nbsp;[![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/better-auth/better-auth/issues/3602)
Author
Owner

@eaoliver commented on GitHub (Jul 25, 2025):

Amazing. Thank you @dosu.

<!-- gh-comment-id:3115442172 --> @eaoliver commented on GitHub (Jul 25, 2025): Amazing. Thank you @dosu.
Author
Owner

@dosubot[bot] commented on GitHub (Jul 25, 2025):

You're welcome!

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other  Chat with Dosu Join Discord Share on X

<!-- gh-comment-id:3115443385 --> @dosubot[bot] commented on GitHub (Jul 25, 2025): <!-- Answer --> You're welcome! <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/1612ef22-d48b-4deb-8611-563d5aff08f6?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/1612ef22-d48b-4deb-8611-563d5aff08f6?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/1612ef22-d48b-4deb-8611-563d5aff08f6?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/1612ef22-d48b-4deb-8611-563d5aff08f6?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/1612ef22-d48b-4deb-8611-563d5aff08f6?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/1612ef22-d48b-4deb-8611-563d5aff08f6?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/1612ef22-d48b-4deb-8611-563d5aff08f6?feedback_type=other)</sup>&nbsp;&nbsp;[![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/better-auth/better-auth/issues/3602)
Author
Owner

@eaoliver commented on GitHub (Jul 25, 2025):

For what it's worth @dosu, using "json" as a type produces this error when attempting to generate the new schema:

% npx @better-auth/cli generate
⠋ preparing schema...file:///Users/eaoliver/.npm/_npx/167ca1f116d365e6/node_modules/@better-auth/cli/dist/index.mjs:480
      return typeMap[type][databaseType];
                          ^

TypeError: Cannot read properties of undefined (reading 'pg')
    at getType (file:///Users/eaoliver/.npm/_npx/167ca1f116d365e6/node_modules/@better-auth/cli/dist/index.mjs:480:27)
    at file:///Users/eaoliver/.npm/_npx/167ca1f116d365e6/node_modules/@better-auth/cli/dist/index.mjs:508:18
    at Array.map (<anonymous>)
    at generateDrizzleSchema (file:///Users/eaoliver/.npm/_npx/167ca1f116d365e6/node_modules/@better-auth/cli/dist/index.mjs:506:28)
    at generateSchema (file:///Users/eaoliver/.npm/_npx/167ca1f116d365e6/node_modules/@better-auth/cli/dist/index.mjs:741:12)
    at Command.generateAction (file:///Users/eaoliver/.npm/_npx/167ca1f116d365e6/node_modules/@better-auth/cli/dist/index.mjs:784:24)

It's also causing the following error when calling auth.api.verifyApiKey:

Type error: Property 'verifyApiKey' does not exist on type 'InferAPI<{ ok: { <AsResponse extends boolean = false, ReturnHeaders extends boolean = false>(inputCtx_0?: ({ body?: undefined; } & { method?: "GET" | undefined; } & { query?: Record<string, any> | undefined; } & { params?: Record<string, any> | undefined; } & { ...; } & { ...; } & { ...; } & { ...; }) | undefined): ...'.

> 80 |       const verifyData = await auth.api.verifyApiKey({
<!-- gh-comment-id:3115652440 --> @eaoliver commented on GitHub (Jul 25, 2025): For what it's worth @dosu, using "json" as a type produces this error when attempting to generate the new schema: ``` % npx @better-auth/cli generate ⠋ preparing schema...file:///Users/eaoliver/.npm/_npx/167ca1f116d365e6/node_modules/@better-auth/cli/dist/index.mjs:480 return typeMap[type][databaseType]; ^ TypeError: Cannot read properties of undefined (reading 'pg') at getType (file:///Users/eaoliver/.npm/_npx/167ca1f116d365e6/node_modules/@better-auth/cli/dist/index.mjs:480:27) at file:///Users/eaoliver/.npm/_npx/167ca1f116d365e6/node_modules/@better-auth/cli/dist/index.mjs:508:18 at Array.map (<anonymous>) at generateDrizzleSchema (file:///Users/eaoliver/.npm/_npx/167ca1f116d365e6/node_modules/@better-auth/cli/dist/index.mjs:506:28) at generateSchema (file:///Users/eaoliver/.npm/_npx/167ca1f116d365e6/node_modules/@better-auth/cli/dist/index.mjs:741:12) at Command.generateAction (file:///Users/eaoliver/.npm/_npx/167ca1f116d365e6/node_modules/@better-auth/cli/dist/index.mjs:784:24) ``` It's also causing the following error when calling `auth.api.verifyApiKey`: ``` Type error: Property 'verifyApiKey' does not exist on type 'InferAPI<{ ok: { <AsResponse extends boolean = false, ReturnHeaders extends boolean = false>(inputCtx_0?: ({ body?: undefined; } & { method?: "GET" | undefined; } & { query?: Record<string, any> | undefined; } & { params?: Record<string, any> | undefined; } & { ...; } & { ...; } & { ...; } & { ...; }) | undefined): ...'. > 80 | const verifyData = await auth.api.verifyApiKey({ ```
Author
Owner

@dosubot[bot] commented on GitHub (Jul 25, 2025):

The Drizzle adapter in Better Auth doesn't support "json" as a type for additionalFields, which is why you see that TypeError—only "string", "number", "boolean", "date", "number[]", and "string[]" are supported. To store custom user data, you can either define each custom field explicitly as its own string/number/etc. field in additionalFields, or (if you need to store arbitrary JSON) serialize your object to a string and store it in a "string" field, then parse it in your app logic. See the database extension docs for examples.

For the verifyApiKey TypeScript error: the correct usage is auth.apiKey.verifyApiKey, not auth.api.verifyApiKey. The plugin APIs are namespaced, so make sure you're calling the method from the right place. If you still see type errors, double-check that the apiKey plugin is enabled in your config and that your types are up to date.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other  Chat with Dosu Join Discord Share on X

<!-- gh-comment-id:3115682497 --> @dosubot[bot] commented on GitHub (Jul 25, 2025): <!-- Answer --> The Drizzle adapter in Better Auth doesn't support `"json"` as a type for `additionalFields`, which is why you see that TypeError—only `"string"`, `"number"`, `"boolean"`, `"date"`, `"number[]"`, and `"string[]"` are supported. To store custom user data, you can either define each custom field explicitly as its own string/number/etc. field in `additionalFields`, or (if you need to store arbitrary JSON) serialize your object to a string and store it in a `"string"` field, then parse it in your app logic. See the [database extension docs](https://better-auth.com/docs/concepts/database) for examples. For the `verifyApiKey` TypeScript error: the correct usage is `auth.apiKey.verifyApiKey`, not `auth.api.verifyApiKey`. The plugin APIs are namespaced, so make sure you're calling the method from the right place. If you still see type errors, double-check that the `apiKey` plugin is enabled in your config and that your types are up to date. <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/6ab581c0-d323-4c97-bae3-1d8f483a6b2e?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/6ab581c0-d323-4c97-bae3-1d8f483a6b2e?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/6ab581c0-d323-4c97-bae3-1d8f483a6b2e?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/6ab581c0-d323-4c97-bae3-1d8f483a6b2e?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/6ab581c0-d323-4c97-bae3-1d8f483a6b2e?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/6ab581c0-d323-4c97-bae3-1d8f483a6b2e?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/6ab581c0-d323-4c97-bae3-1d8f483a6b2e?feedback_type=other)</sup>&nbsp;&nbsp;[![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/better-auth/better-auth/issues/3602)
Author
Owner

@eaoliver commented on GitHub (Jul 25, 2025):

@dosu, so you admit to hallucinating? ;-)

<!-- gh-comment-id:3115720210 --> @eaoliver commented on GitHub (Jul 25, 2025): @dosu, so you admit to hallucinating? ;-)
Author
Owner

@dosubot[bot] commented on GitHub (Jul 25, 2025):

Guilty as charged! 😅 I based that suggestion on the general pattern in the docs, but the Drizzle adapter doesn't actually support "json" as a type for additionalFields—only "string", "number", "boolean", "date", "number[]", and "string[]" are supported. For now, if you need to store JSON-like data, you'll need to stringify it into a "string" field and parse it in your app logic. Thanks for catching that and keeping me honest!

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other  Chat with Dosu Join Discord Share on X

<!-- gh-comment-id:3115733078 --> @dosubot[bot] commented on GitHub (Jul 25, 2025): <!-- Answer --> Guilty as charged! 😅 I based that suggestion on the general pattern in the docs, but the Drizzle adapter doesn't actually support "json" as a type for additionalFields—only "string", "number", "boolean", "date", "number[]", and "string[]" are supported. For now, if you need to store JSON-like data, you'll need to stringify it into a "string" field and parse it in your app logic. Thanks for catching that and keeping me honest! <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/d6141788-6272-4b08-bf0f-08da7435919d?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/d6141788-6272-4b08-bf0f-08da7435919d?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/d6141788-6272-4b08-bf0f-08da7435919d?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/d6141788-6272-4b08-bf0f-08da7435919d?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/d6141788-6272-4b08-bf0f-08da7435919d?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/d6141788-6272-4b08-bf0f-08da7435919d?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/d6141788-6272-4b08-bf0f-08da7435919d?feedback_type=other)</sup>&nbsp;&nbsp;[![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/better-auth/better-auth/issues/3602)
Author
Owner

@dlindahl commented on GitHub (Sep 26, 2025):

Would love to have a read key added to databaseHooks so that it was easier to serialize/deserialize outside of app logic.

<!-- gh-comment-id:3340755202 --> @dlindahl commented on GitHub (Sep 26, 2025): Would love to have a `read` key added to `databaseHooks` so that it was easier to serialize/deserialize outside of app logic.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#9659