[{"data":1,"prerenderedAt":522},["ShallowReactive",2],{"en-post-\u002Fen\u002Fnuxt-content-vercel-empty-query-sqlite":3},{"id":4,"title":5,"body":6,"description":512,"extension":513,"meta":514,"navigation":516,"path":517,"seo":518,"sitemap":519,"stem":520,"__hash__":521},"blogEn\u002Fen\u002Fnuxt-content-vercel-empty-query-sqlite.md","Nuxt Content v3 queryCollection() Returns Empty on Vercel (But Works Locally)",{"type":7,"value":8,"toc":503},"minimark",[9,13,22,25,28,33,184,211,222,224,228,236,256,264,266,278,300,328,334,336,340,343,380,386,446,448,452,455,487,489,493,499],[10,11,5],"h1",{"id":12},"nuxt-content-v3-querycollection-returns-empty-on-vercel-but-works-locally",[14,15,16,17,21],"p",{},"A Nuxt 3 + Nuxt Content v3 blog suddenly started rendering a completely empty post list in production. No error, no crash — the page just rendered with zero posts. Locally, running ",[18,19,20],"code",{},"npm run build"," and serving that exact same build worked perfectly: every post showed up.",[14,23,24],{},"That gap — identical code, different result depending on where it runs — is the signature of an environment-specific bug, not a logic bug. Here's how it was tracked down.",[26,27],"hr",{},[29,30,32],"h2",{"id":31},"the-symptom","The symptom",[34,35,40],"pre",{"className":36,"code":37,"language":38,"meta":39,"style":39},"language-vue shiki shiki-themes github-light github-dark","\u003Cscript setup>\nconst { data: posts } = await useAsyncData(\"blog-post-list\", async () => {\n  const result = await queryCollection(\"blog\").all();\n  return result;\n}, { default: () => [] });\n\u003C\u002Fscript>\n","vue","",[18,41,42,62,117,148,157,174],{"__ignoreMap":39},[43,44,47,51,55,59],"span",{"class":45,"line":46},"line",1,[43,48,50],{"class":49},"sVt8B","\u003C",[43,52,54],{"class":53},"s9eBZ","script",[43,56,58],{"class":57},"sScJk"," setup",[43,60,61],{"class":49},">\n",[43,63,65,69,72,76,79,83,86,89,92,95,98,102,105,108,111,114],{"class":45,"line":64},2,[43,66,68],{"class":67},"szBVR","const",[43,70,71],{"class":49}," { ",[43,73,75],{"class":74},"s4XuR","data",[43,77,78],{"class":49},": ",[43,80,82],{"class":81},"sj4cs","posts",[43,84,85],{"class":49}," } ",[43,87,88],{"class":67},"=",[43,90,91],{"class":67}," await",[43,93,94],{"class":57}," useAsyncData",[43,96,97],{"class":49},"(",[43,99,101],{"class":100},"sZZnC","\"blog-post-list\"",[43,103,104],{"class":49},", ",[43,106,107],{"class":67},"async",[43,109,110],{"class":49}," () ",[43,112,113],{"class":67},"=>",[43,115,116],{"class":49}," {\n",[43,118,120,123,126,129,131,134,136,139,142,145],{"class":45,"line":119},3,[43,121,122],{"class":67},"  const",[43,124,125],{"class":81}," result",[43,127,128],{"class":67}," =",[43,130,91],{"class":67},[43,132,133],{"class":57}," queryCollection",[43,135,97],{"class":49},[43,137,138],{"class":100},"\"blog\"",[43,140,141],{"class":49},").",[43,143,144],{"class":57},"all",[43,146,147],{"class":49},"();\n",[43,149,151,154],{"class":45,"line":150},4,[43,152,153],{"class":67},"  return",[43,155,156],{"class":49}," result;\n",[43,158,160,163,166,169,171],{"class":45,"line":159},5,[43,161,162],{"class":49},"}, { ",[43,164,165],{"class":57},"default",[43,167,168],{"class":49},": () ",[43,170,113],{"class":67},[43,172,173],{"class":49}," [] });\n",[43,175,177,180,182],{"class":45,"line":176},6,[43,178,179],{"class":49},"\u003C\u002F",[43,181,54],{"class":53},[43,183,61],{"class":49},[185,186,187,201],"ul",{},[188,189,190,191,193,194,197,198,200],"li",{},"Locally (",[18,192,20],{}," + ",[18,195,196],{},"node .output\u002Fserver\u002Findex.mjs","): ",[18,199,82],{}," comes back with every post. Works.",[188,202,203,204,206,207,210],{},"On Vercel, hitting the live URL: ",[18,205,82],{}," comes back as ",[18,208,209],{},"[]",". Every time. No error in the response, no warning in the logs — just an empty array.",[14,212,213,214,217,218,221],{},"Confirmed it wasn't a caching artifact first: the response headers on Vercel showed ",[18,215,216],{},"x-vercel-cache: MISS"," and ",[18,219,220],{},"age: 0"," — a genuinely fresh server execution, still returning nothing.",[26,223],{},[29,225,227],{"id":226},"ruling-things-out","Ruling things out",[14,229,230,231,235],{},"Since the exact same build artifact behaved differently by environment, the cause had to be something about ",[232,233,234],"em",{},"where"," it ran, not the page code:",[185,237,238,245,248],{},[188,239,240,241,244],{},"Not a missing ",[18,242,243],{},"content.config.ts"," — it was present and correctly configured.",[188,246,247],{},"Not a code bug in the page — the identical build rendered all posts correctly when run locally.",[188,249,250,251,104,254,141],{},"Not a stale CDN cache — confirmed via response headers (",[18,252,253],{},"MISS",[18,255,220],{},[14,257,258,259,263],{},"That narrows it down to the one thing that genuinely differs between \"run locally\" and \"run inside a Vercel serverless function\": ",[260,261,262],"strong",{},"filesystem access",".",[26,265],{},[29,267,269,270,273,274,277],{"id":268},"root-cause-nuxtcontent-v3s-sqlite-database-needs-tmp-on-vercel-and-300-didnt-know-that-yet","Root cause: ",[18,271,272],{},"@nuxt\u002Fcontent"," v3's SQLite database needs ",[18,275,276],{},"\u002Ftmp"," on Vercel — and 3.0.0 didn't know that yet",[14,279,280,282,283,286,287,292,293,295,296,299],{},[18,281,272],{}," v3 indexes all your markdown into a SQLite database at build time, read via ",[18,284,285],{},"better-sqlite3"," (a native module) at runtime. On Vercel, the deployed function's filesystem is ",[260,288,289,290],{},"read-only everywhere except ",[18,291,276],{},". If the content module tries to read or write its SQLite file somewhere outside ",[18,294,276],{},", that access silently fails in a way that doesn't throw — ",[18,297,298],{},"queryCollection()"," just comes back with nothing, instead of erroring.",[14,301,302,303,305,306,311,312,319,320,323,324,327],{},"The fix for this exact scenario — making the module use ",[18,304,276],{}," on Vercel — shipped in ",[260,307,308,310],{},[18,309,272],{}," v3.1.1"," (",[313,314,318],"a",{"href":315,"rel":316},"https:\u002F\u002Fgithub.com\u002Fnuxt\u002Fcontent\u002Fissues\u002F3108",[317],"nofollow","nuxt\u002Fcontent#3108","). The project in question was pinned to ",[18,321,322],{},"@nuxt\u002Fcontent: \"^3.0.0\""," — the very first v3 release, published ",[232,325,326],{},"before"," that fix existed.",[14,329,330,331,333],{},"That's the whole bug: a brand-new Nitro\u002FNuxt project scaffold had pinned the first-ever v3 release of the content module, and that specific version never got the Vercel filesystem fix. Locally, there's no ",[18,332,276],{},"-only restriction, so the broken path silently worked anyway — which is exactly why this kind of bug survives so long undetected: it only manifests in the one environment nobody manually tests against on every change.",[26,335],{},[29,337,339],{"id":338},"the-fix","The fix",[14,341,342],{},"Upgrade past the fix, plus whatever else comes along for the ride:",[34,344,348],{"className":345,"code":346,"language":347,"meta":39,"style":39},"language-diff shiki shiki-themes github-light github-dark","- \"@nuxt\u002Fcontent\": \"^3.0.0\",\n+ \"@nuxt\u002Fcontent\": \"^3.16.1\",\n- \"nuxt\": \"^3.15.2\",\n+ \"nuxt\": \"^3.21.11\",\n- \"@nuxtjs\u002Fsitemap\": \"^7.2.9\",\n+ \"@nuxtjs\u002Fsitemap\": \"^8.6.1\",\n","diff",[18,349,350,355,360,365,370,375],{"__ignoreMap":39},[43,351,352],{"class":45,"line":46},[43,353,354],{},"- \"@nuxt\u002Fcontent\": \"^3.0.0\",\n",[43,356,357],{"class":45,"line":64},[43,358,359],{},"+ \"@nuxt\u002Fcontent\": \"^3.16.1\",\n",[43,361,362],{"class":45,"line":119},[43,363,364],{},"- \"nuxt\": \"^3.15.2\",\n",[43,366,367],{"class":45,"line":150},[43,368,369],{},"+ \"nuxt\": \"^3.21.11\",\n",[43,371,372],{"class":45,"line":159},[43,373,374],{},"- \"@nuxtjs\u002Fsitemap\": \"^7.2.9\",\n",[43,376,377],{"class":45,"line":176},[43,378,379],{},"+ \"@nuxtjs\u002Fsitemap\": \"^8.6.1\",\n",[14,381,382,383,385],{},"A few things fall out of bumping ",[18,384,272],{}," that far forward, worth knowing before you hit them:",[185,387,388,402,422],{},[188,389,390,393,394,397,398,401],{},[18,391,392],{},"@nuxt\u002Fcontent@3.16.1"," requires ",[18,395,396],{},"nuxt >=3.19.0"," (or ",[18,399,400],{},"^4.1.0",") — the module disables itself with a warning if your Nuxt version is older, rather than failing loudly.",[188,403,404,405,407,408,410,411,414,415,418,419,263],{},"Newer ",[18,406,272],{}," no longer bundles ",[18,409,285],{}," — it now expects it as an explicit dependency. ",[18,412,413],{},"nuxt prepare"," fails with ",[18,416,417],{},"Nuxt Content requires better-sqlite3 module to operate"," until you ",[18,420,421],{},"npm install better-sqlite3",[188,423,424,427,428,431,432,435,436,438,439,442,443,445],{},[18,425,426],{},"@nuxtjs\u002Fsitemap","'s older content integration (",[18,429,430],{},"asSitemapCollection",") imports ",[18,433,434],{},"queryCollectionWithEvent"," from ",[18,437,272],{},"'s runtime — a function that newer content versions renamed\u002Fremoved. The build fails at the Rollup stage with ",[18,440,441],{},"\"queryCollectionWithEvent\" is not exported"," until ",[18,444,426],{}," is bumped to a version built against the newer content API.",[26,447],{},[29,449,451],{"id":450},"verifying-the-fix","Verifying the fix",[14,453,454],{},"Since this bug only showed up in the deployed environment, \"it builds locally\" isn't enough evidence. After upgrading:",[456,457,458,466,480],"ol",{},[188,459,460,462,463,465],{},[18,461,20],{},", then run the actual build output locally (",[18,464,196],{},") and confirm the post count matches your content directory.",[188,467,468,469,472,473,475,476,479],{},"Deploy, then check the ",[260,470,471],{},"live"," response headers for ",[18,474,216],{}," \u002F fresh ",[18,477,478],{},"age"," to make sure you're not looking at a cached (and still-empty) response.",[188,481,482,483,486],{},"Check ",[18,484,485],{},"\u002Fsitemap.xml"," on the live deployment — it should list every post, not just static routes.",[26,488],{},[29,490,492],{"id":491},"takeaway","Takeaway",[14,494,495,496,498],{},"If ",[18,497,298],{}," (or any SQLite-file-backed Nuxt module) works locally but comes back empty only on Vercel with zero errors, check your filesystem assumptions before your logic — and check whether you're pinned to a version of the module that predates its own Vercel-specific fix. \"Works on my machine\" is a filesystem-permissions story as often as it's a cache one.",[500,501,502],"style",{},"html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":39,"searchDepth":64,"depth":64,"links":504},[505,506,507,509,510,511],{"id":31,"depth":64,"text":32},{"id":226,"depth":64,"text":227},{"id":268,"depth":64,"text":508},"Root cause: @nuxt\u002Fcontent v3's SQLite database needs \u002Ftmp on Vercel — and 3.0.0 didn't know that yet",{"id":338,"depth":64,"text":339},{"id":450,"depth":64,"text":451},{"id":491,"depth":64,"text":492},"A production-only bug where queryCollection(\"blog\").all() silently returns an empty array on Vercel while the exact same build works fine locally — caused by @nuxt\u002Fcontent 3.0.0 predating the Vercel \u002Ftmp SQLite fix.","md",{"date":515},"2026.10.07",true,"\u002Fen\u002Fnuxt-content-vercel-empty-query-sqlite",{"title":5,"description":512},{"loc":517},"en\u002Fnuxt-content-vercel-empty-query-sqlite","jl-tvvA75zhHc-eCBsZ6t-ML2zB-Zct6uwi6xIsxc34",1791347386895]