This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
frontendcritical PriorityID: rr7-hydration-single-fetch-boundaries

React Router 7 Framework Mode Hydration & Single-Fetch Data Boundaries

Enforces strict architectural boundaries for React Router 7 Framework Mode, governing typegen route modules, Single Fetch streaming contracts, and clientLoader execution lifecycles. Prevents hydration mismatches, double-fetching loops, and serialization bugs caused by legacy Remix primitives and unflagged client hydration loaders.

Prohibited Anti-Pattern: Using legacy Remix json/defer APIs or unflagged clientLoader implementations that trigger hydration desync and streaming bottlenecks.

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: React Router 7 Framework Mode Hydration & Single-Fetch Data Boundaries - Enforces strict architectural boundaries for React Router 7 Framework Mode, governing typegen route modules, Single Fetch streaming contracts, and clientLoader execution lifecycles. Prevents hydration mismatches, double-fetching loops, and serialization bugs caused by legacy Remix primitives and unflagged client hydration loaders.
globs: app/**/+types/**/*.ts, app/routes/**/*.{ts,tsx}, app/root.tsx
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/rr7-hydration-single-fetch-boundaries"
---

# React Router 7 Framework Mode Hydration & Single-Fetch Data Boundaries

> **Severity**: CRITICAL | **Category**: frontend
> **Anti-Pattern Warning**: Using legacy Remix json/defer APIs or unflagged clientLoader implementations that trigger hydration desync and streaming bottlenecks.

## System Constraints
You are a Principal Software Architect enforcing React Router 7 Framework Mode standards. Enforce strict adherence to Single Fetch semantics, the typegen contract via `./+types/*`, and explicit hydration boundaries. Ban deprecated Remix primitives (`defer`, `json`) in favor of direct naked returns with turbo-stream serialization. Require explicit `clientLoader.hydrate = true` annotations whenever client-side loaders must intercept SSR hydration.

## Strict Guidelines
- Engineers MUST ALWAYS import route module types strictly from `./+types/[route_file_name]` (e.g., `import type { Route } from './+types/dashboard'`) to guarantee full type safety across params, loaderData, and actionData.
- Engineers MUST NOT use deprecated `json()` or `defer()` helpers in React Router 7 Framework Mode; Single Fetch natively serializes raw objects, Promises, Dates, Maps, Sets, and Errors via turbo-stream.
- Engineers MUST set `clientLoader.hydrate = true` on any route defining a `clientLoader` if that loader is required to execute during initial document hydration; otherwise, clientLoader runs solely on subsequent client navigations.
- Code MUST structure streaming by awaiting critical path data in the server loader while returning naked, unresolved promises for non-critical deferred data, consuming them downstream via `<Suspense>` and `<Await>`.
- Services MUST NOT construct manual `Response` envelopes for domain data within loaders unless intentionally setting custom HTTP headers or status codes.
- Components NEVER access unresolved loader promises without wrapping the access inside a React Router `<Await resolve={...}>` component bounded by a `<Suspense>` boundary.

## Bad vs Good Implementations
### Single Fetch Streaming and Typegen Route Module Contract

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: React Router 7 Framework Mode deprecates `defer()` and `json()`. Wrapping payloads in `defer()` or manual `Response` wrappers prevents turbo-stream from serializing native structures efficiently. Bypassing `./+types` breaks the compile-time typegen contract, forcing unsafe type assertions (`as LoaderData`).
```typescript
// DEPRECATED / BROKEN: Using Remix legacy defer/json and manual loader types
import { defer } from "@remix-run/node"; // Anti-pattern in RR7
import { useLoaderData } from "@remix-run/react";

interface LoaderData {
  user: { id: string; name: string };
  analytics: Promise<{ views: number }>;
}

export async function loader(): Promise<Response> {
  const user = await fetchUser();
  const analytics = fetchAnalytics(); // Deferred promise

  // Legacy defer utility breaks RR7 Single Fetch streaming pipeline
  return defer({ user, analytics });
}

export default function RouteComponent() {
  const data = useLoaderData() as LoaderData; // Fragile manual cast
  return <div>{data.user.name}</div>;
}
```

#### Production Standard (Correct)
> **Standard**: Employs `./+types/dashboard` for compile-time generated typing of `Route.LoaderArgs` and `Route.ComponentProps`. Utilizes native Single Fetch streaming by returning raw promises alongside awaited data without obsolete `defer()` wrappers.
```typescript
// PRODUCTION STANDARD: React Router 7 Framework Mode Single Fetch + Typegen
import { Await } from "react-router";
import { Suspense } from "react";
import type { Route } from "./+types/dashboard";
import { fetchUser, fetchAnalytics } from "~/services/telemetry.server";

export async function loader({ params }: Route.LoaderArgs) {
  // Critical path: awaited blocking data
  const user = await fetchUser(params.id);
  // Non-critical: unawaited naked Promise streamed via turbo-stream
  const analyticsPromise = fetchAnalytics(params.id);

  return {
    user,
    analytics: analyticsPromise,
  };
}

export default function DashboardRoute({ loaderData }: Route.ComponentProps) {
  return (
    <main>
      <h1>Welcome, {loaderData.user.name}</h1>
      <Suspense fallback={<p>Loading analytics stream...</p>}>
        <Await resolve={loaderData.analytics}>
          {(analytics) => <span>Page Views: {analytics.views}</span>}
        </Await>
      </Suspense>
    </main>
  );
}
```

### Client Loader Hydration Boundary with Cache Strategy

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Without `clientLoader.hydrate = true`, the client loader is completely skipped during the initial SSR hydration phase. The server render hydrates with initial server payload, but any custom client-side cache population or hydration transforms fail to execute until a subsequent client navigation occurs.
```typescript
// BROKEN: clientLoader without hydrate flag leads to cache desync and UI flash
import type { Route } from "./+types/profile";
import { clientCache } from "~/cache.client";

export async function loader({ params }: Route.LoaderArgs) {
  return { profile: await fetchRemoteProfile(params.id) };
}

// Missing clientLoader.hydrate = true
export async function clientLoader({ serverLoader }: Route.ClientLoaderArgs) {
  const cached = clientCache.get("profile");
  if (cached) return { profile: cached };
  
  const fresh = await serverLoader();
  clientCache.set("profile", fresh.profile);
  return fresh;
}
```

#### Production Standard (Correct)
> **Standard**: Setting `clientLoader.hydrate = true` guarantees that the client cache policy intercepts document hydration correctly. Declaring `HydrateFallback` provides an explicit loading boundary if `clientLoader` needs to resolve asynchronous client-side operations prior to first paint.
```typescript
// PRODUCTION STANDARD: Explicit Hydration Contract with clientLoader
import type { Route } from "./+types/profile";
import { fetchRemoteProfile } from "~/services/profile.server";
import { clientCache } from "~/services/cache.client";

export async function loader({ params }: Route.LoaderArgs) {
  return { profile: await fetchRemoteProfile(params.id) };
}

export async function clientLoader({ serverLoader, params }: Route.ClientLoaderArgs) {
  const cacheKey = `profile:${params.id}`;
  const cached = clientCache.get(cacheKey);
  if (cached) {
    return { profile: cached };
  }

  const serverData = await serverLoader();
  clientCache.set(cacheKey, serverData.profile);
  return serverData;
}

// Mandatory: Instructs React Router to execute clientLoader on initial document hydration
clientLoader.hydrate = true as const;

export function HydrateFallback() {
  return <div className="skeleton-loader">Hydrating Profile Boundary...</div>;
}
```

Recommended MCP Servers (mcp-serverlist.com)

Equip agent with system tools to verify code for this stack.

Recommended Agent Skills (askills.dev)

Ready-to-use executable skill functions tailored to this stack.

Architectural Specification & Invariant Rationale

Architectural Invariant Design: React Router 7 Framework Mode Hydration & Single-Fetch Data Boundaries

React Router 7 Framework Mode Hydration & Single-Fetch Data Boundaries defines an industrial-grade behavioral standard for frontend engineering. Enforces strict architectural boundaries for React Router 7 Framework Mode, governing typegen route modules, Single Fetch streaming contracts, and clientLoader execution lifecycles. Prevents hydration mismatches, double-fetching loops, and serialization bugs caused by legacy Remix primitives and unflagged client hydration loaders. Modern software architectures require strict adherence to deterministic patterns to guarantee high availability, maintainability, and zero security vulnerabilities.

Framework Paradigm Shift & Drift MechanicsLLMs are trained on millions of open-source repositories containing outdated code, legacy idioms, and unpatched antipatterns. When coding assistants generate implementations for this stack, they default to common statistical tokens: Using legacy Remix json/defer APIs or unflagged clientLoader implementations that trigger hydration desync and streaming bottlenecks. Without an explicit system instruction file, developers spend hours debugging silent failures.
Failure Modes & Production Blast Radius

Hazard Analysis: What Breaks Without This Rule

The following failure modes have been cataloged from hundreds of hours of production code reviews where AI assistants produced non-compliant implementations:

Failure ModeAI Symptom (The Anti-Pattern)SeverityProduction Impact & Remedy
AI Hallucination & Deprecation DriftUsing legacy Remix json/defer APIs or unflagged clientLoader implementations that trigger hydration desync and streaming bottlenecks.Critical
Violating this industrial standard introduces regression bugs, security risks, and unexpected runtime failures in production.
Enforce explicit behavioral system directives across all AI coding assistants in your repository.
Silent Architecture InconsistencyAI assistants produce mixed paradigms across files, creating fragmented codebase conventions.Medium
Increases cognitive load during code reviews and leads to maintenance debt across engineering teams.
Pin project conventions in .cursor/rules, CLAUDE.md, and AGENTS.md so all team agents follow identical guardrails.
Architectural Directives in Detail

Step-by-Step Production Directives

Each rule constraint below is injected into the AI agent's system prompt to establish deterministic boundaries:

1

Engineers MUST ALWAYS import route module types strictly from `./+types/[route_file_name]` (e.g., `import type { Route } from './+types/dashboard'`) to guarantee full type safety across params, loaderData, and actionData.

Engineers MUST ALWAYS import route module types strictly from `./+types/[route_file_name]` (e.g., `import type { Route } from './+types/dashboard'`) to guarantee full type safety across params, loaderData, and actionData.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
2

Engineers MUST NOT use deprecated `json()` or `defer()` helpers in React Router 7 Framework Mode

Engineers MUST NOT use deprecated `json()` or `defer()` helpers in React Router 7 Framework Mode; Single Fetch natively serializes raw objects, Promises, Dates, Maps, Sets, and Errors via turbo-stream.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
3

Engineers MUST set `clientLoader.hydrate = true` on any route defining a `clientLoader` if that loader is required to execute during initial document hydration

Engineers MUST set `clientLoader.hydrate = true` on any route defining a `clientLoader` if that loader is required to execute during initial document hydration; otherwise, clientLoader runs solely on subsequent client navigations.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
4

Code MUST structure streaming by awaiting critical path data in the server loader while returning naked, unresolved promises for non-critical deferred data, consuming them downstream via `<Suspense>` and `<Await>`.

Code MUST structure streaming by awaiting critical path data in the server loader while returning naked, unresolved promises for non-critical deferred data, consuming them downstream via `<Suspense>` and `<Await>`.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
5

Services MUST NOT construct manual `Response` envelopes for domain data within loaders unless intentionally setting custom HTTP headers or status codes.

Services MUST NOT construct manual `Response` envelopes for domain data within loaders unless intentionally setting custom HTTP headers or status codes.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
6

Components NEVER access unresolved loader promises without wrapping the access inside a React Router `<Await resolve={...}>` component bounded by a `<Suspense>` boundary.

Components NEVER access unresolved loader promises without wrapping the access inside a React Router `<Await resolve={...}>` component bounded by a `<Suspense>` boundary.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
Technical Questions & Answers

Frequently Asked Technical Questions

Common questions developers face when configuring AI coding assistants for this stack:

Q:Why is React Router 7 Framework Mode Hydration & Single-Fetch Data Boundaries critical for AI coding assistants?

Enforces strict architectural boundaries for React Router 7 Framework Mode, governing typegen route modules, Single Fetch streaming contracts, and clientLoader execution lifecycles. Prevents hydration mismatches, double-fetching loops, and serialization bugs caused by legacy Remix primitives and unflagged client hydration loaders. Without explicit behavioral boundaries, AI coding assistants (Cursor, Claude Code, Windsurf, Codex) rely on training data averages, which frequently produce deprecated, inefficient, or vulnerable code patterns.

Q:How does adopting this rule prevent AI hallucinations?

This rule explicitly declares what the AI must avoid (Using legacy Remix json/defer APIs or unflagged clientLoader implementations that trigger hydration desync and streaming bottlenecks.) and prescribes verified positive examples. Grounding the LLM with negative and positive pairs eliminates guesswork.

Q:Which AI coding environments are supported?

This specification is multi-platform compatible: Cursor (.cursor/rules/*.mdc & .cursorrules), Anthropic Claude Code (CLAUDE.md), Windsurf (.windsurfrules), Codex / Cline (AGENTS.md), and GitHub Copilot (.github/copilot-instructions.md).

Q:Can I combine this rule with other technology stacks?

Yes. Use the Interactive Stack Builder or download an Agent Pack to merge this rule with other frontend, backend, database, security, and DevOps rules without syntax collision.

Open Specification · CC BY 4.0·Free for Personal, Team & Commercial In-Repo Use

Citation & Open Source Attribution Guidelines

This specification is licensed under Creative Commons Attribution 4.0 International (CC BY 4.0). You are completely free to adapt and share this rule in your workspace. If citing, including in public AI benchmark datasets, or redistributing, attribution to AgentRules.org is required.

Related FRONTEND Rules

View all rules →
frontend
119

SolidStart 1.0 Server Functions & Async Boundaries Production Standard

SolidStart 1.0 relies on the Vinxi bundler to split `server$` closures into independent HTTP POST RPC endpoints. Direct lexical closure over client signals within `server$` scopes or failure to demarcate async boundaries with `<Suspense>` causes silent serialization failures, client-bundle secret leaks, and SSR hydration mismatches. Enforcing strict parameter passing, runtime input validation, and Solid async primitives maintains security and fine-grained reactivity across network boundaries.

frontend
119

Astro 5 Actions & Content Layer Production Standard

Enforces strict type safety and architectural correctness for Astro 5 Server Actions and the zero-waterfall Content Layer API. Prevents runtime contract mismatches, hydration mismatches, and unhandled mutation exceptions across dynamic and prerendered boundaries. Failure to follow these patterns leads to silent data fetching waterfalls, build-time cache corruptions, and unhandled server action exceptions.

frontend
51

Nuxt 4 Nitro Server Engine & Shared Directory Production Standard

Nuxt 4 enforces strict boundary segregation between client UI in the app/ directory, backend endpoints in server/, and universal contracts in shared/. Violating cross-boundary isolation or maintaining module-scoped state in Nitro server handlers causes catastrophic cross-request data corruption and hydration mismatches under concurrent production traffic. Architects must enforce request-isolated H3 event contexts, universal serialization schemas, and strict path-alias boundaries.

1 Rule in Stack

React