[GH-ISSUE #3015] Property 'createUser' does not exist #9436

Closed
opened 2026-04-13 04:53:59 -05:00 by GiteaMirror · 12 comments
Owner

Originally created by @sovetski on GitHub (Jun 13, 2025).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/3015

I am using this: await auth.api.createUser to create initial users with a custom script on my website, it is like seeds but only for users. I am running this script at the beginning of the project, and once the project is live for the first time, to create my initial admin accounts.

This code works

await auth.api.createUser({
    body: {
        name: "Name",
        email: "blabla",
        password: "blabla",
        role: "blabla",
    },
});

But it gives this typescript error:

Property 'createUser' 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): ...'

And I looked at the documentation, but no where we have any information on how to create users, without using this admin plugin

Originally created by @sovetski on GitHub (Jun 13, 2025). Original GitHub issue: https://github.com/better-auth/better-auth/issues/3015 I am using this: `await auth.api.createUser` to create initial users with a custom script on my website, it is like `seeds` but only for users. I am running this script at the beginning of the project, and once the project is live for the first time, to create my initial admin accounts. This code works ```ts await auth.api.createUser({ body: { name: "Name", email: "blabla", password: "blabla", role: "blabla", }, }); ``` But it gives this typescript error: `Property 'createUser' 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): ...'` And I looked at the documentation, but no where we have any information on how to create users, without using [this admin plugin](https://www.better-auth.com/docs/plugins/admin)
GiteaMirror added the locked label 2026-04-13 04:53:59 -05:00
Author
Owner

@Kinfe123 commented on GitHub (Jun 13, 2025):

createUser is part of the admin plugin. The TypeScript error you're encountering happens because the types from the admin plugin aren't being picked up in your setup and thats why the createUser is doesn't exist. so you have to use the admin plugin for that. for seeding you can do write a script which first creates the admin and then creates a users.

<!-- gh-comment-id:2971195464 --> @Kinfe123 commented on GitHub (Jun 13, 2025): `createUser` is part of the admin plugin. The TypeScript error you're encountering happens because the types from the admin plugin aren't being picked up in your setup and thats why the createUser is doesn't exist. so you have to use the admin plugin for that. for seeding you can do write a script which first creates the admin and then creates a users.
Author
Owner

@jpainam commented on GitHub (Jun 14, 2025):

I have a slighly similar question, createUser, setUserPassword all exist in the admin plugin but only work from authClient
Is it possible to create/update from auth.api?

Image

<!-- gh-comment-id:2972051646 --> @jpainam commented on GitHub (Jun 14, 2025): I have a slighly similar question, `createUser`, `setUserPassword` all exist in the `admin` plugin but only work from `authClient` Is it possible to `create/update` from `auth.api`? ![Image](https://github.com/user-attachments/assets/de59c041-8af6-427f-8e42-5dea1179a533)
Author
Owner

@Kinfe123 commented on GitHub (Jun 14, 2025):

this is valid if you are using admin plugin.

auth.api.createUser({
  body: {
    email: "test@test.com",
    password: "test",
    name: "Test User",
  }
})
<!-- gh-comment-id:2972087396 --> @Kinfe123 commented on GitHub (Jun 14, 2025): this is valid if you are using admin plugin. ```ts auth.api.createUser({ body: { email: "test@test.com", password: "test", name: "Test User", } }) ```
Author
Owner

@jpainam commented on GitHub (Jun 14, 2025):

this is valid if you are using admin plugin.

auth.api.createUser({
body: {
email: "test@test.com",
password: "test",
name: "Test User",
}
})

See my screenshot above. Can’t find createUser on the auth.api. But on authClient.admin

I’m using admin plugin both in the client and server

<!-- gh-comment-id:2972092795 --> @jpainam commented on GitHub (Jun 14, 2025): > this is valid if you are using admin plugin. > > auth.api.createUser({ > body: { > email: "test@test.com", > password: "test", > name: "Test User", > } > }) See my screenshot above. Can’t find createUser on the auth.api. But on authClient.admin I’m using admin plugin both in the client and server
Author
Owner

@Kinfe123 commented on GitHub (Jun 14, 2025):

can you please share your server auth config ?

<!-- gh-comment-id:2972275711 --> @Kinfe123 commented on GitHub (Jun 14, 2025): can you please share your server auth config ?
Author
Owner

@jpainam commented on GitHub (Jun 14, 2025):

auth.ts

const config = {
    database: prismaAdapter(db, {
      provider: "postgresql",
    }),
   
    baseURL: options.baseUrl,
    secret: options.secret,
    plugins: [
      admin() as unknown as BetterAuthPlugin,
      username(),
      apiKey({
        enableMetadata: true,
      }),
      expo(),
      nextCookies(),
    ],
    trustedOrigins: ["expo://"],
  } satisfies BetterAuthOptions;

  return betterAuth(config);

client.ts

import {
  adminClient,
  apiKeyClient,
  inferAdditionalFields,
  usernameClient,
} from "better-auth/client/plugins";
import { createAuthClient } from "better-auth/react";
import type { auth } from "./server";
export const authClient = createAuthClient({
  plugins: [
    apiKeyClient(),
    adminClient(),
    usernameClient(),
    inferAdditionalFields<typeof auth>(),
  ],
});

export const { useSession } = authClient;

<!-- gh-comment-id:2972294118 --> @jpainam commented on GitHub (Jun 14, 2025): `auth.ts` ```tsx const config = { database: prismaAdapter(db, { provider: "postgresql", }), baseURL: options.baseUrl, secret: options.secret, plugins: [ admin() as unknown as BetterAuthPlugin, username(), apiKey({ enableMetadata: true, }), expo(), nextCookies(), ], trustedOrigins: ["expo://"], } satisfies BetterAuthOptions; return betterAuth(config); ``` `client.ts` ```tsx import { adminClient, apiKeyClient, inferAdditionalFields, usernameClient, } from "better-auth/client/plugins"; import { createAuthClient } from "better-auth/react"; import type { auth } from "./server"; export const authClient = createAuthClient({ plugins: [ apiKeyClient(), adminClient(), usernameClient(), inferAdditionalFields<typeof auth>(), ], }); export const { useSession } = authClient; ```
Author
Owner

@Kinfe123 commented on GitHub (Jun 14, 2025):

i see. the problem is we are force asserting the admim plugin. can you please tell me the error if you are not doing the assertion ?

<!-- gh-comment-id:2972296005 --> @Kinfe123 commented on GitHub (Jun 14, 2025): i see. the problem is we are force asserting the admim plugin. can you please tell me the error if you are not doing the assertion ?
Author
Owner

@jpainam commented on GitHub (Jun 14, 2025):

It was following this issue The inferred type of this node exceeds the maximum length the compiler will serialize https://github.com/better-auth/better-auth/issues/2789

<!-- gh-comment-id:2972418763 --> @jpainam commented on GitHub (Jun 14, 2025): It was following this issue The inferred type of this node exceeds the maximum length the compiler will serialize https://github.com/better-auth/better-auth/issues/2789
Author
Owner

@jpainam commented on GitHub (Jun 14, 2025):

Changing admin() as unknown as BetterAuthPlugin to simply admin() fixed the problem,. I have to. find another way around issue #2789 by defining my functions return type instead of infering them

<!-- gh-comment-id:2972796958 --> @jpainam commented on GitHub (Jun 14, 2025): Changing `admin() as unknown as BetterAuthPlugin` to simply `admin()` fixed the problem,. I have to. find another way around issue #2789 by defining my functions return type instead of infering them
Author
Owner

@Kinfe123 commented on GitHub (Jun 15, 2025):

can you try adding @ts-ignore and check that if the auth.api.createUser would exists ?

<!-- gh-comment-id:2973531070 --> @Kinfe123 commented on GitHub (Jun 15, 2025): can you try adding @ts-ignore and check that if the auth.api.createUser would exists ?
Author
Owner

@jpainam commented on GitHub (Jun 15, 2025):

ts-ignore or ts-expect-error didn't work.

Image

This is what work

export const createTRPCContext = async (opts: {
  headers: Headers;
  auth: Auth;
}): Promise<{
  authApi: Auth["api"];
  session: Session | null;
}> => {
  const authApi: Auth["api"] = opts.auth.api;
  const session = await authApi.getSession({
    headers: opts.headers,
  });
  return {
    authApi,
    session,
  };
};

I have to typed the returns typecreateTRPCContext

<!-- gh-comment-id:2973877426 --> @jpainam commented on GitHub (Jun 15, 2025): `ts-ignore` or `ts-expect-error` didn't work. ![Image](https://github.com/user-attachments/assets/a5119ecf-07ea-4f19-a79e-f4e200bda64a) This is what work ```tsx export const createTRPCContext = async (opts: { headers: Headers; auth: Auth; }): Promise<{ authApi: Auth["api"]; session: Session | null; }> => { const authApi: Auth["api"] = opts.auth.api; const session = await authApi.getSession({ headers: opts.headers, }); return { authApi, session, }; }; ``` I have to typed the returns type`createTRPCContext`
Author
Owner

@sovetski commented on GitHub (Jun 15, 2025):

thanks @Kinfe123

I don't really understand why on the documentation we have the authClient is prioritised but not this one auth.api.

And also, instead of using auth.api, I suggest something like auth.createUser or auth.admin.createUser to keep the conistency with authClient

Because this one:

await auth.createUser({
        name: "Name",
        email: "blabla",
        password: "blabla",
        role: "blabla",
});

is better than

await auth.api.createUser({
    body: {
        name: "Name",
        email: "blabla",
        password: "blabla",
        role: "blabla",
    },
});
<!-- gh-comment-id:2974072240 --> @sovetski commented on GitHub (Jun 15, 2025): thanks @Kinfe123 I don't really understand why on the [documentation](https://www.better-auth.com/docs/plugins/admin) we have the `authClient` is prioritised but not this one `auth.api`. And also, instead of using `auth.api`, I suggest something like `auth.createUser` or `auth.admin.createUser` to keep the conistency with `authClient` Because this one: ```js await auth.createUser({ name: "Name", email: "blabla", password: "blabla", role: "blabla", }); ``` is better than ```js await auth.api.createUser({ body: { name: "Name", email: "blabla", password: "blabla", role: "blabla", }, }); ```
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#9436