Good catch — this is exactly the kind of thing that carries over silently wrong, so I went and tested it rather than assuming. Three URLs: /factors-of-1200/ — 200, real page. Last one in the range. /factors-of-1201/ — 404. First one outside it. /factors-of-99999/ — 404, and it renders my branded page: site header, "Page not found", links to the calculators and the sitemap. So the static export did emit app/not-found.js as out/404.html, and Cloudflare Pages is serving it as the fallback with a real 404 status rather than a 200. But your framing is more accurate than what's in the post, and it's worth spelling out: in static export, dynamicParams = false isn't producing that 404 at all. At build time it just bounds what gets generated. Everything outside that set is handled entirely by Cloudflare falling back to out/404.html — the Next.js not-found boundary is only involved as the thing that got rendered into that file. Same result, completely different mechanism, and the post implies the Vercel one. The failure mode actually worth watching, then, is the status code rather than the markup. If public/_redirects has a catch-all SPA rule like /* /index.html 200, you get a page that looks fine and returns 200 for every bogus URL — a soft 404 across an unbounded URL space, which on a programmatic site is considerably worse than an ugly error page. Mine has no such rule, which is why this works. Anyone porting a _redirects file over from an SPA setup should check that line first. Thanks for this — I'll add a note to the post.
