Sitemap
Genglin

Genglin

Building practical web tools for creators & everyday users 🛠️ Indie developer obsessed with making things that just work. Shipping small, useful software.

Three Ways to Deploy Nuxt 4 on Cloudflare (And Why I Chose Pages)

7 min readAug 30, 2026

--

Press enter or click to view image in full size
A dark technical illustration showing three parallel deployment paths (Pages in green, Workers in orange, Hybrid in blue) converging to a Nuxt icon, with Cloudflare edge nodes and a $0 cost label, using cyan and blue-violet accents on a dark navy background.

A practical comparison of Cloudflare Pages, Workers, and hybrid deployment for Nuxt 4 — with real costs, real bugs, and what actually works for indie developers.

I wanted to run a tool site with near-zero infrastructure costs. After testing three deployment approaches on Cloudflare, I settled on Pages + R2 storage. The total monthly cost: one domain name.

Here is what I tried, what broke, and why Pages won for my use case.

Who This Is For

This article is for:

  • Indie developers building tool sites or SaaS products
  • Frontend engineers considering Cloudflare as a deployment platform
  • Nuxt developers looking for low-cost hosting options
  • Anyone tired of paying $20+/month for Vercel or Netlify Pro

If you want a production-ready Nuxt 4 setup with automatic deployments, static asset storage, and zero monthly fees, this should give you a practical starting point.

Project Context

BulkPicTools is a browser-based image processing tool site. Users can resize, compress, and convert images without uploading them to a server. Most processing happens in the browser.

The tech stack:

  • Nuxt 4 (full feature usage: SSG, server routes, middleware, auto-imports)
  • Cloudflare Pages (hosting and deployment)
  • Cloudflare R2 (image storage and ONNX model files)
  • Cloudflare Workers (used in other projects, not the main site)

At the time of writing, the site generates approximately US$200 in monthly revenue. Infrastructure cost beyond the domain: $0.

The Three Approaches I Tested

Approach 1: Cloudflare Pages + R2

This is what I use in production.

How it works:

  • Nuxt 4 built with SSG (Static Site Generation)
  • Static files deployed to Cloudflare Pages
  • R2 bucket stores blog images and ONNX models
  • API routes handle sitemap.xml generation
  • Git push to main branch triggers automatic deployment

Pros:

  • Generous free tier (500 builds/month, 100GB bandwidth)
  • Automatic deployments from Git
  • Built-in CDN and edge caching
  • R2 has zero egress fees
  • Custom domain support with free SSL

Cons:

  • SSG builds can consume significant memory
  • Cloudflare build environment differs from local Node.js
  • Some npm packages need special handling

Approach 2: Cloudflare Workers

I tested this for a different project.

How it works:

  • Nuxt 4 configured for server-side rendering (SSR)
  • Deployed as a Worker script
  • Handles requests at the edge

Pros:

  • True edge rendering
  • Lower latency for dynamic content
  • Better for API-heavy applications

Cons:

  • Worker runtime has strict memory and CPU limits
  • Not all Node.js APIs are available
  • Requires Nitro preset configuration for Cloudflare
  • More complex debugging

Approach 3: Hybrid (Pages + Workers)

This combines both approaches.

How it works:

  • Static pages served from Pages
  • Dynamic API routes handled by Workers
  • R2 for asset storage

Pros:

  • Best of both worlds
  • Static assets are fast and cheap
  • Dynamic logic runs at the edge

Cons:

  • More complex architecture
  • Need to manage two deployment targets
  • Harder to debug across environments

Why I Chose Pages

For a tool site with mostly static content, Pages was the clear winner.

Decision factors:

Press enter or click to view image in full size

The key insight: Most tool sites are 90% static content. The pages users visit (tool interfaces, blog posts, landing pages) do not need server-side rendering. They just need fast CDN delivery.

Cloudflare Pages handles this perfectly. The API routes I need (sitemap generation) work within Pages’ limitations.

The Bugs I Hit

Bug 1: Cloudflare Build Environment Differences

Problem: Packages that work locally failed during Cloudflare builds.

Cloudflare’s build environment does not provide a full Node.js runtime. Some npm packages assume access to native modules or system APIs that are not available.

One specific issue: the Nuxt Content module (used for blog posts) failed during SSG builds on Cloudflare. The module tries to query content at build time, but the Cloudflare environment does not support this properly.

Get Genglin’s stories in your inbox

Join Medium for free to get updates from this writer.

Solution: I created a mock file to replace the Content module’s query functions during Cloudflare builds:

// mock-content.ts
// Mock queryCollection for Content v3
export const queryCollection = () => {
return {
all: () => Promise.resolve([]),
where: () => ({
all: () => Promise.resolve([])
})
}
}
// Mock serverQueryContent for Content v2
export const serverQueryContent = () => {
return {
find: () => Promise.resolve([]),
where: () => ({
find: () => Promise.resolve([])
})
}
}
export default {
queryCollection,
serverQueryContent
}

This mock returns empty arrays, allowing the Sitemap module and other content-dependent features to complete without errors. The actual content is still loaded client-side from the CMS.

Lesson: Test your build on Cloudflare early. Do not assume local builds will translate directly. When packages fail, creating targeted mocks is often faster than finding alternatives.

Bug 2: SSG Build Memory Usage

Problem: Nuxt 4 SSG builds consumed more memory than Cloudflare’s build environment expected.

Static Site Generation needs to render every page at build time. For sites with many pages or complex components, this can exceed memory limits.

Solution: I modified the build command to allocate more memory:

NODE_OPTIONS=" - max-old-space-size=8192" npm run build

This sets the maximum heap size to 8192 MB (8 GB). Cloudflare Pages build environment supports this allocation, and it resolved the out-of-memory errors for my SSG builds.

I also optimized the build process by:

  • Reducing the number of pages generated at build time
  • Simplifying complex components
  • Using dynamic imports where possible
  • Monitoring build memory usage

Lesson: SSG is great for performance, but the build process has real costs. If your builds fail with memory errors, adjusting `NODE_OPTIONS` is the first thing to try. Plan your page structure accordingly.

Bug 3: R2 Path Configuration

Problem: Serving files from R2 required careful path configuration.

R2 does not serve files like a traditional CDN out of the box. You need to configure routes or use a Worker to handle requests.

Solution: I set up proper path mapping between my Nuxt routes and R2 object keys. Blog images use a predictable path structure that maps directly to R2 storage.

Lesson: Plan your R2 path structure before you start storing files. Changing paths later means updating all references.

R2 Storage: Images and Models

I use R2 for two purposes:

1. Blog images

All images for blog posts are stored in R2. This keeps my Pages deployment lightweight and reduces build times. The images are served through a custom domain with proper caching headers.

2. ONNX models

For browser-based AI features, I store ONNX model files in R2. Users download these models directly from R2 when they need them, without hitting my server.

Why R2 instead of a traditional CDN:

  • Zero egress fees (this matters at scale)
  • S3-compatible API (easy to integrate)
  • Built into Cloudflare ecosystem
  • Generous free tier (10GB storage, 10 million Class A operations/month)

The Deployment Workflow

My deployment process is intentionally simple:

git push to main branch
↓
Cloudflare detects changes
↓
Cloudflare runs build command
↓
Static files deployed to Pages
↓
Site live

No Kubernetes. No CI/CD pipelines. No Docker containers. No server management.

For an indie developer, this simplicity is a feature, not a limitation. I spend my time building products, not maintaining infrastructure.

Build times to expect:

My site has 1000+ pages. With SSG, Cloudflare needs to render every page at build time. Realistic build time: around 15 minutes.

This is not a problem for my workflow. I verify changes locally before pushing. The 15-minute wait is just background processing — I continue working on other things while it builds.

Build configuration:

  • Build command: `NODE_OPTIONS=” — max-old-space-size=8192" npm run build`
  • Build output directory: `.output/public`
  • Node.js version: 22 (or whatever Nuxt 4 requires)
  • Memory allocation: 8192 MB (required for SSG builds with many pages)
  • Typical build time: ~15 minutes for 1000+ pages

Cost Breakdown

Cloudflare costs

The free tiers cover everything I need:

  • Pages: 500 builds/month, 100GB bandwidth
  • R2: 10GB storage, 10M Class A / 10M Class B operations
  • Workers: 100,000 requests/day

I have never hit these limits. With local verification before deploying, I average around 20–30 builds per month. The 500 build limit is more than enough.

When This Approach Works

Good fit:

  • Tool sites with mostly static content
  • Blog-driven sites with static pages
  • Landing pages and marketing sites
  • Small to medium SaaS products
  • Projects where cost is a primary concern

Bad fit:

  • Applications with heavy server-side logic
  • Real-time collaborative features
  • Large-scale API services
  • Projects requiring database connections at the edge
  • Applications with strict Node.js API requirements

What I Would Change

If I started over:

1. Test the build environment earlier. I wasted time fixing build issues that could have been caught on day one.

2. Plan R2 paths from the beginning. My initial path structure needed refactoring later.

3. Use hybrid approach for API-heavy projects. For BulkPicTools, Pages is fine. For projects with more dynamic content, I would consider hybrid from the start.

4. Monitor build performance. SSG builds can degrade silently as the site grows. Set up alerts early.

Key Takeaways

  • Cloudflare Pages + R2 can run a profitable tool site for ~$1/month (just the domain)
  • Three deployment options exist: Pages, Workers, and Hybrid — pick based on your content type
  • SSG builds have real memory costs — plan your page structure accordingly
  • Cloudflare’s build environment differs from local Node.js — test early
  • R2 is ideal for static assets with zero egress fees
  • Simple deployment (git push → auto deploy) saves more time than you think

CTA

If you want to see a live example of this stack, you can check out BulkPicTools: https://bulkpictools.com

The blog runs on Nuxt 4 + Cloudflare Pages, with images stored in R2. The infrastructure cost is zero beyond the domain.

--

--