Treat fetch, queue, scheduled, and email handlers as separate Worker surfaces with their own files
Devflare can compose or wrap several Worker surfaces into one generated entrypoint, but the authored source of truth should stay in explicit files such as , , , and .
A single Devflare package can own more than one Cloudflare event surface. Keep each surface in its own file when the package genuinely owns that event type, wire schedules through , and let the generated composed entrypoint stay generated instead of hand-maintained.
- Best for
- Packages that own both HTTP and background event surfaces
- Default files
- , , ,
- Generated output
- when Devflare needs to wrap or compose the worker surfaces it discovered
- Test helpers
- , , , and
Keep each event surface in its own lane
Devflare does not flatten every Cloudflare event into one mystery handler. When one package owns HTTP, queue consumption, cron jobs, or inbound email, the cleanest shape is usually one file per surface so ownership stays obvious in code review.
That separation is especially useful once the package has both request/response code and background work. The HTTP story stays in fetch or routes, while queue, scheduled, and email code can evolve without disappearing into one huge entry file.
| Surface | Conventional file | Use it when | Helper |
|---|---|---|---|
| Fetch | or | HTTP requests belong to one main handler or route tree. | / |
| Queue consumer | The package owns deferred, batched, or retryable queue work. | ||
| Scheduled handler | plus | Time-based jobs should run from config-owned schedules. | |
| Email handler | The Worker handles inbound email or local email-handler flows. |
Put scheduled intent in config instead of scripts or comments
A scheduled handler is only half the story. The code lives in , but the timing contract belongs in so the package declares when the job should run instead of relying on external shell memory.
Preview behavior belongs in config too. defaults to , so branch-scoped preview deploys drop cron triggers unless you opt them back in deliberately.
Preview environments should not inherit cron behavior by accident
If previews should run scheduled jobs, say so explicitly. Otherwise keep preview validation focused on the surfaces reviewers actually expect to exercise.
A package that owns several Worker surfaces explicitly
Disable unused conventions explicitly and let Devflare compose the rest
Generated composition is not only a build detail. The local dev server also uses the same surface model to decide what to watch, so the directories around configured or conventional fetch, queue, scheduled, email, route, and transport files all become reload roots.
That split is intentional: config-file edits take the config reload path, while worker-source changes under those watched roots take the worker reload path. You do not need a second watch system just because the package grew another surface.
- Set , , or when one of the default conventions should stay off.
- Set when the package should stay fetch-only instead of discovering a route tree.
- When a fetch entry, route tree, or background surface set needs wrapper glue, Devflare can generate a composed entrypoint under to fan them into the Worker runtime correctly.
- If is set, or the fetch worker already lives at , Devflare skips that generated main entry and uses the explicit worker instead.
- Generated entrypoints are supposed to churn as the surface set changes. Keep the authored files and config authoritative, and let the glue stay disposable.
- Treat that generated entrypoint as output. The authored source of truth remains the explicit files and config that selected them.
Dev reload follows the same surface roots
Worker-source changes under the watched fetch, queue, scheduled, email, route, or transport roots trigger the worker reload path, while edits to the resolved trigger the config reload path instead.
Tail is still a special case
Devflare can exercise tail behavior in the test harness when exists, but there is not yet a public config key. Keep the main project-shape story centered on the documented event surfaces, and open the page when the question is tail testing.
Some nearby keys are discovery globs, not event handlers
Not every key means “Cloudflare will call this file as an event surface.” Some keys tell Devflare where to discover related program structure such as Durable Object classes, named entrypoints, workflow definitions, or transport hooks.
That distinction matters because it keeps code review honest. Event surfaces answer “what can invoke this package?”, while discovery globs answer “what else should Devflare scan and bundle for the runtime contract?”
Runtime
Need transport behavior?
Open the transport page when a discovered transport file becomes part of the package contract.
Configuration
Need the generated type contract?
Open the generated types page when , , or discovered Durable Objects need to show up correctly in .
Configuration
Need the broader config map?
The runtime and deploy settings page covers the non-surface knobs such as account context, compatibility posture, routes, assets, limits, and migrations.
| Config key | What it points at | Why it is different |
|---|---|---|
| Durable Object class files or globs | These classes are discovered and wrapped; they are not a standalone top-level event surface like fetch or queue. | |
| Named entrypoint files or globs | These support typed cross-worker references and discovery, not a separate Cloudflare event hook. | |
| Workflow definition files or globs | These are additional discovered modules, not a direct replacement for fetch, queue, scheduled, or email handlers. | |
| One custom transport file | This is a serialization hook for bridge-backed calls, not an event handler that Cloudflare dispatches directly. |
Previous
Project shape
Start with one fetch file, then add routes, background handlers, Durable Objects, assets, and transport rules only when the project genuinely needs them.
Next
Generated types
turns config, discovered Durable Objects, named entrypoints, and cross-worker references into one generated TypeScript contract instead of a pile of hand-maintained env guesswork.