nextjs - ✅(Solved) Fix `updateTag` invalidates all cached components for a product when only one tag should be invalidated (Vercel only) [1 pull requests, 3 comments, 3 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
vercel/next.js#91368Fetched 2026-04-08 02:02:12
View on GitHub
Comments
3
Participants
3
Timeline
11
Reactions
0
Author
Timeline (top)
commented ×3closed ×1cross-referenced ×1issue_type_added ×1

Fix Action

Fixed

PR fix notes

PR #1: fix: remove nested use cache to prevent tag cross-invalidation on Vercel

Description (problem / solution / changelog)

Summary

Fixes the issue where updateTag invalidates all cached field components for a product on Vercel, when only one tag should be invalidated (vercel/next.js#91368).

Root cause

Both the component-level functions (ProductName, ProductDescription, etc.) and the inner getProductField query function had "use cache" with cacheTag. On Vercel's Data Cache, when an outer "use cache" function calls an inner "use cache" function, the inner tags propagate through shared dependencies. Since every field component calls the same getProductField function, invalidating any one tag cascades to all components for that product.

This also explains the note in the issue: "in very rare occasions, all fields being revalidated can also happen in a local production build on the first data mutation" — build-time cache entries share the same dependency graph, which breaks on the first mutation.

Changes

  • Remove "use cache" and cacheTag from getProductField — caching now happens exclusively at the component level, where each component has its own independent cache boundary and tag. No more nested cache boundaries means no tag cross-contamination.
  • Fix tag mismatch for categoryFIELD_CACHE_TAGS.category produced badge-{id} but ProductBadge registers category-{id}, so category edits never invalidated the badge component.

Before / After

ScenarioBefore (Vercel)After
Edit only nameAll fields highlight (name, description, badge, brand, rating, price)Only name highlights
Edit categoryBadge never updates (tag mismatch)Badge correctly updates

Test plan

  • Deploy to Vercel with Turso env vars
  • Edit a single field (e.g. name) on any product card
  • Verify only the edited field shows the blue update highlight
  • Verify other fields retain their cached updatedAt (tooltip shows old timestamp)
  • Edit category and verify the badge component updates
  • Confirm local bun run dev still works correctly

Changed files

  • src/server/actions/update-product.ts (modified, +1/-1)
  • src/server/queries/products.ts (modified, +1/-7)

Code Example

git clone https://github.com/Thakisis/cache-components
cd cache-components
bun install

---

TURSO_DATABASE_URL=your_turso_url
TURSO_AUTH_TOKEN=your_turso_token

---

bun run db:migrate
bun run db:seed

---

bun run dev

---

// getProductField in server/queries/products.ts
export async function getProductField(id, field) {
  "use cache";
  cacheTag(`${field}-${id}`);
  // ...
}

---

// Only the changed field tag is added
const FIELD_CACHE_TAGS = {
  name: (id) => `name-${id}`,
  description: (id) => `description-${id}`,
  // ...
};
 
for (const field of changedFields) {
  const tagFn = FIELD_CACHE_TAGS[field];
  if (tagFn) tagsToRevalidate.add(tagFn(original.id));
}
 
for (const tag of tagsToRevalidate) {
  updateTag(tag); // only one tag, e.g. "name-5"
}

---

- **Next.js:** 16.1.6
- **Runtime:** Vercel (production) vs local (Windows, Bun)
- **Database:** Turso (LibSQL) + Drizzle ORM
- **Build:** performed on Windows with Bun
RAW_BUFFERClick to expand / collapse

Link to the code that reproduces this issue

https://github.com/Thakisis/cache-components

To Reproduce

Prerequisites

  • A Turso database (free tier works). Create a database and get your TURSO_DATABASE_URL and TURSO_AUTH_TOKEN.
  • Bun installed
  • A Vercel account

Setup

git clone https://github.com/Thakisis/cache-components
cd cache-components
bun install

Create a .env.local file:

TURSO_DATABASE_URL=your_turso_url
TURSO_AUTH_TOKEN=your_turso_token

Run migrations and seed the database:

bun run db:migrate
bun run db:seed

Local (works correctly)

bun run dev
  1. Open the app — 10 product cards are displayed
  2. Click Edit Product on any card
  3. Change a single field (e.g. name) and click Save Changes
  4. ✅ Only the edited field shows the update highlight

Vercel (broken)

Deploy to Vercel setting the same env vars (TURSO_DATABASE_URL, TURSO_AUTH_TOKEN).

  1. Open the deployed app
  2. Click Edit Product on any card
  3. Change a single field (e.g. name) and click Save Changes
  4. ❌ All fields of that product show the update highlight — all cacheTag entries for that product id are invalidated

Relevant code

Each field component uses a unique tag per field+id:

// getProductField in server/queries/products.ts
export async function getProductField(id, field) {
  "use cache";
  cacheTag(`${field}-${id}`);
  // ...
}

The server action only invalidates the changed field's tag:

// Only the changed field tag is added
const FIELD_CACHE_TAGS = {
  name: (id) => `name-${id}`,
  description: (id) => `description-${id}`,
  // ...
};
 
for (const field of changedFields) {
  const tagFn = FIELD_CACHE_TAGS[field];
  if (tagFn) tagsToRevalidate.add(tagFn(original.id));
}
 
for (const tag of tagsToRevalidate) {
  updateTag(tag); // only one tag, e.g. "name-5"
}

Current vs. Expected behavior

Expected behavior (local build)

Only the component whose cacheTag matches the invalidated tag should re-render. For example, calling updateTag('name-5') should only revalidate ProductName for product id 5.

<img width="1903" height="943" alt="Image" src="https://github.com/user-attachments/assets/a86dcc5a-143b-4173-9c65-8fa3b6c231a6" />

Actual behavior (Vercel only)

All cached field components for the edited product re-render (ProductName, ProductDescription, ProductBadge, ProductBrand, ProductRating, Price). This is confirmed by the updatedAt tooltip changing on all fields and wrapper component show blue outline, which only happens when the component re-executes and returns a new date value from the database.

<img width="1903" height="941" alt="Image" src="https://github.com/user-attachments/assets/6e442493-6e0f-4cd7-b0ff-523e06dbde11" />

Provide environment information

- **Next.js:** 16.1.6
- **Runtime:** Vercel (production) vs local (Windows, Bun)
- **Database:** Turso (LibSQL) + Drizzle ORM
- **Build:** performed on Windows with Bun

Which area(s) are affected? (Select all that apply)

cacheComponents

Which stage(s) are affected? (Select all that apply)

Vercel (Deployed)

Additional context

  • Related issues from October 2025 mention similar behavior but do not identify Vercel as the specific environment where it fails
  • The issue does not reproduce locally, suggesting it is specific to Vercel's Data Cache implementation rather than the Next.js compiler
  • It is worth noting that in very rare occasions, all fields being revalidated can also happen in a local production build (bun run build && bun run start) on the first data mutation.

extent analysis

TL;DR

The issue can likely be fixed by adjusting the cache invalidation strategy to account for Vercel's Data Cache implementation.

Guidance

  • Verify that the cacheTag function is correctly generating unique tags for each field and product ID.
  • Check the Vercel documentation to see if there are any specific requirements or recommendations for cache invalidation.
  • Consider adding logging or debugging statements to determine which cache tags are being invalidated on Vercel.
  • Review the updateTag function to ensure it is only invalidating the intended cache tags.

Example

No code example is provided as the issue seems to be related to the interaction between the application and Vercel's caching layer, rather than a specific code snippet.

Notes

The issue appears to be specific to Vercel's environment, and the fact that it does not reproduce locally suggests that it may be related to Vercel's caching implementation. Further investigation into Vercel's documentation and caching behavior may be necessary to resolve the issue.

Recommendation

Apply a workaround to adjust the cache invalidation strategy to account for Vercel's Data Cache implementation, as the root cause of the issue seems to be related to the interaction between the application and Vercel's caching layer.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING