Skip to content

Conversation

@sergical
Copy link
Member

@sergical sergical commented Jan 9, 2026

Summary

  • Fixes the issue where updating images doesn't invalidate the build cache
  • Adds a function to hash referenced image files and include them in the MDX cache key
  • When an image changes, the cache key changes, triggering a page rebuild

Problem

When images are updated but their referencing MDX files aren't changed, Vercel serves stale images because the MDX cache key only depends on the MDX source content hash.

Discussed in #docs-dev Slack thread.

Test plan

  • Deploy to preview and verify images update correctly
  • Verify build still works for pages without images
  • Check that the cache key changes when an image is modified

🤖 Generated with Claude Code

Include hashes of referenced images in the MDX cache key so that
pages are rebuilt when their images are updated, even if the MDX
source file itself hasn't changed.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@vercel
Copy link

vercel bot commented Jan 9, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
develop-docs Ready Ready Preview, Comment Jan 12, 2026 4:37pm
sentry-docs Ready Ready Preview, Comment Jan 12, 2026 4:37pm

sergical and others added 2 commits January 9, 2026 12:36
Improve regex to match image paths without leading dot (e.g., img/file.png)
while still excluding absolute paths and URLs.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Copy link
Member

@BYK BYK left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if this would actually work since as far as I understand, this is Vercel caching the files based on the file name. So unless we have new file names for the images we are not doing much?

Instead of computing image hashes in mdx.ts during cache key generation,
embed the content hash directly in image URLs via remark-image-size.

Before: /mdx-images/image.png#800x600
After:  /mdx-images/image.png?v=abc12345#800x600

This ensures Vercel's CDN serves fresh images when content changes,
since the URL itself changes. Also simplifies mdx.ts by removing the
redundant getImageHashesFromSource function.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@sergical sergical force-pushed the fix/invalidate-cache-on-image-change branch from dfd73b9 to 80343fc Compare January 11, 2026 00:14
* The size is consumed by docImage.tsx and passed down to next/image.
* The content hash (?v=xxx) busts Vercel's CDN cache when images are updated.
*/
export default function remarkImageSize(options) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this function now does more than just handle image size. Would it make sense to update its name to better reflect its current responsibilities?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good point, thanks for flagging!

* Appends image size and content hash to the URL.
* e.g. /img.png -> /img.png?v=abc12345#100x100
*
* The size is consumed by docImage.tsx and passed down to next/image.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: why are we doing this? (That was my initial question) Would it be worth mentioning that this is done to avoid any extra image measurement?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The version hash will help bust the vercel cache so that new images with the same name don't end up being cached. this also updates the html that we use for content hashing and checking whether changes were made to a file or not to update that cache.

why are we doing the image size? that was there before. The idea is when we render it in the lightbox container, next/image requires a width and a height prop to render the image properly, this puts it in the url of the image for the component to grab it

sergical and others added 2 commits January 12, 2026 11:26
Address PR review feedback:
- Rename file to better reflect its dual responsibility (sizing + cache busting)
- Update function name and improve documentation
- Add comment explaining single file read for efficiency

Co-Authored-By: Claude Opus 4.5 <[email protected]>
const contentHash = createHash('md5').update(imageBuffer).digest('hex').slice(0, 8);

// Add content hash as query param (for CDN cache busting) and size as hash
node.url = node.url + `?v=${contentHash}#${imageSize.width}x${imageSize.height}`;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

URL with existing query params produces malformed URL

Low Severity

The URL construction unconditionally appends ?v=${contentHash} without checking if the URL already contains query parameters. If an image URL has existing query params (e.g., ./img.png?param=1), the result would be ./img.png?param=1?v=abc#WxH with two ? characters, producing a malformed URL. The previous remarkImageSize plugin only appended #WxH, which correctly followed any existing query string. This regression means the cache-busting query param wouldn't be parsed correctly when pre-existing query params are present.

Fix in Cursor Fix in Web

@sergical sergical merged commit 84a7dde into master Jan 12, 2026
16 checks passed
@sergical sergical deleted the fix/invalidate-cache-on-image-change branch January 12, 2026 17:46
@github-actions github-actions bot locked and limited conversation to collaborators Jan 29, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants