Skip to content

fix(cloudflare): stop bundling @vercel/og when it is unused#1221

Merged
vicb merged 1 commit intoopennextjs:mainfrom
mushan0x0:fix/drop-vercel-og-when-unused
Apr 22, 2026
Merged

fix(cloudflare): stop bundling @vercel/og when it is unused#1221
vicb merged 1 commit intoopennextjs:mainfrom
mushan0x0:fix/drop-vercel-og-when-unused

Conversation

@mushan0x0
Copy link
Copy Markdown
Contributor

Fixes #1220 (and the original #1211).

Problem

Next.js's internal externalImport helper emits a dynamic

import("next/dist/compiled/@vercel/og/index.edge.js")

into the app handler even for apps that never use next/og (ImageResponse, opengraph-image, twitter-image, …). Today, when patchVercelOgLibrary decides useOg === false, bundle-server.ts marks that module as external:

external: [
  "./middleware/handler.mjs",
  // Do not bundle og when it is not used
  ...(useOg ? [] : ["next/dist/compiled/@vercel/og/index.edge.js"]),
],

esbuild honors external and leaves the import("…@vercel/og/index.edge.js") call site intact. Wrangler then resolves that external module against node_modules and bundles:

  • @vercel/og edge bundle (~800 KiB uncompressed / ~260 KiB gzip)
  • resvg.wasm (~1.4 MiB)

…even though the code path is unreachable. For CSR-heavy apps that never use OG images this single dynamic import pushes the Worker over the 3 MiB free-tier gzip limit.

Reproduced on a real Next 16 app with @opennextjs/[email protected] and 1.19.2:

build wrangler deploy --dry-run
unpatched (useOg=false, external) 14098.57 KiB / gzip 3119.42 KiB
after this PR 11875.51 KiB / gzip 2415.74 KiB

(The same savings were previously achievable only via a post-build regex script that rewrote the emitted handler.)

Fix

When useOg === false, alias the edge entry to the existing throw.js shim instead of marking it external:

external: ["./middleware/handler.mjs"],
alias: {
  ...(useOg
    ? {}
    : {
        "next/dist/compiled/@vercel/og/index.edge.js": path.join(
          buildOpts.outputDir,
          "cloudflare-templates/shims/throw.js"
        ),
      }),
  // …
},

The unreachable dynamic import now resolves to a tiny throw "OpenNext shim" module, and Wrangler no longer drags the real @vercel/og library + resvg.wasm into the Worker bundle. If the dynamic import is ever executed at runtime (which would indicate a bug in patchVercelOgLibrary's useOg detection), the shim throws immediately — the same failure mode users already get from @ampproject/toolbox-optimizer and other shimmed modules, rather than a silent runtime mismatch.

When useOg === true the behavior is unchanged: the real edge build is copied and patched by patchVercelOgLibrary as before.

Why not a config flag?

The original issue proposed an opt-in flag (cloudflare: { disableVercelOg: true }), but the adapter already computes the exact signal it needs (useOg), so this can be done safely with no new config surface.

Validation

  • pnpm --filter cloudflare test — 31 files / 317 tests pass.
  • pnpm code:checks (prettier + eslint + tsc) — clean.
  • End-to-end: built a real app (Next 16.2.4, app/ router, no next/og) against this fork, confirmed handler.mjs no longer contains next/dist/compiled/@vercel/og/index.edge.js and wrangler deploy --dry-run size dropped as shown above.

Changeset

Included as a patch bump under .changeset/drop-unused-vercel-og.md.

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 22, 2026

🦋 Changeset detected

Latest commit: 8db8d43

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@opennextjs/cloudflare Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Copy link
Copy Markdown
Contributor

@vicb vicb left a comment

Choose a reason for hiding this comment

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

Great investigation!

LGTM, thank you so much for the fix!

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Apr 22, 2026

Open in StackBlitz

npm i https://pkg.pr.new/@opennextjs/cloudflare@1221

commit: 8db8d43

@vicb vicb merged commit a2679bf into opennextjs:main Apr 22, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE] Opt-in flag to strip unused @vercel/og dynamic import (saves ~2 MiB, keeps Worker under free-tier 3 MiB)

2 participants