# cloudflare/templates: fifty Workers starters held together by one coverage rule

> This repository is a catalogue of starter templates for building on a serverless edge runtime, and its real engineering is not the templates. It is the test harness that starts a development server for every one of them, allocates ports so they do not collide, kills process trees afterwards, and fails the build if a template ships without a browser test.

**cloudflare/templates** — Templates for Cloudflare Workers

- Repository: https://github.com/cloudflare/templates
- Website: https://workers.cloudflare.com
- Stars: 2,142 · Forks: 1,048
- Language: TypeScript
- License: MIT
- Published: 2026-09-30 · Updated: 2026-09-30 · Language: en
- Canonical page: https://hysenlabs.com/projects/cloudflare-templates

## The harness starts a server for every template and cleans up after itself

The testing section is the longest and most specific part of the readme, and it describes seven properties of a harness that exist because the author hit the problems they solve.

Discovery is the first. The harness finds every directory matching a template naming pattern that also has a development script defined, and builds its test list from that. Nothing is registered by hand, so a template cannot be added without the harness noticing, and a directory whose development script is renamed does not silently drop out of testing. For a catalogue that is growing by several entries a month, that is the difference between a test suite and a suggestion.

Port allocation is the second, and it is a specific kind of pain. Both an HTTP port and an inspector port are allocated dynamically for each template, so fifty templates can be tested in sequence on one machine without the second one failing because the first one is still holding a port. The readme says this explicitly as a feature: existing local services do not conflict.

Cleanup is the third and it is the one most harnesses get wrong. The text specifies terminating process trees, not just processes, and removing the environment files the harness itself created. Both halves matter. A development server that spawns a child and gets the parent killed leaves an orphan holding a port, which then breaks the next template. And a harness that writes a temporary environment file and does not remove it will eventually overwrite a real one in a developer's working tree, which is a genuinely destructive bug rather than an untidy one.

Failure diagnosis is the fourth, and it is the feature that will save you the most time. The harness detects a process that exits early, rather than waiting for a test timeout, and attaches the captured server output to the failed test. A template that fails to start because of a bad configuration therefore produces an error pointing at the configuration, not a timeout forty seconds later with no explanation.

Resource policy is the fifth and it is a deliberate asymmetry. In local mode the suite runs with a single worker, described as keeping resource usage predictable, and in live mode it runs up to four locally and two in continuous integration. That is a considered answer to a real trade: local machines vary enormously, and a suite that is fast on a workstation and unusable on a laptop is a suite people disable.

## The coverage rule is the one invariant that makes fifty templates viable

Among the seven properties, one is not a convenience. The coverage enforcement line says the harness fails when a development-enabled template has no corresponding browser test.

Think about what that means in practice. A pull request that adds a new template directory and forgets the test file does not merge. A pull request that breaks an existing test does not merge. And because discovery is automatic, neither failure requires a human to notice. The invariant is mechanical, and mechanical invariants are the only kind that survive fifty pull requests a month across a team large enough to need a per-directory ownership file.

The naming convention exists to serve the rule. A test must be named after its template, in a specific spelling, and live in one directory. Given that plus automatic discovery, the mapping from template to test is unambiguous in both directions, and the harness can compute the set difference. A template without a test is a detectable state rather than an absence of information.

The mode design is the other piece that makes the rule affordable. The same test file runs in two modes. In the default local mode it drives a locally started server, which is slow but needs no deployment. In live mode, enabled by an environment variable, it drives an already-deployed instance, which is faster and uses shorter timeouts. Since a template is also a deployed demo, live mode tests the thing users will actually touch, and since local mode is the default, contributors do not need credentials to contribute.

Live mode is enabled by an environment variable:

```bash
pnpm run test:e2e:live
```

Live mode also reveals something about the deployment setup. The readme gives the live URL pattern directly, so the tests are hitting a real hostname per template. Deriving that hostname automatically from the deployment configuration, rather than hardcoding it in fifty test files, is the last of the seven properties and it is the one that means adding template fifty-one does not require touching anything but two new files.

## Keep mocks at the binding boundary, or the test proves nothing

There is a short paragraph in the instructions for writing template tests that is worth more attention than anything else in the repository, and it is easy to miss because it is phrased as a technical note.

It says that if a template's normal development command requires remote resources, you should add a separate development script for testing, backed by local test configuration, and that the harness will prefer it when present. Then it says: keep mocks at external binding boundaries so the production request handler still runs end to end.

That is a precise statement of what makes a template test worth having, and the alternative is a very common failure. A test that mocks the thing you are trying to demonstrate has proved that the mock works. If a template's whole purpose is to show a request handler reading a key value store, and the test substitutes the store with an in-memory stand-in that the template itself wires up, then the only thing exercised is the template's wiring, not its binding. A regression in the binding configuration would pass.

The escape hatch and the rule are consistent, and the distinction between them is the interesting part. A template that genuinely cannot start without a remote resource is allowed to have a different development command for testing. What is forbidden is replacing the remote resource with a fake inside the code path under test. The remote resource is the boundary; mock there, and let everything between the boundary and the response be the real thing.

There is also a fixture that removes an entire class of mistake. Tests are given a template URL value rather than constructing one, and the fixture supplies the right form for the current mode. Without that, every one of the fifty test files would contain a conditional on the mode and a hardcoded hostname, and fifty copies of that logic is fifty chances to get it wrong.

The readme closes the loop with the browser test framework's own recorder, invoked through a package script, so that writing the first test is a matter of clicking through the page rather than writing a selector by hand.

## Three packages are allowed to run install scripts, and that is the point

The root package manifest contains a field listing three packages as permitted to run their own install scripts, and the names are a build tool, an image processing library and the local runtime that executes the server code. Everything else in a dependency tree of fifty templates is denied that permission.

Install scripts are arbitrary code. A package that ships a script that runs on installation can do anything the user can do, which makes it the standard supply chain attack surface in the JavaScript ecosystem. Most projects respond by ignoring the problem or by switching to a flag that disables all of them and then discovering the build no longer works. This repository has taken the middle path, which is the right one: disable the scripts, then re-enable them individually for the three packages that genuinely need to compile or download something.

The choice is defensible on its own terms and instructive because of the shape of the exception list. The build tool and the image library are native modules that must compile. The local runtime is a binary the development server downloads. None of the three is a package that has any business running arbitrary code beyond that, and each is a well-known name. If someone added a fourth entry, a reviewer would ask why, and the answer would have to be specific.

For a template repository this control is more valuable than it would be in an application, and the reason is the copy. A template is not deployed from this repository, it is cloned from it and then it belongs to somebody else. Every template in the catalogue is a separate dependency tree that a user will install, and each of those trees inherits whatever install-script posture the template was written under. A posture enforced at the root of the monorepo is therefore not just hygiene for the maintainers. It is the default that fifty separate projects inherit without anybody deciding to adopt it.

The same reasoning explains the version pinning in the same manifest, which is the other practice worth copying and which comes up in the next section.

## Every tool is pinned exactly, and the check fails on any diff

The root manifest pins its development dependencies to exact versions with no ranges at all, and a separate configuration file exists to enforce that across every package in the workspace. There is also a workspace file, an orchestration configuration, and a lockfile, which is the standard modern monorepo stack and is unremarkable in itself.

What is not standard is the degree of the pinning, and the reason is specific to this repository. A template is code that other people copy, possibly months later, possibly into a project with a different dependency graph. A caret range in a template is a promise about a version that may not exist when the template is used. Exact pins make the template a fixed artefact: it worked on this date with these versions, and if it does not work for you, the cause is not a version that moved underneath you.

The consistency tool exists because a workspace with fifty packages drifts. Nothing in the JavaScript ecosystem stops a package from depending on a different minor version of the same library from its neighbour, and in a template catalogue that produces fifty subtly different dependency trees. Linting for it in continuous integration, with a matching fix command, keeps the catalogue uniform.

The check script is the most interesting entry, and its final line is a plain git command that fails if the working tree is not clean. The script runs a dependency consistency lint, a template linter, a lockfile linter, a build and type generation pass across the workspace, and a formatting check, and then asserts that none of them changed a file.

That is a strong statement. It means every fixer in the chain is required to be a no-op when the check runs, which in turn means all formatting is already applied and all generated artefacts are already committed. Most projects run their formatters in write mode during a check and accept that the check modifies your working tree. Refusing that is stricter and mildly annoying, and it converts a whole category of confusing local state into a build failure that says what happened.

The release history explains the rest. Three major versions in seventeen days, each a whole number. For a template catalogue that is a very fast cadence, and it suggests the major number tracks something shared across the templates rather than the templates themselves, most likely a change in the local runtime or the command line tooling that every template depends on.

## The catalogue is the roadmap, and it has turned towards agents

The top-level listing is around fifty template directories, and reading the names tells you what a platform vendor thinks its users are building in 2026 without anyone having to publish a strategy document.

The database-oriented entries are there in the obvious forms: a SQL database starter, a sessions API built on it, a key value starter, an object storage explorer, two connection pooling templates for hosted relational databases, one per engine, and two full-stack templates pairing a database with a front end. The server-side rendering family is the largest coherent group, with several variations on a modern client-side router paired with a database, plus a server-rendered variant, a full-stack variant, and a plain starter. There is a blog starter on a static site generator, a plain front-end starter on a build tool, a micro-frontend template, and a server-rendering framework starter, which is a reasonable spread of the shapes people actually start from.

Then there is the group that would not have been on a list like this three years ago. Three templates with agent in the name: one for agent visibility, one for analytics specific to agent commerce, and one for a brand visibility use case. A template whose name is the standard natural language interface protocol rather than a technology. A voice agent template. A template for generating images. A template for serving text to language models as a machine-readable file. A durable objects starter for chat.

That is a catalogue with a clear second front, and the naming is more informative than a feature list would be. The first front is the established one: storage, compute, rendering, connection pooling. The second is applications that call a model, and within it the emphasis is on agents that act on a user's behalf, which is a different shape from the chat template that already existed for a model you talk to.

Two entries on the infrastructure side are also worth naming because they are not obvious from the word template. There is a directory for internal sites, and one for containers. Both suggest the vendor is addressing the case where the workload is not a request handler at all, which is the honest boundary of what an edge runtime is for.

The repository is organised for that scale with two files that are pure governance: one assigning ownership per directory, and one instructing automated coding tools, alongside a blame ignore file for a repository that has been through automated rewrites and still wants its history to be readable.

## Conclusion

The value of this repository is the harness rather than any individual template, and that is the right way to read it if you are deciding whether to trust the catalogue. Every template is discovered automatically, started automatically, and required to have a browser test, so a broken starter is a failed build rather than a support ticket. The pinning discipline is the other thing worth copying, because a template is code that other people will copy later, and a floating version range becomes their outage six months from now. If you use one of these, treat it as a starting point and re-pin it, keep the mock boundary at the external binding so the real request handler still executes, and expect the runtime floor and the tooling to move faster than your own project, since major releases here have landed weekly.

## FAQ

### What is in the Cloudflare Workers templates repository?

Around fifty starter template directories covering databases, key value storage, object storage, connection pooling, server-side rendering with several frameworks, email, and a second group built around agents, voice and image generation. The readme explicitly encourages using, modifying and extending them, and they are MIT licensed.

### How does the template test suite decide what to test?

Automatically. The harness discovers every directory matching the template naming pattern that also defines a development script, requires the test file to be named after the template in a fixed directory, and fails the build when a development-enabled template has no corresponding test.

### What is the difference between local and live test modes?

Local mode is the default and starts a development server for each template on dynamically allocated ports with a single worker. Live mode is enabled by an environment variable and runs against already-deployed instances at a predictable hostname per template, allowing parallel execution with different worker counts locally and in continuous integration, and shorter timeouts because no server startup is needed.

### Why should mocks stay at the binding boundary in template tests?

So the production request handler still runs end to end. A template whose purpose is to demonstrate a particular binding will prove nothing if the test substitutes that binding with a stand-in, since a configuration error in the binding would still pass. Templates that genuinely cannot start without a remote resource get a separate test development script, but the remote resource itself remains the mock boundary.

### What is the purpose of the onlyBuiltDependencies list in the root package manifest?

It restricts which packages are permitted to run their own install scripts. Exactly three are allowed, covering a build tool, an image processing library and the local server runtime, and everything else in the dependency tree is denied. For a template catalogue this matters beyond the maintainers, because every template is copied into somebody else's project and inherits that install posture.

## Sources

- [cloudflare/templates on GitHub](https://github.com/cloudflare/templates)
- [License: MIT](https://github.com/cloudflare/templates/blob/main/LICENSE)
- [Project website](https://workers.cloudflare.com)
- [README](https://github.com/cloudflare/templates/blob/main/README.md)
- [Releases](https://github.com/cloudflare/templates/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/cloudflare-templates
