Skip to content

[Cloudflare preset] Per-collection sql_dump.txt prerender serves stale content #3730

@adamsaimi

Description

@adamsaimi

Environment

Operating system macOS 24.5.0
CPU Apple M2 Pro (10 cores)
Node.js version v24.11.1
nuxt/cli version 3.33.1
Package manager pnpm@10.4.1
Nuxt version 4.3.1
Nitro version 2.13.1
Builder vite@7.3.1
Config app, colorMode, compatibilityDate, css, modules, nitro, site, ssr, vite
Modules @nuxt/ui@4.4.0, @nuxt/content@3.11.2, @nuxtjs/sitemap@7.6.0

Version

v3.11.2

Reproduction

Not feasible as a minimal repo — requires Cloudflare Pages deployment with D1 binding

Description

When deploying to Cloudflare Pages with ssr: false, content changes are
not reflected in the prerendered
/__nuxt_content/{collection}/sql_dump.txt files. The build correctly
parses markdown files (0 cached, 19 parsed) and
.data/content/contents.sqlite contains the updated content, but the
prerendered dump files serve stale data.

This was discovered while debugging a deployment issue where docs content
wouldn't update on Cloudflare Pages despite fresh builds and cache
purges. After hours of debugging, Claude Code (Anthropic's AI coding
agent) traced the issue through the build pipeline and identified the
root cause in the module source. I'm not deeply familiar with the
@nuxt/content internals to fully verify the analysis, but applying the
suggested workaround (copying the correct root-level dump files over the
prerendered ones) did fix the deployment and the live site now serves the
updated content.

Root cause (as identified by Claude Code):

In module.mjs, the Cloudflare preset registers per-collection dump
templates via collectionDumpTemplate() inside setupNitro:

  manifest.collections.map(async (collection) => {
    if (!collection.private) {
      addTemplate(collectionDumpTemplate(collection.name, manifest));
    }
  });

However, the updateTemplates() call in the modules:done hook only
refreshes:

  await updateTemplates({
    filter: (template) => [
      moduleTemplates.fullRawDump,
      moduleTemplates.fullCompressedDump,
      moduleTemplates.manifest,
      moduleTemplates.components
    ].includes(template.filename)
  });

The per-collection templates (content/raw/dump.{collection}.sql) are not
included in the filter. They get rendered once when registered (with
empty manifest.dump = {}), but never re-rendered after
processCollectionItems populates manifest.dump.

Evidence during build:

File: .data/content/contents.sqlite
Content: NEW ✅
────────────────────────────────────────
File: dist/dump.{collection}.sql (from fullDatabaseRawDumpTemplate)
Content: NEW ✅
────────────────────────────────────────
File: .nuxt/content/raw/dump.{collection}.sql (per-collection template)
Content: OLD ❌
────────────────────────────────────────
File: dist/__nuxt_content/{collection}/sql_dump.txt (prerendered)
Content: OLD ❌

Suggested fix:

Add per-collection dump templates to the updateTemplates filter:


  const perCollectionDumps = manifest.collections
    .filter((c) => !c.private)
    .map((c) => `content/raw/dump.${c.name}.sql`);

  await updateTemplates({
    filter: (template) => [
      moduleTemplates.fullRawDump,
      moduleTemplates.fullCompressedDump,
      moduleTemplates.manifest,
      moduleTemplates.components,
      ...perCollectionDumps
    ].includes(template.filename)
  });

Workaround:

  nuxt build
  cp dist/dump.docs.sql dist/__nuxt_content/docs/sql_dump.txt
  cp dist/dump.blog.sql dist/__nuxt_content/blog/sql_dump.txt
  wrangler --cwd dist pages deploy

Additional context

No response

Logs

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions