This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
frontendcritical PriorityID: nextjs-15-dynamic-io-cache-life-invariants

Next.js 15 Dynamic I/O and Cache-Life Invalidation Standard

Governs deterministic `use cache` profiles and explicit `cacheTag` lifecycles under React 19 Dynamic I/O (`experimental.dynamicIO: true`). Eliminates silent stale data cross-contamination and un-tracked runtime dynamic leaks across hybrid streaming routes by enforcing strict isolation of caching scopes and revalidation boundaries.

Prohibited Anti-Pattern: Implicit Caching via Ambiguous Dynamic Access and Missing Invalidation Tags Under Dynamic I/O

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: Next.js 15 Dynamic I/O and Cache-Life Invalidation Standard - Governs deterministic `use cache` profiles and explicit `cacheTag` lifecycles under React 19 Dynamic I/O (`experimental.dynamicIO: true`). Eliminates silent stale data cross-contamination and un-tracked runtime dynamic leaks across hybrid streaming routes by enforcing strict isolation of caching scopes and revalidation boundaries.
globs: app/**/*.{ts,tsx}, src/app/**/*.{ts,tsx}, lib/data/**/*.{ts,tsx}, src/lib/data/**/*.{ts,tsx}
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/nextjs-15-dynamic-io-cache-life-invariants"
---

# Next.js 15 Dynamic I/O and Cache-Life Invalidation Standard

> **Severity**: CRITICAL | **Category**: frontend
> **Anti-Pattern Warning**: Implicit Caching via Ambiguous Dynamic Access and Missing Invalidation Tags Under Dynamic I/O

## System Constraints
You are a Principal Software Architect enforcing deterministic Next.js 15 Dynamic I/O and React 19 cache invariants. Dynamic I/O fundamentally alters runtime semantics: any access to runtime cookies, headers, params, or searchParams flags a branch as dynamic unless explicitly enclosed within a `use cache` directive with explicit `cacheLife` and `cacheTag` identifiers. You must enforce strict boundaries between dynamic context access and cached data fetchers, prohibiting ambient leaks, missing cache tags, and untagged cacheLife defaults.

## Strict Guidelines
- Engineers MUST ALWAYS declare 'use cache' at function or file scope when caching queries, paired with explicit `cacheLife('profile')` and `cacheTag('entity:id')` declarations inside the cached block.
- Engineers MUST NOT read dynamic runtime state (`cookies()`, `headers()`, `searchParams`) inside a function or component flagged with 'use cache'; dynamic parameters must be resolved externally and passed as explicit, serializable primitive arguments.
- Engineers MUST NEVER invoke `revalidateTag` with arbitrary string literals; tags MUST be derived through a strictly typed domain tag catalog (e.g., `TAGS.user(id)`).
- Components wrapping dynamic I/O segments with React Suspense MUST establish granular fallback boundaries to prevent dynamic de-opt bubbling up to parent cached layout branches.
- Cached data access functions SHOULD define explicit fallback profiles in `next.config.ts` cacheLife definitions instead of relying on implicit framework defaults.

## Bad vs Good Implementations
### Isolated Data Cache Function with Explicit Tagging vs Leaked Request Headers

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Accessing `cookies()` directly inside a `'use cache'` scope violates dynamic I/O isolation. It mixes request-time ambient context with persistent cached computation, destabilizing cache keys and preventing deterministic tag-based revalidation via `revalidateTag`.
```typescript
import { cookies } from 'next/headers';

// ANTI-PATTERN: Accessing runtime headers/cookies directly inside a cached function
// Under Dynamic I/O, this throws runtime errors or creates un-revalidatable global pollution
export async function getProductData(productId: string) {
  'use cache';
  const cookieStore = await cookies();
  const currency = cookieStore.get('currency')?.value ?? 'USD';
  
  const res = await fetch(`https://api.internal/products/${productId}?currency=${currency}`);
  return res.json();
}
```

#### Production Standard (Correct)
> **Standard**: Dynamic properties (`currency`) are extracted outside the cache boundary and passed as deterministic serialized inputs. The function explicitly declares its `cacheLife` SLA and registers atomic domain `cacheTag` entries for precise invalidation.
```typescript
import { unstable_cacheLife as cacheLife, unstable_cacheTag as cacheTag } from 'next/cache';

interface ProductQuery {
  productId: string;
  currency: string;
}

// PRODUCTION FIX: Pure serialized parameters with explicit lifecycle and domain tags
export async function getProductData({ productId, currency }: ProductQuery) {
  'use cache';
  cacheLife('hours');
  cacheTag(`product:${productId}`, `currency:${currency}`);

  const res = await fetch(`https://api.internal/products/${productId}?currency=${currency}`, {
    headers: { 'Accept': 'application/json' }
  });
  
  if (!res.ok) {
    throw new Error(`Failed to fetch product: ${productId} status: ${res.status}`);
  }
  
  return res.json();
}
```

### Dynamic Component Encapsulation via Explicit Suspense Stream Boundaries

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Awaiting cookies and dynamic params at the root layout/page level without Suspense forces the entire render tree to de-opt to on-demand execution, discarding static shell streaming benefits provided by Next.js 15 Dynamic I/O.
```typescript
import { cookies } from 'next/headers';
import { getProductData } from '@/lib/data/product';

// ANTI-PATTERN: Unprotected dynamic access at page root un-caches whole route
export default async function ProductPage({ params }: { params: Promise<{ id: string }> }) {
  const { id } = await params;
  const cookieStore = await cookies();
  const currency = cookieStore.get('currency')?.value ?? 'USD';
  
  const data = await getProductData({ productId: id, currency });
  
  return <div>{data.title} - {data.price}</div>;
}
```

#### Production Standard (Correct)
> **Standard**: Dynamic runtime dependencies are strictly encapsulated within an isolated component wrapped in a `<Suspense>` boundary. The static shell streams immediately under Dynamic I/O, and the dynamic component streams concurrently.
```typescript
import { Suspense } from 'react';
import { cookies } from 'next/headers';
import { getProductData } from '@/lib/data/product';

interface PageProps {
  params: Promise<{ id: string }>;
}

async function DynamicProductDetails({ id }: { id: string }) {
  const cookieStore = await cookies();
  const currency = cookieStore.get('currency')?.value ?? 'USD';
  const data = await getProductData({ productId: id, currency });
  
  return <div>{data.title} - {data.price}</div>;
}

// PRODUCTION FIX: Layout/Page remains statically streamable with dynamic hole
export default async function ProductPage({ params }: PageProps) {
  const { id } = await params;
  
  return (
    <main className="container mx-auto p-4">
      <header className="border-b pb-4">Product Overview</header>
      <Suspense fallback={<div className="animate-pulse h-16 bg-muted rounded" />}>
        <DynamicProductDetails id={id} />
      </Suspense>
    </main>
  );
}
```

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: Next.js 15 Dynamic I/O and Cache-Life Invalidation Standard

Next.js 15 Dynamic I/O and Cache-Life Invalidation Standard defines an industrial-grade behavioral standard for frontend engineering. Governs deterministic `use cache` profiles and explicit `cacheTag` lifecycles under React 19 Dynamic I/O (`experimental.dynamicIO: true`). Eliminates silent stale data cross-contamination and un-tracked runtime dynamic leaks across hybrid streaming routes by enforcing strict isolation of caching scopes and revalidation boundaries. 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: Implicit Caching via Ambiguous Dynamic Access and Missing Invalidation Tags Under Dynamic I/O 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 DriftImplicit Caching via Ambiguous Dynamic Access and Missing Invalidation Tags Under Dynamic I/OCritical
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 declare 'use cache' at function or file scope when caching queries, paired with explicit `cacheLife('profile')` and `cacheTag('entity

Engineers MUST ALWAYS declare 'use cache' at function or file scope when caching queries, paired with explicit `cacheLife('profile')` and `cacheTag('entity:id')` declarations inside the cached block.

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 read dynamic runtime state (`cookies()`, `headers()`, `searchParams`) inside a function or component flagged with 'use cache'

Engineers MUST NOT read dynamic runtime state (`cookies()`, `headers()`, `searchParams`) inside a function or component flagged with 'use cache'; dynamic parameters must be resolved externally and passed as explicit, serializable primitive arguments.

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 NEVER invoke `revalidateTag` with arbitrary string literals

Engineers MUST NEVER invoke `revalidateTag` with arbitrary string literals; tags MUST be derived through a strictly typed domain tag catalog (e.g., `TAGS.user(id)`).

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

Components wrapping dynamic I/O segments with React Suspense MUST establish granular fallback boundaries to prevent dynamic de-opt bubbling up to parent cached layout branches.

Components wrapping dynamic I/O segments with React Suspense MUST establish granular fallback boundaries to prevent dynamic de-opt bubbling up to parent cached layout branches.

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

Cached data access functions SHOULD define explicit fallback profiles in `next.config.ts` cacheLife definitions instead of relying on implicit framework defaults.

Cached data access functions SHOULD define explicit fallback profiles in `next.config.ts` cacheLife definitions instead of relying on implicit framework defaults.

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 Next.js 15 Dynamic I/O and Cache-Life Invalidation Standard critical for AI coding assistants?

Governs deterministic `use cache` profiles and explicit `cacheTag` lifecycles under React 19 Dynamic I/O (`experimental.dynamicIO: true`). Eliminates silent stale data cross-contamination and un-tracked runtime dynamic leaks across hybrid streaming routes by enforcing strict isolation of caching scopes and revalidation boundaries. 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 (Implicit Caching via Ambiguous Dynamic Access and Missing Invalidation Tags Under Dynamic I/O) 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

Next.js