diff --git a/src/mcp-prompts/enable-cache-components-prompt.md b/src/mcp-prompts/enable-cache-components-prompt.md index 3d6e515..9de3699 100644 --- a/src/mcp-prompts/enable-cache-components-prompt.md +++ b/src/mcp-prompts/enable-cache-components-prompt.md @@ -549,6 +549,22 @@ Before enabling Cache Components: ⚠️ WARNING: Route Segment Config options are DISABLED with Cache Components Action: Document all locations - will migrate to `"use cache"` + `cacheLife` in Phase 5 +6. **unstable_noStore Usage Check** + Search for all `unstable_noStore()` calls: + - Pattern: `"unstable_noStore"` + - Path: `"app"` + + ⚠️ WARNING: `unstable_noStore()` is INCOMPATIBLE with Cache Components + + **Why:** With Cache Components, everything is dynamic by default. `unstable_noStore()` was used to opt-out of static rendering in the old model, but this is now the default behavior. + + **📖 For detailed migration examples, load:** + ``` + Read resource "nextjs16://migration/examples" (see unstable_noStore Examples section) + ``` + + Action: Document all locations - will remove in Phase 5 + ## PHASE 2: Enable Cache Components Configuration ──────────────────────────────────────── Update the Next.js configuration to enable Cache Components. This phase handles ALL configuration and flag changes needed. @@ -1063,7 +1079,59 @@ For detailed code examples and patterns for each error type, refer to the knowle - `export const preferredRegion` → Keep value but remove the export const - `export const dynamicParams` → Remove, use `generateStaticParams` instead - **Always add migration comments** to document what was removed -- F. Caching strategies → Configure cacheLife() and cacheTag() +- F. unstable_noStore Removal → Remove all `unstable_noStore()` calls + - `unstable_noStore()` → Remove completely (dynamic is now the default) + - No replacement needed - Cache Components makes everything dynamic by default + - If you want to cache specific content, use `"use cache"` instead + - **Add migration comment** explaining the removal +- G. Caching strategies → Configure cacheLife() and cacheTag() + +### Removing unstable_noStore() Usage + +**CRITICAL: unstable_noStore() is incompatible with Cache Components** + +The `unstable_noStore()` API was used in the old caching model to opt-out of static rendering. With Cache Components, this API is no longer needed because: + +1. **Everything is dynamic by default** - No need to opt-out of caching +2. **Use "use cache" to opt-in** - The paradigm is reversed +3. **unstable_noStore() causes errors** - Will break Cache Components behavior + +**📖 For complete migration patterns and code examples, load:** +``` +Read resource "nextjs16://migration/examples" +``` + +Then navigate to the **"unstable_noStore Examples"** section for: +- Basic removal (keep dynamic) +- Migration with Suspense boundary +- Migration to cached content +- Complete before/after examples +- Hybrid approach patterns + +**Quick Migration Steps:** + +1. **Search for usage:** + ```bash + grep -r "unstable_noStore" app/ src/ + ``` + +2. **Remove the import and calls:** + ```typescript + // Remove: import { unstable_noStore } from 'next/cache'; + // Remove: unstable_noStore(); + ``` + +3. **Add migration comment:** + ```typescript + // MIGRATED: Removed unstable_noStore() - dynamic by default with Cache Components + ``` + +4. **Choose migration path:** + - **Keep dynamic (most common):** No changes needed - already dynamic by default + - **Add Suspense:** Wrap in `` for better UX with loading states + - **Cache instead:** Add `"use cache"` if content should actually be cached + +5. **Load the resource for detailed examples** specific to your use case ### Importing and Commenting cacheLife() and cacheTag() - Let Users Decide @@ -1599,6 +1667,7 @@ Report findings in this format: [x] Existing config checked [x] Routes identified: [count] routes [x] Route Segment Config usage documented +[x] unstable_noStore() usage documented ## Phase 2: Configuration & Flags [x] cacheComponents enabled (version-aware: experimental for 16.0.0, root level for canary) @@ -1662,12 +1731,18 @@ Report findings in this format: - [file path]: Removed export const fetchCache, replaced with "use cache" - ... -### F. Cache Tags Added: [count] +### F. unstable_noStore Removals: [count] +- [file path]: Removed unstable_noStore() call (dynamic by default) +- [file path]: Removed unstable_noStore() and added "use cache" instead +- [file path]: Removed unstable_noStore() and added Suspense boundary +- ... + +### G. Cache Tags Added: [count] - [file path]: Added cacheTag('posts') for on-demand revalidation - [file path]: Added cacheTag('products') for granular control - ... -### G. cacheLife Profiles Configured: [count] +### H. cacheLife Profiles Configured: [count] - [file path]: Added cacheLife('minutes') for frequently updating content - [file path]: Added cacheLife('max') for long-lived content - [file path]: Added cacheLife('hours') for hourly updates @@ -1678,6 +1753,7 @@ Report findings in this format: - Total "use cache" directives added: [count] - Total generateStaticParams functions added: [count] - Total Route Segment Config exports removed: [count] +- Total unstable_noStore() calls removed: [count] - Total cache tags added: [count] - Total cacheLife profiles configured: [count] - Total unavailable API errors fixed: [count] diff --git a/src/mcp-prompts/upgrade-nextjs-16-prompt.md b/src/mcp-prompts/upgrade-nextjs-16-prompt.md index 1caafa0..b1501f2 100644 --- a/src/mcp-prompts/upgrade-nextjs-16-prompt.md +++ b/src/mcp-prompts/upgrade-nextjs-16-prompt.md @@ -432,7 +432,18 @@ After the codemod runs, check for any remaining issues it might have missed: - Run with `--experimental-next-config-strip-types` flag to enable native TS for `next.config.ts` - Example: `next dev --experimental-next-config-strip-types` -**P. Other Deprecated Features (WARNINGS - Optional)** +**P. unstable_noStore Migration (If using Cache Components)** + - Search: `grep -r "unstable_noStore" app/ src/` + - Context: If you plan to enable Cache Components (experimental.cacheComponents) + - Action: Remove all `unstable_noStore()` calls - dynamic is the default with Cache Components + - Migration: No replacement needed - everything is dynamic by default + - Alternative: If content should be cached, use `"use cache"` instead + + **📖 For code examples, see: `nextjs16://migration/examples` (unstable_noStore Examples)** + + **Note:** `unstable_noStore()` is only incompatible when Cache Components are enabled. If you're not using Cache Components, you can keep using it. + +**Q. Other Deprecated Features (WARNINGS - Optional)** - `next/legacy/image` → use `next/image` - `images.domains` → use `images.remotePatterns` - `unstable_rootParams()` → being replaced @@ -481,7 +492,15 @@ Based on Phase 3 analysis, apply only the necessary manual fixes: See: `nextjs16://migration/examples` → Middleware to Proxy Examples -**7. Fix edge cases the codemod missed (RARE - only if found in Phase 3 section K)** +**7. Remove unstable_noStore (see section P in Phase 3 - if using Cache Components)** + - Remove all `unstable_noStore()` calls + - Remove imports: `import { unstable_noStore } from 'next/cache'` + - No replacement needed - dynamic by default with Cache Components + - Add migration comments explaining removal + + See: `nextjs16://migration/examples` → unstable_noStore Examples + +**8. Fix edge cases the codemod missed (RARE - only if found in Phase 3 section K)** See: `nextjs16://migration/examples` → Async API Migration Examples @@ -553,7 +572,8 @@ Issues the codemod couldn't handle: [ ] M. revalidateTag API changes [ ] N. Middleware to Proxy migration (rename middleware.ts → proxy.ts and config properties) [ ] O. Build and dev improvements reviewed (informational) -[ ] P. Deprecated features to update +[ ] P. unstable_noStore removal (if using Cache Components) +[ ] Q. Deprecated features to update ## Files Requiring Manual Changes - path/to/file1.ts (reason - not handled by codemod) diff --git a/src/mcp-resources/nextjs-16-migration-examples.md b/src/mcp-resources/nextjs-16-migration-examples.md index af14809..f0ec4a8 100644 --- a/src/mcp-resources/nextjs-16-migration-examples.md +++ b/src/mcp-resources/nextjs-16-migration-examples.md @@ -67,6 +67,7 @@ Complete reference and code examples for migrating to Next.js 16 stable. 5. [Async API Migration Examples](#async-api-migration-examples) 6. [Cache Invalidation Examples](#cache-invalidation-examples) 7. [Middleware to Proxy Examples](#middleware-to-proxy-examples) +8. [unstable_noStore Examples](#unstable_nostore-examples) --- @@ -598,6 +599,164 @@ module.exports = { --- +## unstable_noStore Examples + +**IMPORTANT:** `unstable_noStore()` is only incompatible when Cache Components are enabled. If you're not using `experimental.cacheComponents`, you can continue using it. + +### Search for Usage + +```bash +# Find all unstable_noStore usage +grep -r "unstable_noStore" app/ src/ +``` + +### Basic Removal (Keep Dynamic) + +```diff +- import { unstable_noStore } from 'next/cache' + + export default async function Page() { +- unstable_noStore() // Opt-out of static rendering ++ // MIGRATED: Removed unstable_noStore() - dynamic by default with Cache Components ++ // This component executes on every request (dynamic behavior) + + const data = await fetch('https://api.example.com/data') + return
{data}
+ } +``` + +### Migration with Suspense Boundary + +```diff +- import { unstable_noStore } from 'next/cache' ++ import { Suspense } from 'react' + + export default async function Page() { +- unstable_noStore() ++ // MIGRATED: Removed unstable_noStore() and added Suspense boundary ++ // Dynamic content wrapped in Suspense for better UX ++ return ( ++ }> ++ ++ ++ ) ++ } + ++ async function DynamicContent() { ++ // No unstable_noStore() needed - dynamic by default + const data = await fetch('https://api.example.com/data') + return
{data}
+ } +``` + +### Migration to Cached Content + +If you realize the content should actually be cached: + +```diff +- import { unstable_noStore } from 'next/cache' ++ import { cacheLife } from 'next/cache' + + export default async function Page() { +- unstable_noStore() // Was preventing caching ++ "use cache" ++ // MIGRATED: Removed unstable_noStore() - decided to cache this content instead ++ // DECISION: Content changes hourly, cacheable to reduce server load ++ ++ // Uncomment to enable time-based revalidation: ++ // cacheLife('hours') + + const data = await fetch('https://api.example.com/data') + return
{data}
+ } +``` + +### Complete Example: Page with Multiple Components + +**Before:** +```typescript +// app/dashboard/page.tsx +import { unstable_noStore } from 'next/cache' + +export default async function Dashboard() { + unstable_noStore() // Make everything dynamic + + const user = await getCurrentUser() + const stats = await getStats() + const settings = await getSettings() + + return ( +
+
+ + +
+ ) +} +``` + +**After (Hybrid Approach):** +```typescript +// app/dashboard/page.tsx +import { Suspense } from 'react' +import { cacheLife } from 'next/cache' + +// MIGRATED: Removed unstable_noStore() +// Now using hybrid approach - cache static parts, dynamic user content +export default async function Dashboard() { + return ( +
+ + }> + + + }> + + +
+ ) +} + +async function CachedHeader() { + "use cache" + // cacheLife('hours') // Uncomment to enable revalidation + + // Static header - same for all users + const settings = await getGlobalSettings() + return
+} + +async function DynamicStats() { + // Dynamic per user - no unstable_noStore needed + const user = await getCurrentUser() + const stats = await getStats(user.id) + return +} + +async function DynamicSettings() { + // Dynamic per user - no unstable_noStore needed + const user = await getCurrentUser() + const settings = await getUserSettings(user.id) + return +} +``` + +### Why This Migration Matters + +**Old Caching Model (Next.js 15 and earlier):** +- Everything was static by default +- `unstable_noStore()` opted out of caching +- Used to make routes dynamic + +**New Cache Components Model (Next.js 16 with cacheComponents):** +- Everything is dynamic by default +- `"use cache"` opts into caching +- `unstable_noStore()` is redundant and causes errors + +**Key Insight:** The paradigm is reversed. You no longer need to opt-out of caching; instead, you opt-in to caching only where it makes sense. + +--- + ## ViewTransition API Migration ### Import Rename