Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/get-convex/convex-react-query/llms.txt

Use this file to discover all available pages before exploring further.

ConvexQueryClient supports SSR by using ConvexHttpClient to fetch query results on the server. On the client, the WebSocket subscription takes over and keeps data live.

How it works

  • On the server (typeof window === "undefined"), convexQueryClient.queryFn() uses ConvexHttpClient to make HTTP requests instead of opening a WebSocket subscription.
  • By default, SSR fetches use consistent mode: multiple queries are fetched from the same logical database snapshot. This prevents inconsistencies when your UI joins data across multiple queries.
  • You can opt out with dangerouslyUseInconsistentQueriesDuringSSR: true for a faster but potentially inconsistent SSR render.

Basic SSR setup

Construct ConvexQueryClient with a serverFetch option to supply a custom fetch implementation for server-side HTTP requests.
import { ConvexQueryClient } from "@convex-dev/react-query";
import { ConvexReactClient } from "convex/react";

const convexClient = new ConvexReactClient(process.env.CONVEX_URL!);
const convexQueryClient = new ConvexQueryClient(convexClient, {
  // Provide a custom fetch for server-only usage
  serverFetch: fetch,
});

Consistent vs. inconsistent SSR queries

// Default: consistent mode — two round trips, consistent snapshot
const convexQueryClient = new ConvexQueryClient(convexClient);

Why consistent queries matter

When your React code joins data from multiple queries, both queries must reflect the same database state. In consistent mode, Convex guarantees this on the server.
// These two queries will always be from the same database snapshot in consistent mode.
// In inconsistent mode, they could disagree (a favChannelId with no matching channel).
const channels = useQuery(convexQuery(api.channels.all, {}));
const favChannelIds = useQuery(convexQuery(api.channels.favIds, {}));
const favChannels = channels && favChannelIds
  ? favChannelIds.map((id) => channels[id])
  : [];
In inconsistent mode, favChannelIds could reference channel IDs that don’t yet exist in channels because the two HTTP requests may have hit different database snapshots.

Using with TanStack Start

In TanStack Start, use createServerOnlyFn to ensure the serverFetch implementation is never bundled into the client.
import { createServerOnlyFn } from "@tanstack/start";

const convexQueryClient = new ConvexQueryClient(convexClient, {
  serverFetch: createServerOnlyFn().handler(fetch),
});
The serverFetch option should be server-only code. In TanStack Start, wrap it with createServerOnlyFn to avoid bundling it on the client.
During client-side navigation, the WebSocket subscription is used — SSR only affects the initial server render.