cf-workerify
v1.0.1
Published
Turn any React, Next.js, or Node.js project into a deployable Cloudflare Worker with wrangler.
Maintainers
Readme
☁️ cf-workerify
Deploy any web project to Cloudflare Workers — one command.
Turn your React / Vite SPA, Next.js app, or Node.js / Express server into a deployable Cloudflare Worker with a single command and a few interactive prompts.
Why?
Moving an existing project to the edge usually means rewriting config files by hand, digging through Cloudflare's docs, and getting the nodejs_compat flags, assets directories and bindings exactly right. cf-workerify automates all of that:
- Detects your framework (
vite,next,node, or a generic worker scaffold). - Asks you (with nice interactive dialogs) for the configurable parameters — worker name, compatibility date, KV / D1 / R2 / Queues / Service bindings, environment variables, cron triggers and CI workflow.
- Generates everything:
wrangler.toml, Worker entry points,.dev.vars.example, package scripts,.gitignoreentries and an optional GitHub Actions workflow. - Installs the dependencies it needs (
wrangler,@opennextjs/cloudflare) and shows you the exact next steps.
Features
- 🔍 Automatic framework detection — Vite/React/CRA SPAs, Next.js, Express/Fastify/Koa/plain
node:httpservers, or unknown projects. - 🎛️ Interactive configuration — ask for every parameter that matters before generating anything.
- 🧩 Full binding support — KV namespaces, D1 databases, R2 buckets, Queues, Service bindings, cron triggers, environment variables and secrets.
- ⚡ One-shot edge deploy — after generating everything, cf-workerify offers to create your Cloudflare resources (KV / D1 / R2) and substitute their ids into
wrangler.toml, then offers to deploy immediately (or use--deploy). - 📦 Framework-aware output (see What gets generated).
- 🤖 Works in CI —
--yesnon-interactive mode with overrides for name, framework, compatibility date and account id. - 🛡️ Safe — dry-run mode,
--no-install, never overwrites existing files unless asked. - 🌐 Zero-config deploys — a
deploynpm script that builds and runswrangler deploy.
Requirements
- Node.js ≥ 18
- A Cloudflare account (free tier is fine)
- An existing project with a
package.json
Installation
Run it without installing anything:
npx cf-workerifyOr install it globally:
npm install -g cf-workerify
cf-workerifyOr add it to your project's dev dependencies:
npm install -D cf-workerify
npx cf-workerifyUsage
cf-workerify [project-path] [options]If no path is given, the current directory is used.
# adapt the current project (interactive)
cf-workerify
# adapt another project directory
cf-workerify ../my-next-app
# fully non-interactive, using detected defaults
cf-workerify . --yes
# force a framework and a specific worker name
cf-workerify . --framework node --name my-api
# preview what would be created without writing anything
cf-workerify . --dry-runCLI options
| Option | Description |
| --- | --- |
| [project-path] | Path to the project to adapt (defaults to the current directory). |
| --name <name> | Cloudflare Worker / project name (skips the name prompt). |
| --framework <id> | Force a framework: vite, next, node or generic. |
| --compatibility-date <date> | Wrangler compatibility_date (YYYY-MM-DD). |
| --account-id <id> | Pin a Cloudflare account id in wrangler.toml. |
| --yes, -y | Use detected defaults for everything, no prompts. |
| --no-install | Write files but don't run the package manager install. |
| --deploy | Deploy immediately at the end of the run (non-interactive). |
| --dry-run | Print the files that would be created without writing them. |
| --force | Overwrite existing wrangler.toml and worker files. |
| --version, -v | Print the version. |
| --help, -h | Show help. |
What gets generated
Everything is written at the root of the target project; your source files are never modified.
| File | Purpose |
| --- | --- |
| wrangler.toml | Wrangler configuration: name, compatibility_date, compatibility flags, assets, bindings, vars, triggers, observability. |
| worker/index.js | Worker entry point — SPA handler or cloudflare:node HTTP wrapper. |
| open-next.config.ts | OpenNext configuration for Next.js projects. |
| .dev.vars.example | Template for local environment variables / secrets. |
| .github/workflows/deploy.yml | Optional CI workflow (Cloudflare wrangler-action). |
| .gitignore | Adds .wrangler, dev.vars and build output entries (if missing). |
| package.json | Adds deploy, dev:worker, preview, cf-typegen scripts and dev dependencies. |
React / Vite / Create React App → Static Assets Worker
Your app stays fully static; Cloudflare serves it from env.ASSETS with
client-side routing fallback (single_page_application = true), and you can
add API routes to the same Worker in worker/index.js.
name = "my-vite-app"
main = "worker/index.js"
compatibility_date = "2026-08-10"
assets = { directory = "./dist", binding = "ASSETS", single_page_application = true }// package.json scripts
"deploy": "npm run build && wrangler deploy",
"dev:worker": "npm run build && wrangler dev"Next.js → @opennextjs/cloudflare
Uses the officially recommended OpenNext Cloudflare adapter.
name = "my-next-app"
main = ".open-next/worker.js"
compatibility_flags = [ "nodejs_compat" ]
assets = { directory = ".open-next/assets", binding = "ASSETS" }// package.json scripts
"preview": "opennextjs-cloudflare build && opennextjs-cloudflare preview",
"deploy": "opennextjs-cloudflare build && opennextjs-cloudflare deploy"Note: remove
export const runtime = "edge"from route files — OpenNext runs on the Node.js runtime.
Node.js / Express → cloudflare:node
Wraps your existing HTTP server without rewriting any routes. Requires
nodejs_compat + enable_nodejs_http_server_modules (already set).
// worker/index.js (generated)
import { httpServerHandler } from "cloudflare:node";
import "./src/index.js"; // your server, must call app.listen(3000)
const PORT = 3000;
export default httpServerHandler({ port: PORT });The port above must match the port your server listens on. This works for
Express, Fastify, Koa, Hapi and plain node:http servers.
Interactive configuration
During an interactive run you're asked for:
- Framework — detected automatically, overridable.
- Worker name — defaults to your package name.
- Compatibility date — defaults to today.
- Account id — optional, pinned into
wrangler.toml. - Bindings (each optional, multiple allowed):
- KV namespaces — binding name + namespace id (leave id blank if you'll create it later).
- D1 databases — binding name + database name + database id.
- R2 buckets — binding name + bucket name.
- Queues — producer binding + queue name.
- Service bindings — binding name + target Worker service.
- Cron triggers — e.g.
0 0 * * *. - Environment variables — values go in
wrangler.toml[vars]; empty values are treated as secrets and added to.dev.vars.example.
- GitHub Actions workflow — optional auto-deploy on push to
main.
Environment variables & secrets
- Non-secret vars are written into
wrangler.toml→[vars]. - Secrets (vars without a value) are listed in
.dev.vars.exampleand must be set in production:
npx wrangler secret put API_KEYFor local development, copy .dev.vars.example → .dev.vars and fill in real
values (wrangler dev loads it automatically).
Creating Cloudflare resources
If you left a KV / D1 / R2 id blank, cf-workerify offers to create them for
you at the end of the run (you need to be logged in with npx wrangler login).
It runs the create commands, parses the returned ids and writes them into
wrangler.toml automatically:
npx wrangler kv namespace create my-app-kv # id → wrangler.toml
npx wrangler d1 create my-db # id → wrangler.toml
npx wrangler r2 bucket create my-bucket # no id neededAnything that couldn't be created is listed in the summary with the exact command to run manually.
Deploying
At the end of an interactive run you're asked whether to deploy now. Answer
yes (or use --deploy) and cf-workerify runs the deploy script for you:
cd my-project
npx wrangler login # one time
npm run deploynpm run deploy builds your app (when needed) and runs npx wrangler deploy.
You'll get a https://<name>.<account>.workers.dev URL.
With the GitHub Actions workflow you configure two repository secrets and every
push to main deploys:
CLOUDFLARE_API_TOKEN
CLOUDFLARE_ACCOUNT_IDTroubleshooting
| Problem | Fix |
| --- | --- |
| Express app doesn't respond | Check the PORT in worker/index.js matches app.listen(...) in your server entry. |
| Next.js deploy fails | Use nodejs_compat, recent compatibility_date, and remove export const runtime = "edge". |
| 404 on deep links | The SPA uses single_page_application = true; make sure the assets directory points at your build output. |
| Bindings missing | Run npx wrangler kv namespace create / d1 create and update the ids in wrangler.toml. |
| Node built-ins unavailable | The nodejs_compat flag must be present and compatibility_date recent. |
| Project less than edge-friendly | CPU-time, memory and cold-start limits apply; avoid native/node-only modules at runtime. |
Development
git clone https://github.com/manalejandro/cf-workerify.git
cd cf-workerify
npm install
npm test # node --testThe codebase is dependency-light (only prompts and picocolors) and
organized as:
bin/workerify.js CLI entry point
src/cli.js argument parsing + help
src/index.js orchestration (detect → ask → generate → install → summary)
src/detect.js framework detection
src/prompts.js interactive dialogs
src/config.js wrangler.toml + .dev.vars.example builders
src/generators/* per-framework file plans (vite, nextjs, nodejs, generic)
src/summary.js final summary + next steps
test/ unit + integration tests (prompts.inject driven)Roadmap / ideas
- [ ] Deploy straight from a fresh clone (zero interactive setup via flags).
- [ ] Support Nuxt / Astro / SvelteKit through their official adapters.
- [ ] Vercel / Netlify-to-Cloudflare migration mode.
License
MIT © manalejandro
Made with ☕ and the Cloudflare Workers SDK.
