Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 79 additions & 3 deletions src/mcp-prompts/enable-cache-components-prompt.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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 `<Suspense>` 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

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand All @@ -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]
Expand Down
26 changes: 23 additions & 3 deletions src/mcp-prompts/upgrade-nextjs-16-prompt.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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)
Expand Down
159 changes: 159 additions & 0 deletions src/mcp-resources/nextjs-16-migration-examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

---

Expand Down Expand Up @@ -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 <div>{data}</div>
}
```

### 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 (
+ <Suspense fallback={<Loading />}>
+ <DynamicContent />
+ </Suspense>
+ )
+ }

+ async function DynamicContent() {
+ // No unstable_noStore() needed - dynamic by default
const data = await fetch('https://api.example.com/data')
return <div>{data}</div>
}
```

### 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 <div>{data}</div>
}
```

### 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 (
<div>
<Header user={user} />
<Stats data={stats} />
<Settings data={settings} />
</div>
)
}
```

**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 (
<div>
<CachedHeader />
<Suspense fallback={<StatsSkeleton />}>
<DynamicStats />
</Suspense>
<Suspense fallback={<SettingsSkeleton />}>
<DynamicSettings />
</Suspense>
</div>
)
}

async function CachedHeader() {
"use cache"
// cacheLife('hours') // Uncomment to enable revalidation

// Static header - same for all users
const settings = await getGlobalSettings()
return <Header settings={settings} />
}

async function DynamicStats() {
// Dynamic per user - no unstable_noStore needed
const user = await getCurrentUser()
const stats = await getStats(user.id)
return <Stats data={stats} />
}

async function DynamicSettings() {
// Dynamic per user - no unstable_noStore needed
const user = await getCurrentUser()
const settings = await getUserSettings(user.id)
return <Settings data={settings} />
}
```

### 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
Expand Down