[GH-ISSUE #8618] Adapter types should respect supportsDates: false #11138

Closed
opened 2026-04-13 07:30:23 -05:00 by GiteaMirror · 3 comments
Owner

Originally created by @erquhart on GitHub (Mar 15, 2026).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/8618

Problem

When an adapter sets supportsDates: false in its config, the runtime behavior correctly converts dates to/from the adapter's native format. However, the TypeScript types always use Date for date fields regardless of this setting.

This means adapters like Convex (which stores dates as numbers/milliseconds) have a type mismatch: TypeScript says createdAt: Date but the actual runtime value is a number.

Current behavior

const session = await auth.api.getSession({ headers });
// TypeScript thinks: session.createdAt is Date
// Runtime reality: session.createdAt is number (ms since epoch)

Expected behavior

When supportsDates: false, date field types in API responses should reflect the adapter's actual output type, or there should be a mechanism for adapters to specify the output type for date fields.

Context

This affects the Convex adapter for better-auth. Convex doesn't support the Date type — it uses numbers for timestamps. Our adapter's customTransformOutput returns new Date(data).getTime() for date fields, but the types still say Date.

A contributor tried to "fix" the type mismatch by making the runtime return Date objects instead (to match the types), but this broke Convex serialization since Date isn't a supported Convex type. We had to revert that fix.

Relevant code

In @better-auth/core, the type inference for date fields (InferDBValueType<"date">) always resolves to Date, with no conditional based on adapter config:

  • node_modules/@better-auth/core/dist/db/type.d.mtsInferDBFieldOutput always returns Date for date fields
  • node_modules/@better-auth/core/dist/db/schema/session.d.mts — hardcoded ZodDate types

Possible solutions

  1. Make InferDBValueType generic over adapter config so supportsDates: false changes the output type
  2. Add a type-level hook (similar to customTransformOutput) that lets adapters specify their date output type
  3. Add a generic type parameter to the adapter factory that maps field types
Originally created by @erquhart on GitHub (Mar 15, 2026). Original GitHub issue: https://github.com/better-auth/better-auth/issues/8618 ## Problem When an adapter sets `supportsDates: false` in its config, the runtime behavior correctly converts dates to/from the adapter's native format. However, the **TypeScript types** always use `Date` for date fields regardless of this setting. This means adapters like Convex (which stores dates as numbers/milliseconds) have a type mismatch: TypeScript says `createdAt: Date` but the actual runtime value is a `number`. ## Current behavior ```typescript const session = await auth.api.getSession({ headers }); // TypeScript thinks: session.createdAt is Date // Runtime reality: session.createdAt is number (ms since epoch) ``` ## Expected behavior When `supportsDates: false`, date field types in API responses should reflect the adapter's actual output type, or there should be a mechanism for adapters to specify the output type for date fields. ## Context This affects the [Convex adapter for better-auth](https://github.com/get-convex/better-auth). Convex doesn't support the `Date` type — it uses numbers for timestamps. Our adapter's `customTransformOutput` returns `new Date(data).getTime()` for date fields, but the types still say `Date`. A contributor tried to "fix" the type mismatch by making the runtime return `Date` objects instead (to match the types), but this broke Convex serialization since `Date` isn't a supported Convex type. We had to revert that fix. ## Relevant code In `@better-auth/core`, the type inference for date fields (`InferDBValueType<"date">`) always resolves to `Date`, with no conditional based on adapter config: - `node_modules/@better-auth/core/dist/db/type.d.mts` — `InferDBFieldOutput` always returns `Date` for date fields - `node_modules/@better-auth/core/dist/db/schema/session.d.mts` — hardcoded `ZodDate` types ## Possible solutions 1. Make `InferDBValueType` generic over adapter config so `supportsDates: false` changes the output type 2. Add a type-level hook (similar to `customTransformOutput`) that lets adapters specify their date output type 3. Add a generic type parameter to the adapter factory that maps field types
GiteaMirror added the locked label 2026-04-13 07:30:23 -05:00
Author
Owner

@dosubot[bot] commented on GitHub (Mar 15, 2026):

Thanks for the detailed issue! I can confirm this is a real limitation in Better Auth's type system.

The root cause is in InferDBValueType, which hardcodes "date" → Date with no conditional based on adapter configuration:

export type InferDBValueType<T extends DBFieldType> = T extends "date"
    ? Date  // ← Always Date, no adapter awareness
    // ...

The type system is completely decoupled from adapter configuration:

This type-runtime mismatch has caused issues for other adapters too, like Drizzle with { mode: "string" } timestamps and Prisma with MySQL.

Your proposed solution #1 (making InferDBValueType generic over adapter config) seems like the cleanest approach. It would require threading a type parameter through the adapter factory that maps field types based on configuration, something like:

type InferDBValueType<T extends DBFieldType, DateType = Date> = 
    T extends "date" ? DateType : // ...

This would be a significant change to the type system, but it's the right fix for adapters like Convex where dates aren't just stored differently—they're a fundamentally different type.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other

Chat with Dosu Open in Cursor Join Discord Share on X

<!-- gh-comment-id:4063475306 --> @dosubot[bot] commented on GitHub (Mar 15, 2026): <!-- Answer --> Thanks for the detailed issue! I can confirm this is a real limitation in Better Auth's type system. The root cause is in [`InferDBValueType`](https://github.com/better-auth/better-auth/blob/8f47015af223e5db9ff406f6ca8247f6b8dcd9fe/packages/core/src/db/type.ts#L16-L32), which hardcodes `"date" → Date` with no conditional based on adapter configuration: ```typescript export type InferDBValueType<T extends DBFieldType> = T extends "date" ? Date // ← Always Date, no adapter awareness // ... ``` The type system is completely decoupled from adapter configuration: - `supportsDates` only affects [runtime transformations in the adapter factory](https://github.com/better-auth/better-auth/blob/8f47015af223e5db9ff406f6ca8247f6b8dcd9fe/packages/core/src/db/adapter/factory.ts#L350-L355) - `customTransformOutput` is [purely runtime with no type-level impact](https://github.com/better-auth/better-auth/blob/8f47015af223e5db9ff406f6ca8247f6b8dcd9fe/packages/core/src/db/adapter/index.ts#L234-L262) - [`InferDBFieldOutput`](https://github.com/better-auth/better-auth/blob/8f47015af223e5db9ff406f6ca8247f6b8dcd9fe/packages/core/src/db/type.ts#L34-L39) propagates these hardcoded types throughout the system This type-runtime mismatch has caused issues for other adapters too, like [Drizzle with `{ mode: "string" }` timestamps](https://github.com/better-auth/better-auth/issues/7819) and [Prisma with MySQL](https://github.com/better-auth/better-auth/issues/3892#issuecomment-3170464388). Your proposed solution #1 (making `InferDBValueType` generic over adapter config) seems like the cleanest approach. It would require threading a type parameter through the adapter factory that maps field types based on configuration, something like: ```typescript type InferDBValueType<T extends DBFieldType, DateType = Date> = T extends "date" ? DateType : // ... ``` This would be a significant change to the type system, but it's the right fix for adapters like Convex where dates aren't just stored differently—they're a fundamentally different type. <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot?utm_source=github&utm_medium=bot-comment&utm_campaign=github-assistant&utm_content=brand-link).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/6262dde6-631a-495b-9dcd-1f71a8fbc4dc?feedback_type=great_response&utm_source=github&utm_medium=bot-comment&utm_campaign=github-assistant&utm_content=feedback-great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/6262dde6-631a-495b-9dcd-1f71a8fbc4dc?feedback_type=irrelevant_answer&utm_source=github&utm_medium=bot-comment&utm_campaign=github-assistant&utm_content=feedback-irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/6262dde6-631a-495b-9dcd-1f71a8fbc4dc?feedback_type=incorrect_sources&utm_source=github&utm_medium=bot-comment&utm_campaign=github-assistant&utm_content=feedback-incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/6262dde6-631a-495b-9dcd-1f71a8fbc4dc?feedback_type=too_verbose&utm_source=github&utm_medium=bot-comment&utm_campaign=github-assistant&utm_content=feedback-too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/6262dde6-631a-495b-9dcd-1f71a8fbc4dc?feedback_type=hallucination&utm_source=github&utm_medium=bot-comment&utm_campaign=github-assistant&utm_content=feedback-hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/6262dde6-631a-495b-9dcd-1f71a8fbc4dc?feedback_type=bug_report&utm_source=github&utm_medium=bot-comment&utm_campaign=github-assistant&utm_content=feedback-bug_report) | [Other](https://app.dosu.dev/response-feedback/6262dde6-631a-495b-9dcd-1f71a8fbc4dc?feedback_type=other&utm_source=github&utm_medium=bot-comment&utm_campaign=github-assistant&utm_content=feedback-other)</sup> [![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github&utm_medium=bot-comment&utm_campaign=github-assistant&utm_content=chat-badge)&nbsp;[![Open in Cursor](https://dosu.dev/dosu-in-cursor.svg)](https://cursor.com/link/prompt?text=Thanks%20for%20the%20detailed%20issue%21%20I%20can%20confirm%20this%20is%20a%20real%20limitation%20in%20Better%20Auth%27s%20type%20system.%0A%0AThe%20root%20cause%20is%20in%20%5B%60InferDBValueType%60%5D%28https%3A//github.com/better-auth/better-auth/blob/8f47015af223e5db9ff406f6ca8247f6b8dcd9fe/packages/core/src/db/type.ts%23L16-L32%29%2C%20which%20hardcodes%20%60%22date%22%20%E2%86%92%20Date%60%20with%20no%20conditional%20based%20on%20adapter%20configuration%3A%0A%0A%60%60%60typescript%0Aexport%20type%20InferDBValueType%3CT%20extends%20DBFieldType%3E%20%3D%20T%20extends%20%22date%22%0A%20%20%20%20%3F%20Date%20%20//%20%E2%86%90%20Always%20Date%2C%20no%20adapter%20awareness%0A%20%20%20%20//%20...%0A%60%60%60%0A%0AThe%20type%20system%20is%20completely%20decoupled%20from%20adapter%20configuration%3A%0A-%20%60supportsDates%60%20only%20affects%20%5Bruntime%20transformations%20in%20the%20adapter%20factory%5D%28https%3A//github.com/better-auth/better-auth/blob/8f47015af223e5db9ff406f6ca8247f6b8dcd9fe/packages/core/src/db/adapter/factory.ts%23L350-L355%29%0A-%20%60customTransformOutput%60%20is%20%5Bpurely%20runtime%20with%20no%20type-level%20impact%5D%28https%3A//github.com/better-auth/better-auth/blob/8f47015af223e5db9ff406f6ca8247f6b8dcd9fe/packages/core/src/db/adapter/index.ts%23L234-L262%29%0A-%20%5B%60InferDBFieldOutput%60%5D%28https%3A//github.com/better-auth/better-auth/blob/8f47015af223e5db9ff406f6ca8247f6b8dcd9fe/packages/core/src/db/type.ts%23L34-L39%29%20propagates%20these%20hardcoded%20types%20throughout%20the%20system%0A%0AThis%20type-runtime%20mismatch%20has%20caused%20issues%20for%20other%20adapters%20too%2C%20like%20%5BDrizzle%20with%20%60%7B%20mode%3A%20%22string%22%20%7D%60%20timestamps%5D%28https%3A//github.com/better-auth/better-auth/issues/7819%29%20and%20%5BPrisma%20with%20MySQL%5D%28https%3A//github.com/better-auth/better-auth/issues/3892%23issuecomment-3170464388%29.%0A%0AYour%20proposed%20solution%20%231%20%28making%20%60InferDBValueType%60%20generic%20over%20adapter%20config%29%20seems%20like%20the%20cleanest%20approach.%20It%20would%20require%20threading%20a%20type%20parameter%20through%20the%20adapter%20factory%20that%20maps%20field%20types%20based%20on%20configuration%2C%20something%20like%3A%0A%0A%60%60%60typescript%0Atype%20InferDBValueType%3CT%20extends%20DBFieldType%2C%20DateType%20%3D%20Date%3E%20%3D%20%0A%20%20%20%20T%20extends%20%22date%22%20%3F%20DateType%20%3A%20//%20...%0A%60%60%60%0A%0AThis%20would%20be%20a%20significant%20change%20to%20the%20type%20system%2C%20but%20it%27s%20the%20right%20fix%20for%20adapters%20like%20Convex%20where%20dates%20aren%27t%20just%20stored%20differently%E2%80%94they%27re%20a%20fundamentally%20different%20type.)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot?utm_source=github&utm_medium=bot-comment&utm_campaign=github-assistant&utm_content=join-discord)&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/8618)
Author
Owner

@erquhart commented on GitHub (Mar 15, 2026):

Claude ran way ahead of me and opened this lol.

<!-- gh-comment-id:4063612005 --> @erquhart commented on GitHub (Mar 15, 2026): Claude ran way ahead of me and opened this lol.
Author
Owner

@github-actions[bot] commented on GitHub (Mar 31, 2026):

This issue has been locked as it was closed more than 7 days ago. If you're experiencing a similar problem or you have additional context, please open a new issue and reference this one.

<!-- gh-comment-id:4165918410 --> @github-actions[bot] commented on GitHub (Mar 31, 2026): This issue has been locked as it was closed more than 7 days ago. If you're experiencing a similar problem or you have additional context, please open a new issue and reference this one.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#11138