Package Exports
- better-cf
- better-cf/cli
- better-cf/queue
- better-cf/queue/internal
- better-cf/testing
Readme
better-cf
Opinionated Cloudflare Queue SDK + automation CLI designed for modern developer experience.
Why better-cf
better-cf keeps Cloudflare Queue primitives but improves day-to-day ergonomics:
- typed queue contracts from one place
- less manual entry/config wiring
- structured automation for local dev and codegen
- predictable runtime and testing APIs
Quickstart (Existing Project)
npm i better-cf zod
npm i -D wrangler @cloudflare/workers-types typescript
npx better-cf init
npm run devQuickstart (New Project)
npx better-cf create my-worker
cd my-worker
npm run devUse a specific package manager during create:
npx better-cf create my-worker --use-pnpm
npx better-cf create my-worker --use-bunCanonical Imports
- Queue runtime:
better-cf/queue - Testing helpers:
better-cf/testing - CLI binary:
better-cf
Core Workflow
better-cf dev continuously orchestrates:
- scan queue definitions
- validate config
- generate
.better-cf/entry.tsand type files - patch wrangler queue sections
- infer env types
- run/restart
wrangler dev - re-run on source/config changes
One-shot mode:
better-cf generateExample Patterns
Single queue with typed payload
import { createSDK } from 'better-cf/queue';
import { z } from 'zod';
type Env = { QUEUE_SIGNUP: Queue };
const { defineQueue, defineWorker } = createSDK<Env>();
export const signupQueue = defineQueue({
message: z.object({ email: z.string().email() }),
process: async (ctx, msg) => {
console.log(ctx.message.id, msg.email);
},
retry: 3,
retryDelay: '30s'
});
export default defineWorker({
async fetch() {
return new Response('ok');
}
});Batch mode
const auditQueue = defineQueue({
message: z.object({ action: z.string() }),
batch: { maxSize: 10, timeout: '30s', maxConcurrency: 2 },
processBatch: async (ctx, messages) => {
console.log(messages.length, ctx.batch.queue);
ctx.batch.ackAll();
}
});Queue unit testing
import { testQueue } from 'better-cf/testing';
const result = await testQueue(signupQueue, {
env: {},
message: { email: 'dev@example.com' }
});
expect(result.acked).toHaveLength(1);Comparison with Cloudflare Queue Workflows
| Concern | Cloudflare path | better-cf path |
|---|---|---|
| Queue contract shape | Convention/custom runtime checks | defineQueue({ message: z.object(...) }) |
| Entry + config wiring | Manual exports + Wrangler maintenance | Generated entry + automated Wrangler patching |
| Local dev orchestration | Team-managed scripts | One better-cf dev loop |
| Queue test harness | Custom mocks/harnesses | testQueue helper |
Detailed comparison is being migrated to the separate docs repository.
Limitations
Not supported
- Pull-message runtime abstraction implementation
- Queue metrics/dashboard abstraction
- Dynamic runtime queue declaration
- Unsupported remote queue local-dev parity modes
Known gaps
- Non-literal config extraction can reduce static mapping fidelity
- Legacy service-worker adapter is compatibility-oriented
- Non-standard worker export patterns beyond documented variants are out of scope
Use native Cloudflare APIs directly where the SDK intentionally does not abstract.
Docs
Docs are being migrated to a separate Next.js application repository.
During migration, legacy docs source may still exist under apps/docs, but it is no longer part of package CI/CD.