How I Built an Edge-First AI Cartoon SaaS with Next.js, Cloudflare Workers & D1 An independent developer built AI Cartoon Generator, a SaaS creative studio for cartoon, anime, and comic creators, running entirely on Cloudflare Workers with Next.js App Router via OpenNext, Cloudflare D1 for serverless SQL, and R2 for image storage and caching. The platform centers on a locked "Character Asset" reference anchor that preserves character identity across pose, expression, and background variations, feeding storybook and animation pipelines where an LLM plans narrative beats before image generation. The developer reports that splitting SSR, thumbnail jobs, LLM planning, and webhooks across isolated Workers and background queues was necessary to stay within Worker limits. As an indie maker, launching an AI-powered SaaS often presents a brutal dilemma: I chose the second path. Over the past few months, I built and launched AI Cartoon Generator https://aicartoongenerator.io — a specialized creative studio designed for cartoon, anime, and comic creators. Instead of relying on a monolithic server, the entire platform runs on Cloudflare Workers using Next.js App Router via OpenNext , Cloudflare D1 , and R2 . In this article, I want to show what we built, lay bare the architectural blueprint, and share the hardest battle-tested lessons learned running Next.js at the edge. Most generic AI image generators produce stunning one-off pictures, but they fail creators who want to tell sequential stories or build consistent IP: To solve this, we focused on three core pillars at AI Cartoon Generator https://aicartoongenerator.io : Character Asset . Using an active reference anchor, users can generate pose, facial expression, and background variations without losing identity. A typical result — an ordinary photo restyled as a hand-painted anime scene: Input: the user's original photo Output: Ghibli-style transformation, generated on the edge And here's the character continuity system in action. This is one locked Character Asset Mina the Pocket Illustrator fed through four independent variation requests — same face, same outfit, different pose, expression, and world: The storybook pipeline then turns a character like this into a multi-scene illustrated book, with an LLM planning the narrative beats before any image is generated: A generated storybook cover character: Iris Vale, a mountain map archivist While the animation pipeline produces multi-shot storyboard sequences from the same identity anchor: Four-scene animation storyboard generated from one character reference Running a dynamic Next.js App Router site with heavy background AI orchestration on Cloudflare Workers requires strict isolation. A single Worker trying to handle SSR, image resizing, LLM planning, and webhooks will quickly crash into worker limits. Here is our production topology: ┌─────────────────────────────┐ │ Cloudflare Edge │ └──────────────┬──────────────┘ │ ▼ ┌─────────────────────────┐ │ Main Site Worker │ │ Next.js / OpenNext │ └────┬──────────────┬─────┘ ┌───────────────────┘ └───────────────────┐ ▼ ▼ ┌───────────────────┐ ┌───────────────────┐ │ Cloudflare D1 │ │ Cloudflare R2 │ │ Serverless SQL │ │ Images & Cache │ └───────────────────┘ └───────────────────┘ ▲ ▲ │ │ ┌────────────────┼──────────────────────────────────────────────────────┼────────────────┐ │ Background Queues & Workers │ │ │ │ │ │ ┌───────────────────────┐ ┌────────────────────────────────┐ │ │ │ │ media-thumbnail-jobs │──▶│ Main Worker Thumbnail Handler │───────┤ WebP 512px │ │ └───────────────────────┘ └────────────────────────────────┘ │ │ │ │ │ │ ┌───────────────────────┐ ┌────────────────────────────────┐ │ │ │ │ storybook-planning │──▶│ Standalone Planning Worker │───────┤ LLM planning │ │ └───────────────────────┘ └────────────────────────────────┘ │ │ │ │ │ │ ┌───────────────────────┐ ┌────────────────────────────────┐ │ │ │ │ animation-planning │──▶│ Standalone Planning Worker │ │ │ │ └───────────────────────┘ └────────────────────────────────┘ │ │ │ │ │ │ ┌───────────────────────┐ ┌────────────────────────────────┐ │ │ │ │ storybook-jobs │──▶│ Video Container Worker Docker │───────┘ MP4 renders │ │ └───────────────────────┘ └────────────────────────────────┘ │ └────────────────────────────────────────────────────────────────────────────────────────┘ ai-cartoon-generator batch size = 1 and isolated memory to plan scripts and scene breakdowns. linux/amd64 . Deploying Next.js to Cloudflare Workers via OpenNext isn't just "click deploy and relax." Here are the real challenges we hit in production and how we resolved them: In our early iterations, the main Next.js worker did everything: served HTML, queried D1, streamed LLM responses for story generation, and processed webhooks. During traffic spikes or heavy narrative planning tasks, the V8 isolate hit Cloudflare's memory ceiling, resulting in fatal Error 1102: Worker exceeded memory limits . The Solution: Treat the main worker purely as an interactive UI and API layer. We offloaded LLM-heavy streaming pipelines into dedicated planning workers aicartoon-storybook-planning and aicartoon-animation-planning managed by Cloudflare Queues with dead-letter queue DLQ fallbacks. If an LLM response runs wild, it never degrades website responsiveness. populate-cache Timeout Nightmare When using opennextjs-cloudflare deploy , the built-in deploy step tries to push pre-rendered HTML/RSC cache entries to R2 using an HTTP proxy. As our localized landing pages and style showcase grew to hundreds of static routes, network throttling caused continuous deploy timeouts. The Solution: We decoupled cache population from deployment: pnpm opennextjs-cloudflare build . upload-cache.mjs that maps .open-next/cache entries to OpenNext cache keys next-cache/