@flarefound/levi
v0.3.0
Published
The AppHost Framework for Cloudflare — Aspire for Cloudflare
Maintainers
Readme
levi
The AppHost Framework for Cloudflare
Declare your entire Cloudflare application topology — Workers, D1, KV, R2, Queues, Durable Objects, AI, Domains — in a single typed TypeScript file. Levi generates valid wrangler.jsonc configs, provisions resources, and orchestrates deployment.
Levi does not replace Wrangler. It orchestrates it.
npm install -D @flarefound/leviDocs | Getting Started | Examples | GitHub
Quick Start
npx levi init # scaffold a project (vinext, hono, or raw)
npx levi build # generate wrangler.jsonc for every worker
npx levi dev # local dev — spawns wrangler dev per worker
npx levi deploy # deploy in dependency orderThe AppHost File
One file. Full type safety. Zero lock-in.
// levi.app.ts
import { FlareApp } from "@flarefound/levi";
const app = new FlareApp("my-saas", {
compatibility_date: "2026-04-01",
});
// Storage
const db = app.addD1("main-db", { migrations: "./migrations" });
const cache = app.addKV("sessions", { ttl: 3600 });
const uploads = app.addR2("user-uploads");
// Queue + consumer
const jobs = app.addQueue("background-jobs", { retries: 3 });
// AI
const ai = app.addWorkersAI();
// API worker — binds to everything
const api = app.addWorker("api", {
framework: "hono",
entrypoint: "./packages/api/src/index.ts",
bindings: { DB: db, CACHE: cache, UPLOADS: uploads, JOBS: jobs, AI: ai },
routes: ["api.acme.com/*"],
crons: [{ pattern: "0 */6 * * *" }],
});
// Job runner — consumes the queue
app.addWorker("job-runner", {
entrypoint: "./packages/jobs/src/index.ts",
bindings: { DB: db, AI: ai },
consumers: [{ queue: jobs, maxBatchSize: 10 }],
});
// vinext frontend — service binding to API
app.addWorker("web", {
framework: "vinext",
entrypoint: "./packages/web",
bindings: { API: api.asService(), CACHE: cache },
routes: ["acme.com/*"],
});
// Domains
app.addDomain("acme.com", { ssl: "full_strict", redirectWww: true });
app.addDomain("api.acme.com", { ssl: "full_strict" });
export default app;Run levi build and Levi generates a complete, valid wrangler.jsonc for each worker — with all bindings, routes, crons, migrations, and compatibility flags resolved.
What Levi Generates
.levi/
├── workers/
│ ├── api/wrangler.jsonc ← D1, KV, R2, Queue, AI bindings
│ ├── job-runner/wrangler.jsonc ← D1, AI bindings + queue consumer
│ └── web/wrangler.jsonc ← service binding + vinext assets config
└── graph.json ← serialized dependency graphEvery generated config is a standalone, valid wrangler.jsonc. If you eject from Levi, you copy these files and you're done.
Cloudflare Primitive Coverage
Every Cloudflare primitive gets a typed builder method with full IntelliSense:
| Category | Primitive | Method |
|---|---|---|
| Compute | Workers | addWorker() |
| | Durable Objects | addDurableObject() |
| | Workflows | addWorkflow() |
| | Containers (beta) | addContainer() |
| Storage | D1 Database | addD1() |
| | KV Namespace | addKV() |
| | R2 Bucket | addR2() |
| | Queues | addQueue() |
| | Vectorize | addVectorize() |
| | Hyperdrive | addHyperdrive() |
| | Pipelines (beta) | addPipeline() |
| AI | Workers AI | addWorkersAI() |
| | AI Gateway | addAIGateway() |
| Network | Custom Domains | addDomain() |
| | Service Bindings | .asService() |
| | mTLS | addMTLS() |
CLI Commands
npx levi init # scaffold a project
npx levi build # generate wrangler.jsonc configs
npx levi build --env prod # generate configs for specific environment
npx levi dev # local dev with live reload
npx levi dev --env local # dev with local environment
npx levi deploy # provision + deploy all workers
npx levi deploy --env prod # deploy to specific environment
npx levi provision # create Cloudflare resources only
npx levi diff # compare local vs deployed configs
npx levi dashboard # ASCII topology dashboardProgrammatic API
The same package works as a library:
import { FlareApp, WranglerGenerator } from "@flarefound/levi";
const app = new FlareApp("my-app", { compatibility_date: "2026-04-01" });
const db = app.addD1("db");
const api = app.addWorker("api", {
entrypoint: "./src/index.ts",
bindings: { DB: db },
});
// Validate the graph
const result = app.build();
console.log(result.deployOrder); // ["db", "api"]
// Generate wrangler configs
const gen = new WranglerGenerator(app);
for (const [name, config] of gen.generateAll()) {
console.log(name, WranglerGenerator.serialize(config));
}DNS Provisioning
Levi provisions custom domains via the Cloudflare REST API:
app.addDomain("api.example.com", {
ssl: "full_strict",
redirectWww: true,
});export CLOUDFLARE_API_TOKEN=your-token
npx levi provisionCreates DNS records, configures SSL mode, and sets up www redirects — all idempotent.
vinext First-Class Support
vinext is the recommended frontend framework. framework: "vinext" auto-configures:
- SSR entry point (
dist/server/index.js) - Static assets serving (
dist/client/) nodejs_compatcompatibility flag- Service bindings for frontend-to-API communication
TanStack SPA Support
TanStack SPA is a pure client-side frontend using Vite + React + TanStack Query + TanStack Router. framework: "tanstack" auto-configures:
- Static assets serving (
dist/client/) - Service binding to connected API workers
- No SSR — all data fetching via TanStack Query
const api = app.addWorker("api", {
framework: "hono",
entrypoint: "./src/api/index.ts",
bindings: { DB: db },
});
const web = app.addWorker("web", {
framework: "tanstack",
entrypoint: "./src/web",
bindings: { API: api.asService() },
});Zero Lock-in
Levi generates standard wrangler.jsonc files. At any point:
npx levi ejectThis copies the configs to your project root. Delete Levi, and you're running on pure Wrangler. No proprietary SDK, no platform dependency, no vendor lock-in.
Design Principles
- Wrangler is the engine. Levi is the driver. Never reimplement what Wrangler does.
- TypeScript-first. The apphost file is the single source of truth. All configs are generated.
- Expose everything. Every Cloudflare primitive gets a typed builder. No magic.
- Local dev is first-class.
levi devruns all workers locally with correct bindings. - Incremental adoption. Use Levi for one worker or a 12-service monorepo.
Requirements
- Node.js >= 18
- Wrangler >= 3.0 (peer dependency)
- Cloudflare account (for deployment)
License
MIT — Flarefound
