CometComet

Overview

What Comet is, how the pieces fit together, and why it exists.

What is Comet

Comet runs Rocket routes on Cloudflare Workers.

The problem is easy to state: Rocket's published releases depend on Hyper/Tokio for their networking layer, and that layer doesn't compile for the wasm32-unknown-unknown target Workers use. Workers run inside a single-threaded V8 isolate, with a fetch(request) -> response model, no sockets, no OS threads, and bindings (D1, KV, Queues...) that only resolve through !Send futures.

Comet solves this with two pieces:

  1. A vendored, patched Rocket fork (in vendor/rocket), which splits the routing/guards/responders core (which compiles to wasm32-unknown-unknown) from the server layer (Hyper, TLS, Tokio) — and exposes external dispatch hooks to run without ever opening a socket.
  2. The comet::cloudflare adapter, which converts a worker::Request into Rocket request metadata, dispatches it directly through the patched Rocket (no socket, no Hyper), and converts the resulting rocket::Response back into a worker::Response.

In practice, this means: you write ordinary Rocket route handlers — guards, responders, fairings — in the same style as always, and they run, unmodified, on top of Cloudflare Workers.

use worker::{event, Context, Env, Request, Response, Result};

#[macro_use]
extern crate rocket;

#[get("/")]
fn index() -> &'static str {
    "hello from Rocket on Cloudflare Workers"
}

fn rocket(env: Env, _ctx: Context) -> rocket::Rocket<rocket::Build> {
    rocket::build().manage(env).mount("/", routes![index])
}

#[event(fetch)]
pub async fn main(req: Request, env: Env, ctx: Context) -> Result<Response> {
    comet::cloudflare::fetch(req, env, ctx, rocket).await
}

The three pieces of the project

Current status

Comet is described by its own maintainers as an early-stage adapter, not a finished framework integration. What already works today, with integration tests proving the behavior:

  • Real streaming: request and response bodies flow through Rocket without being fully buffered before the other side can start working with them.
  • JSON guards and responders, the normal Rocket kind.
  • Cloudflare bindings via Rocket managed state — comet::cloudflare::D1, QueueBinding, Kv, R2Bucket, ServiceBinding, and Hyperdrive — as typed request guards for named bindings.
  • R2 object responses via R2Object, which streams an R2 object's body while preserving R2's own HTTP metadata.
  • WebSocket routes via WebSocketUpgrade/WebSocketResponse, behind the cloudflare-websocket feature, using normal Rocket route syntax.

What's not there yet: full, durable-storage-backed replacements for filesystem APIs such as FileServer, NamedFile, and disk-backed TempFile — Workers expose no durable local filesystem, so this area is deliberately left out rather than half-implemented.

Quick vocabulary

TermWhat it is
CometThe comet crate: the Rocket ↔ Cloudflare Workers adapter.
NebulaThe comet::nebula module, the optional ORM core (feature nebula).
comet-cliThe comet binary, packaged in the comet-cli/ directory, for scaffolding and automation.
WorkerCloudflare's runtime (a V8 isolate) where the compiled code runs in production.
D1Cloudflare's SQLite-compatible database, Nebula's primary target.

Publishing to crates.io

comet isn't published to crates.io yet. The reason is the vendored Rocket fork: cargo package fails because a path dependency needs a version, and adding one would make crates.io silently swap the patched Rocket for the unpatched registry version. Until the fork has its own public, versioned home, depend on Comet via Git:

[dependencies]
comet = { git = "https://github.com/viniciusamelio/comet", default-features = false, features = ["cloudflare"] }

A git dependency clones the whole repository, so the vendored rocket path dependency resolves the same way it does locally — no extra setup needed on the consumer's side.

Ready to start? Head over to Getting Started.

On this page