Cloudflare-first backend architecture: Workers, Queues, R2, PlanetScale and Typesense
How to design a production backend around Cloudflare Workers, TypeScript, Pages, R2, Queues, PlanetScale MySQL, and Typesense without turning the edge into a messy second backend.
A Cloudflare-first backend works when each piece has a narrow job: Workers handle request logic, Queues protect slow work, R2 stores objects, PlanetScale owns transactions, and Typesense serves search.
Start with the workload map
A Cloudflare-first backend should not begin with a list of products. It should begin with a workload map. Which requests are latency-sensitive? Which paths are read-heavy? Which actions must be transactional? Which jobs can happen after the user gets a response? Which data belongs in object storage, and which data belongs in a relational database? Once those questions are clear, the stack becomes easier to reason about: Workers for request handling, Queues for background work, R2 for objects, PlanetScale MySQL for transactional data, and Typesense for search.
Workers should own the request edge
Cloudflare Workers are strongest when they own the narrow request edge: routing, validation, auth checks, webhook handling, API gateways, lightweight orchestration, and response shaping. TypeScript helps keep those boundaries explicit because request inputs, response shapes, and integration contracts can be typed. The mistake is letting Workers become a dumping ground for every piece of business logic. If a Worker starts acting like a full monolith with unclear state ownership, the architecture needs to be simplified before it grows.
Queues keep slow work out of the user path
Many backend problems come from making users wait for work that does not need to finish immediately. Cloudflare Queues are useful for jobs like webhook follow-up, email or notification work, sync tasks, search indexing, file processing, analytics events, and retryable integration calls. The important design choice is deciding what must be synchronous and what can be eventual. A donation, checkout, signup, or form submission may need an immediate authoritative result, but supporting work can often move behind a queue with retries and clear failure handling.
R2 is for objects, not relational truth
Cloudflare R2 is a strong fit for files, exports, receipts, images, documents, generated reports, and other object storage needs. It should not be treated as a replacement for relational data. The clean pattern is to store the object in R2 and keep metadata, ownership, status, and workflow state in the database. That way the application can answer questions like who owns this file, whether it is ready, whether it has been processed, and which product workflow it belongs to without scanning object storage as if it were a database.
PlanetScale owns transactional data
PlanetScale MySQL fits the part of the backend that needs relational structure: users, campaigns, donations, permissions, workflow state, audit-friendly records, and product entities with clear relationships. Even in a Cloudflare-first architecture, the database is still the source of truth for transactional behavior. Workers should call the data layer through deliberate API or client boundaries, not scatter ad hoc SQL-shaped decisions across unrelated request paths. The point is to keep state ownership obvious when the product grows.
Typesense should serve search-shaped reads
Search is a different workload from transactions. Typesense works well when users need fast text search, filtering, faceting, typo tolerance, and ranked results. The database can remain the source of truth while Typesense serves search-shaped reads. The hard part is not the first search query; it is keeping the index correct. A reliable system needs a sync path, retry handling, delete behavior, drift monitoring, and a way to rebuild indexes without taking the product offline.
The edge layer still needs observability
A Cloudflare backend can feel simple until something fails across Workers, Queues, R2, PlanetScale, and Typesense at the same time. Observability has to be designed into the system: request IDs, structured logs, queue job status, retry counts, object keys, database operation context, search sync events, and clear error states. Without that, debugging becomes guesswork. The goal is not only to make the happy path fast. The goal is to make production behavior explainable when a user, campaign, webhook, or integration behaves strangely.
Design for idempotency early
Idempotency matters in any backend with queues, webhooks, retries, and external integrations. A queued job may run again. A webhook provider may send the same event twice. A client may retry a request after a timeout. A search indexing task may need to resume after partial failure. The backend should make repeated work safe by using stable event IDs, unique constraints, state transitions, and clear retry rules. This is the difference between a resilient Cloudflare backend and one that slowly corrupts product state under load.
Do not put every decision at the edge
Cloudflare makes it tempting to move everything close to users, but not every decision belongs at the edge. Authorization checks, request validation, caching, and routing can often happen in Workers. Transactional decisions, complex workflow state, and data consistency rules often belong near the database or in a service layer designed around that domain. A good Cloudflare-first backend is not edge-only. It is edge-aware: each workload goes where it is easiest to operate correctly.
What I would document before handoff
Before handing off a Cloudflare-first backend, I want a short operating guide. It should explain which routes run in Workers, which jobs use Queues, what is stored in R2, which tables in PlanetScale are authoritative, how Typesense indexes are synced, how retries work, where logs live, and how to roll back a risky change. Documentation like this is not bureaucracy. It is what lets the next engineer add a feature without accidentally breaking the architecture.
The practical architecture rule
The practical rule is simple: give every platform component a job it is naturally good at. Workers handle the request edge. Queues absorb work that can happen later. R2 stores objects. PlanetScale MySQL owns transactional truth. Typesense serves search. When those responsibilities stay clear, a Cloudflare-first backend can be fast, cost-sensitive, and maintainable. When the boundaries blur, the stack may still look modern, but the product becomes harder to operate.
Next step
Need this decision made for your backend?
Send the current architecture, traffic shape, and cost pressure. I can turn that into a short migration or audit plan.
Request an architecture review