Multiple custom plugins break typesafety #1548

Closed
opened 2026-03-13 08:47:25 -05:00 by GiteaMirror · 1 comment
Owner

Originally created by @Re4GD on GitHub (Jul 21, 2025).

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

Create 2 custom plugins
Add them to authClient
Typesafety works for only one of them. The other one can be called and works fine but without typesafety (currently using ts-ignore everywhere).

Current vs. Expected behavior

  • Current:
    Using more than 2 custom plugins break the autocomlete

  • Expected:
    It should not break

What version of Better Auth are you using?

1.3.1

Provide environment information

- OS: Arch Linux
- Browser: Chrome

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

Client

Auth config (if applicable)

import { betterAuth } from "better-auth"

export const auth = betterAuth({
  emailAndPassword: {  
    enabled: true
  },
  plugins: [
    custom(),
    custom2(),
  ],
});

// authClient.custom -> autocomplete works
// authClient.custom2 -> error

Additional context

No response

Originally created by @Re4GD on GitHub (Jul 21, 2025). ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce Create 2 custom plugins Add them to authClient Typesafety works for only one of them. The other one can be called and works fine but without typesafety (currently using ts-ignore everywhere). ### Current vs. Expected behavior - Current: Using more than 2 custom plugins break the autocomlete - Expected: It should not break ### What version of Better Auth are you using? 1.3.1 ### Provide environment information ```bash - OS: Arch Linux - Browser: Chrome ``` ### Which area(s) are affected? (Select all that apply) Client ### Auth config (if applicable) ```typescript import { betterAuth } from "better-auth" export const auth = betterAuth({ emailAndPassword: { enabled: true }, plugins: [ custom(), custom2(), ], }); // authClient.custom -> autocomplete works // authClient.custom2 -> error ``` ### Additional context _No response_
GiteaMirror added the plugin label 2026-03-13 08:47:25 -05:00
Author
Owner

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

This is a known typesafety issue in Better Auth when using multiple custom plugins. The root cause is how plugin types are merged on the client—TypeScript sometimes only infers the types from one plugin, breaking autocomplete for the others. This often happens due to plugin order or missing type propagation from the server to the client [source].

Workarounds that have helped others:

  • Plugin order: Try switching the order of your plugins in the array. Sometimes placing the plugin that adds new fields or endpoints first helps TypeScript merge types correctly [source].
  • Explicit type import: If possible, import the type of your server-side auth instance (e.g., typeof auth) and use it with your client plugins.
  • inferAdditionalFields plugin: On the client, use the inferAdditionalFields plugin and pass your server-side auth type to it. Example:
    import { createAuthClient, inferAdditionalFields } from "better-auth/client";
    import type { auth } from "@/lib/auth";
    
    export const authClient = createAuthClient({
      plugins: [inferAdditionalFields<typeof auth>()],
    });
    
    [source]
  • Manual type extension: As a last resort, manually extend or cast the types in your code to include the missing properties from your plugins [source].

Recent PRs have tried to improve type merging and serialization, so future versions may address this more robustly [source].

Let me know if you want help with a specific workaround or want to share your plugin code for review.

To reply, just mention @dosu.


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

@dosubot[bot] commented on GitHub (Jul 21, 2025): <!-- Answer --> This is a known typesafety issue in Better Auth when using multiple custom plugins. The root cause is how plugin types are merged on the client—TypeScript sometimes only infers the types from one plugin, breaking autocomplete for the others. This often happens due to plugin order or missing type propagation from the server to the client [[source](https://github.com/better-auth/better-auth/issues/3328)]. Workarounds that have helped others: - **Plugin order:** Try switching the order of your plugins in the array. Sometimes placing the plugin that adds new fields or endpoints first helps TypeScript merge types correctly [[source](https://github.com/better-auth/better-auth/issues/3328)]. - **Explicit type import:** If possible, import the type of your server-side `auth` instance (e.g., `typeof auth`) and use it with your client plugins. - **inferAdditionalFields plugin:** On the client, use the `inferAdditionalFields` plugin and pass your server-side auth type to it. Example: ```ts import { createAuthClient, inferAdditionalFields } from "better-auth/client"; import type { auth } from "@/lib/auth"; export const authClient = createAuthClient({ plugins: [inferAdditionalFields<typeof auth>()], }); ``` [[source](https://github.com/better-auth/better-auth/issues/3328)] - **Manual type extension:** As a last resort, manually extend or cast the types in your code to include the missing properties from your plugins [[source](https://github.com/better-auth/better-auth/issues/3033)]. Recent PRs have tried to improve type merging and serialization, so future versions may address this more robustly [[source](https://github.com/better-auth/better-auth/pull/962)]. Let me know if you want help with a specific workaround or want to share your plugin code for review. <!-- 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/4b3aaa62-1e3e-4c32-9434-859d0ded02e4?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/4b3aaa62-1e3e-4c32-9434-859d0ded02e4?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/4b3aaa62-1e3e-4c32-9434-859d0ded02e4?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/4b3aaa62-1e3e-4c32-9434-859d0ded02e4?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/4b3aaa62-1e3e-4c32-9434-859d0ded02e4?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/4b3aaa62-1e3e-4c32-9434-859d0ded02e4?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/4b3aaa62-1e3e-4c32-9434-859d0ded02e4?feedback_type=other)</sup>&nbsp;&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/3529)
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#1548