Project

Pollmodoro

A real-time polling platform that runs entirely on Cloudflare's network.

Summary

Pollmodoro is an open-source poll maker with no sign-up: write a question, add up to ten options and share the link. Results update live for everyone looking at the poll. It is built with SvelteKit and runs on Cloudflare Workers, with each poll stored in its own Durable Object.

PERIOD

2025 – 2026

STACK

  • Svelte
  • SvelteKit
  • Cloudflare Workers
  • Durable Objects
  • TailwindCSS
Home screen of Pollmodoro

Motivation

When I started Pollmodoro, there were two technologies I was very curious about: Cloudflare's developer platform and Svelte. Reading docs only gets you so far, so I wanted to experiment with them on a project small enough to finish but real enough to run into the interesting problems.

Pollmodoro is that project. To be honest, a polling app doesn't really need this kind of infrastructure: a single server and a regular database would serve it just as well. I picked it because it is simple, yet still touches the parts I wanted to explore: shared state that many people write to, vote counts that must never be wrong, and results that update live for everyone watching.

Cloudflare Workers

Workers is Cloudflare's serverless platform. Instead of giving each application its own container or virtual machine, the Workers runtime runs code inside V8 isolates, the same sandboxing mechanism Chrome uses to keep browser tabs apart. Isolates are cheap enough that a single process can host thousands of applications, so Cloudflare can run every Worker on machines across its whole global network, in hundreds of cities. A request is handled by a data center close to whoever made it.

Pollmodoro has two Workers: the SvelteKit app, which renders pages on the server, and the API, built with tRPC. Each is deployed with a single Wrangler command, and neither has a server I need to manage.

The catch is that Workers are stateless. Two votes on the same poll may be handled by two different Workers on different continents, which share no memory. The votes need to be stored somewhere they can be counted consistently.

Durable Objects

Durable Objects are Cloudflare's answer to state. A Durable Object is an instance of a JavaScript class with a globally unique name. Any Worker, anywhere, can get a reference to it by name and call its methods as if it were a local object. Cloudflare guarantees that only one instance with a given name exists in the world at any time. It runs in a single location, on a single thread, and has its own private SQLite database stored on the same machine.

In Pollmodoro, every poll is a Durable Object. When someone creates a poll, the API generates a random ID and uses it as the object's name. That object stores the poll, its options and every vote in its own database. Because it handles one request at a time, checking whether a poll is closed, validating the options and recording a vote happen with no race conditions and no locks.

Creating a poll in Pollmodoro

A distributed architecture

Put together, Workers and Durable Objects form an unusual kind of distributed system. Compute runs everywhere, but each piece of state has exactly one home.

Browsers

São Paulo

Poll creator

São Paulo

Voter

Lisbon

Voter

Nearest Worker

Worker

São Paulo data center

Worker

São Paulo data center

Worker

Lisbon data center

One Durable Object per poll

Poll hMRwidAt…

Lives in São Paulo, where it was first requested

  • SQLite: poll, options, votes
  • WebSockets of everyone watching
Every request is handled by the closest Worker, but all of them reach the same Durable Object, wherever it lives.
  • Placement: A Durable Object is created in a data center close to where it is first requested, which for Pollmodoro is the person creating the poll. It stays there, and requests from anywhere else travel to it.
  • Trade-off: All of a poll's traffic goes through one single-threaded object, with a soft limit of about 1,000 requests per second. That is what keeps the counts consistent, but it also caps how fast a single poll can take votes. A poll shared during a big livestream could hit that limit.
  • Scaling: There is no limit on how many objects exist. Since polls are independent, the platform scales horizontally by having more polls, not bigger servers.

Real-time results

Since a poll's Durable Object is the single place every vote goes through, it is also the natural place to push live updates. Everyone viewing a poll opens a WebSocket that the Worker forwards to the poll's object. Whenever a vote is recorded, the object sends the new results to all connected browsers.

The connections use Cloudflare's WebSocket Hibernation API. Most of the time a poll is idle, with people looking at it and nobody voting. With hibernation, Cloudflare can evict the object from memory while the connections stay open, and wakes it up again when there is something to do. Idle polls don't accrue duration charges.

Poll with live results

Svelte

On the frontend, Pollmodoro was my first real project with Svelte. Svelte is a compiler: at build time, components are turned into JavaScript that updates the DOM directly, so there is no virtual DOM and very little framework code shipped to the browser.

Svelte 5 handles reactivity with runes: $state for reactive values, $derived for computed ones and $effect for side effects. Runes also work in plain TypeScript files, which made small reusable pieces easy to write. For example, the "Your polls" list is a reactive class that keeps itself in sync with localStorage.

SvelteKit renders the poll page on a Worker, so the first response already contains the results. tRPC shares types between the frontend and the API, so a change in the backend shows up as a type error in the UI. To keep spam away without making people sign up, creating a poll and voting are both protected by Cloudflare Turnstile.

Was it the right tool?

For a polling app, not really. Durable Objects make correct counts and live updates easy, but nobody notices whether a vote takes 80 or 300 milliseconds, and very few polls get enough traffic to need a globally distributed platform. Workers and Durable Objects pay off when many people interact with the same state at the same time and every millisecond is felt. For example:

  • Collaborative editors and whiteboards: each document is an object, placed near the people editing it, that orders their changes and streams them, along with everyone's cursors, in real time.
  • Multiplayer games: each match is an object, placed near its players, that holds the authoritative game state and sends updates many times per second, where latency is immediately noticeable.

Main takeaways

Pollmodoro was a great way to learn by building. Durable Objects changed how I think about distributed state. Instead of a central database that every request competes for, each unit of data gets its own small, single-threaded owner. Building something that didn't strictly need it also taught me where it really pays off. Svelte, in turn, showed me how pleasant a framework can be when most of the work happens at build time.