Type mismatch between Drizzle schema and better-auth helpers #192

Closed
opened 2026-03-13 07:36:59 -05:00 by GiteaMirror · 2 comments
Owner

Originally created by @ianmartorell on GitHub (Nov 7, 2024).

Describe the bug

The better-auth helper functions and hooks return | undefined for optional fields, whereas Drizzle returns | null. For example, this is the type of the user from authClient.useSession:

const { data } = authClient.useSession()
(property) user: Prettify<{
    id: string;
    email: string;
    emailVerified: boolean;
    name: string;
    createdAt: Date;
    updatedAt: Date;
    image?: string | undefined;
    banned: boolean | undefined;
    role?: string | undefined;
    banReason?: string | undefined;
    banExpires?: undefined;
}> | undefined

And this is the inferred type from the Drizzle schema (InferSelectModel<typeof user>):

type User = InferSelectModel<typeof user>
type User = {
    id: string;
    name: string;
    email: string;
    emailVerified: boolean;
    image: string | null;
    createdAt: Date;
    updatedAt: Date;
    role: string | null;
    banned: boolean | null;
    banReason: string | null;
    banExpires: Date | null;
}

To Reproduce
Steps to reproduce the behavior:

Set up a Better Auth project with Drizzle.

Expected behavior
A clear and concise description of what you expected to happen.

The objects returned from Better Auth helpers should match the db schema. Prisma also uses null for optional fields so I think that would be the way to go.

Originally created by @ianmartorell on GitHub (Nov 7, 2024). **Describe the bug** The better-auth helper functions and hooks return `| undefined` for optional fields, whereas Drizzle returns `| null`. For example, this is the type of the `user` from `authClient.useSession`: ```ts const { data } = authClient.useSession() ``` ```ts (property) user: Prettify<{ id: string; email: string; emailVerified: boolean; name: string; createdAt: Date; updatedAt: Date; image?: string | undefined; banned: boolean | undefined; role?: string | undefined; banReason?: string | undefined; banExpires?: undefined; }> | undefined ``` And this is the inferred type from the Drizzle schema (`InferSelectModel<typeof user>`): ```ts type User = InferSelectModel<typeof user> ``` ```ts type User = { id: string; name: string; email: string; emailVerified: boolean; image: string | null; createdAt: Date; updatedAt: Date; role: string | null; banned: boolean | null; banReason: string | null; banExpires: Date | null; } ``` **To Reproduce** Steps to reproduce the behavior: Set up a Better Auth project with Drizzle. **Expected behavior** A clear and concise description of what you expected to happen. The objects returned from Better Auth helpers should match the db schema. Prisma also uses `null` for optional fields so I think that would be the way to go.
Author
Owner

@abegehr commented on GitHub (Feb 1, 2025):

This came up again for me on "better-auth": "^1.1.15":

User type returned from better-auth: auth.api.getSession({ headers: req.headers })

{
    id: string;
    email: string;
    emailVerified: boolean;
    name: string;
    createdAt: Date;
    updatedAt: Date;
    image?: string | null | undefined | undefined;
    deletedAt?: Date | null | undefined;
}

User type inferred by drizzle: typeof Users.$inferSelect

{
    id: string;
    email: string;
    emailVerified: boolean;
    name: string;
    createdAt: Date;
    updatedAt: Date;
    image: string | null;
    deletedAt: Date | null;
}

Drizzle uses | null for optional values, whereas better-auth seems to infer | null | undefined (see image).

This also occurs for additionalFields:

  user: {
    additionalFields: {
      deletedAt: {
        type: "date",
        required: false,
        input: false,
        defaultValue: null,
      },
    },
  },
@abegehr commented on GitHub (Feb 1, 2025): This came up again for me on `"better-auth": "^1.1.15"`: User type returned from better-auth: `auth.api.getSession({ headers: req.headers })` ``` { id: string; email: string; emailVerified: boolean; name: string; createdAt: Date; updatedAt: Date; image?: string | null | undefined | undefined; deletedAt?: Date | null | undefined; } ``` User type inferred by drizzle: `typeof Users.$inferSelect` ``` { id: string; email: string; emailVerified: boolean; name: string; createdAt: Date; updatedAt: Date; image: string | null; deletedAt: Date | null; } ``` Drizzle uses `| null` for optional values, whereas better-auth seems to infer `| null | undefined` (see `image`). This also occurs for additionalFields: ``` user: { additionalFields: { deletedAt: { type: "date", required: false, input: false, defaultValue: null, }, }, }, ```
Author
Owner

@abegehr commented on GitHub (Feb 1, 2025):

Work-around for api context:

export async function createContext({
  req,
  resHeaders,
}: FetchCreateContextFnOptions) {
  const isAuthed = await auth.api.getSession({ headers: req.headers });

  return {
    req,
    resHeaders,
    ...isAuthed,
    user: isAuthed?.user
      ? {
          ...isAuthed.user,
          image: isAuthed.user.image ?? null,
          deletedAt: isAuthed.user.deletedAt ?? null,
        }
      : null,
  };
}
@abegehr commented on GitHub (Feb 1, 2025): Work-around for api context: ```ts export async function createContext({ req, resHeaders, }: FetchCreateContextFnOptions) { const isAuthed = await auth.api.getSession({ headers: req.headers }); return { req, resHeaders, ...isAuthed, user: isAuthed?.user ? { ...isAuthed.user, image: isAuthed.user.image ?? null, deletedAt: isAuthed.user.deletedAt ?? null, } : null, }; } ```
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#192