[GH-ISSUE #2768] Support initial data in React useSession hook for SSR scenarios #9341

Closed
opened 2026-04-13 04:46:37 -05:00 by GiteaMirror · 9 comments
Owner

Originally created by @ludwigbacklund on GitHub (May 23, 2025).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/2768

Is this suited for github?

  • Yes, this is suited for github

Problem

Currently, the React useSession hook always fetches session data on mount, leading to unnecessary network requests and loading states in SSR scenarios where the session data is already available on the client.

This creates several issues:

  1. Fetch waterfalls: Client renders with isPending: true, then fetches data that was already available
  2. Flash of loading state: Users see loading spinners even when session data could be immediately available
  3. Wasted requests: Server-rendered pages make redundant API calls on hydration
  4. Poor UX: Delayed rendering of authenticated content that could be shown immediately

Use Cases

Server-Side Rendering

// Server provides session data, but client still fetches unnecessarily
const sessionData = getServerSideSession(); // Already available
const { data, isPending } = useSession(); // Still fetches & shows loading

Testing with Mock Data

// Want to test components with known session state
const mockSession = { user: { id: "123" }, session: { id: "abc" } };
const { data } = useSession(); // Can't provide mock data directly

Progressive Enhancement

// Have session from cookies/localStorage, but hook ignores it
const cachedSession = getCachedSession();
const { data, isPending } = useSession(); // Ignores cached data

Proposed Solution

Allow useSession to accept initial data that skips the initial fetch:

// Current API (unchanged)
const { data, isPending } = useSession();

// New API with initial data
const { data, isPending } = useSession(initialSessionData);

Expected behavior:

  • When initial data provided: isPending: false immediately, no fetch on mount
  • When no initial data: current behavior unchanged
  • refetch() works in both cases
  • Maintains type safety and backward compatibility

Implementation Reference

A proof of concept implementation is available in PR #2767 that demonstrates:

  • Function overloads for type safety
  • Modified query hook to accept initial data
  • Backward compatible changes
  • Working tests validating the behavior

Describe alternatives you've considered

Passing a skip initial fetch boolean and providing the initial data with your own hook that wraps useSession

Additional context

No response

Originally created by @ludwigbacklund on GitHub (May 23, 2025). Original GitHub issue: https://github.com/better-auth/better-auth/issues/2768 ### Is this suited for github? - [x] Yes, this is suited for github ### Problem Currently, the React `useSession` hook always fetches session data on mount, leading to unnecessary network requests and loading states in SSR scenarios where the session data is already available on the client. This creates several issues: 1. **Fetch waterfalls**: Client renders with `isPending: true`, then fetches data that was already available 2. **Flash of loading state**: Users see loading spinners even when session data could be immediately available 3. **Wasted requests**: Server-rendered pages make redundant API calls on hydration 4. **Poor UX**: Delayed rendering of authenticated content that could be shown immediately ### Use Cases **Server-Side Rendering** ```tsx // Server provides session data, but client still fetches unnecessarily const sessionData = getServerSideSession(); // Already available const { data, isPending } = useSession(); // Still fetches & shows loading ``` **Testing with Mock Data** ```tsx // Want to test components with known session state const mockSession = { user: { id: "123" }, session: { id: "abc" } }; const { data } = useSession(); // Can't provide mock data directly ``` **Progressive Enhancement** ```tsx // Have session from cookies/localStorage, but hook ignores it const cachedSession = getCachedSession(); const { data, isPending } = useSession(); // Ignores cached data ``` ### Proposed Solution Allow `useSession` to accept initial data that skips the initial fetch: ```tsx // Current API (unchanged) const { data, isPending } = useSession(); // New API with initial data const { data, isPending } = useSession(initialSessionData); ``` **Expected behavior:** - When initial data provided: `isPending: false` immediately, no fetch on mount - When no initial data: current behavior unchanged - `refetch()` works in both cases - Maintains type safety and backward compatibility ### Implementation Reference A proof of concept implementation is available in PR #2767 that demonstrates: - Function overloads for type safety - Modified query hook to accept initial data - Backward compatible changes - Working tests validating the behavior ### Describe alternatives you've considered Passing a skip initial fetch boolean and providing the initial data with your own hook that wraps useSession ### Additional context _No response_
GiteaMirror added the locked label 2026-04-13 04:46:37 -05:00
Author
Owner

@CarbonNeuron commented on GitHub (May 24, 2025):

I actually experienced this today as well during my migration to better auth. NextAuth uses a session provider that you can populate on the server, that way it pulls from the provider first instead of fetching from the endpoint. This helps when trying to get the session down to a nested client component without prop drilling and still allowing SSR. It would be cool if better auth had a session provider like NextAuth does.

<!-- gh-comment-id:2906246220 --> @CarbonNeuron commented on GitHub (May 24, 2025): I actually experienced this today as well during my migration to better auth. NextAuth uses a session provider that you can populate on the server, that way it pulls from the provider first instead of fetching from the endpoint. This helps when trying to get the session down to a nested client component without prop drilling and still allowing SSR. It would be cool if better auth had a session provider like NextAuth does.
Author
Owner

@yerzham commented on GitHub (May 25, 2025):

How about defining initial values inferred from all plugins (including user session) when creating an auth client, and passing the client to a root level context provider? Something like this:

type InferPluginsData<Option extends ClientOptions> =
  Option["plugins"] extends Array<infer Plugin>
    ? Plugin extends BetterAuthClientPlugin
      ? Plugin["getAtoms"] extends (fetch: any) => infer Atoms
        ? Atoms extends Record<string, any>
          ? {
              [key in keyof Atoms as key extends string
                ? key extends `$${string}`
                  ? never
                  : ReturnType<Atoms[key]["get"]> extends { data: any }
                    ? key
                    : never
                : never]?:
                | NonNullable<ReturnType<Atoms[key]["get"]>["data"]>
                | undefined;
            }
          : {}
        : {}
      : {}
    : {};

export function createAuthClient<
  Option extends ClientOptions,
  ClientAPI extends InferClientAPI<Option>,
	Session extends ClientAPI extends {
		getSession: () => Promise<infer Res>
	}
	? Res extends BetterFetchResponse<infer S>
		? S
		: Res
		: never
>(options?: Option, initialValues?: InferPluginsData<Option> & {
	session?: Session
}) {
...

Then using the client as follows:

const authOptions = {
  baseURL: "http://localhost:3000",
  plugins: [organizationClient()],
}

export function App({ initialSession, initialOrgs, children }) {
  const authClient = createAuthClient(authOptions, {
    session: initialSession,
    organizations: initialOrgs,
  });
  return (
    <BetterAuthProvider value={authClient}>
      {children}
    </BetterAuthProvider>
  );
}
<!-- gh-comment-id:2907792088 --> @yerzham commented on GitHub (May 25, 2025): How about defining initial values inferred from all plugins (including user session) when creating an auth client, and passing the client to a root level context provider? Something like this: ```ts type InferPluginsData<Option extends ClientOptions> = Option["plugins"] extends Array<infer Plugin> ? Plugin extends BetterAuthClientPlugin ? Plugin["getAtoms"] extends (fetch: any) => infer Atoms ? Atoms extends Record<string, any> ? { [key in keyof Atoms as key extends string ? key extends `$${string}` ? never : ReturnType<Atoms[key]["get"]> extends { data: any } ? key : never : never]?: | NonNullable<ReturnType<Atoms[key]["get"]>["data"]> | undefined; } : {} : {} : {} : {}; export function createAuthClient< Option extends ClientOptions, ClientAPI extends InferClientAPI<Option>, Session extends ClientAPI extends { getSession: () => Promise<infer Res> } ? Res extends BetterFetchResponse<infer S> ? S : Res : never >(options?: Option, initialValues?: InferPluginsData<Option> & { session?: Session }) { ... ``` Then using the client as follows: ```tsx const authOptions = { baseURL: "http://localhost:3000", plugins: [organizationClient()], } export function App({ initialSession, initialOrgs, children }) { const authClient = createAuthClient(authOptions, { session: initialSession, organizations: initialOrgs, }); return ( <BetterAuthProvider value={authClient}> {children} </BetterAuthProvider> ); } ```
Author
Owner

@ludwigbacklund commented on GitHub (May 26, 2025):

@yerzham A provider approach would definitely work as well!

<!-- gh-comment-id:2908796099 --> @ludwigbacklund commented on GitHub (May 26, 2025): @yerzham A provider approach would definitely work as well!
Author
Owner

@asimaranov commented on GitHub (Jun 4, 2025):

Provider approach looks great

<!-- gh-comment-id:2939682214 --> @asimaranov commented on GitHub (Jun 4, 2025): Provider approach looks great
Author
Owner

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

This is such a core issue and is very problematic why don't the devs notice this

<!-- gh-comment-id:3117679948 --> @SorooshGb commented on GitHub (Jul 25, 2025): This is such a core issue and is very problematic why don't the devs notice this
Author
Owner

@tomtien commented on GitHub (Jul 26, 2025):

Agreed, this would be a great addition to streamlining proper SSR in nextjs

<!-- gh-comment-id:3121061063 --> @tomtien commented on GitHub (Jul 26, 2025): Agreed, this would be a great addition to streamlining proper SSR in nextjs
Author
Owner

@axu6705 commented on GitHub (Aug 12, 2025):

Which version supports it? How to use it?

<!-- gh-comment-id:3179860675 --> @axu6705 commented on GitHub (Aug 12, 2025): Which version supports it? How to use it?
Author
Owner

@stewartcelani commented on GitHub (Sep 19, 2025):

Hi, is this supported yet? Pretty core thing to have working to not get state flickers on hydration.

<!-- gh-comment-id:3311224058 --> @stewartcelani commented on GitHub (Sep 19, 2025): Hi, is this supported yet? Pretty core thing to have working to not get state flickers on hydration.
Author
Owner

@dosubot[bot] commented on GitHub (Dec 19, 2025):

Hi, @ludwigbacklund. I'm Dosu, and I'm helping the better-auth team manage their backlog and am marking this issue as stale.

Issue Summary:

  • You proposed enhancing the React useSession hook to accept initial session data for SSR to avoid unnecessary client fetches and loading states.
  • A proof of concept PR (#2767) was provided to demonstrate this enhancement.
  • Commenters suggested a provider-based approach similar to NextAuth for better SSR support and passing initial session data via context.
  • The idea has received positive feedback for improving UX and SSR handling, with multiple users expressing interest and asking about current support.
  • The issue remains unresolved with no recent updates or merged solutions.

Next Steps:

  • Please let me know if this feature is still relevant to the latest version of better-auth by commenting on this issue to keep the discussion open.
  • If I do not hear back within 7 days, I will automatically close this issue to help keep the backlog manageable.

Thank you for your understanding and contribution!

<!-- gh-comment-id:3675637968 --> @dosubot[bot] commented on GitHub (Dec 19, 2025): Hi, @ludwigbacklund. I'm [Dosu](https://dosu.dev), and I'm helping the better-auth team manage their backlog and am marking this issue as stale. **Issue Summary:** - You proposed enhancing the React useSession hook to accept initial session data for SSR to avoid unnecessary client fetches and loading states. - A proof of concept PR (#2767) was provided to demonstrate this enhancement. - Commenters suggested a provider-based approach similar to NextAuth for better SSR support and passing initial session data via context. - The idea has received positive feedback for improving UX and SSR handling, with multiple users expressing interest and asking about current support. - The issue remains unresolved with no recent updates or merged solutions. **Next Steps:** - Please let me know if this feature is still relevant to the latest version of better-auth by commenting on this issue to keep the discussion open. - If I do not hear back within 7 days, I will automatically close this issue to help keep the backlog manageable. Thank you for your understanding and contribution!
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#9341