Lunora Backend framework
A type-safe, realtime backend on your own Cloudflare account.
Four files and about forty lines below. Read them in order and you have seen the whole model, because there is not much more to it.
Describe the data once.
The schema is the source of truth for the database, the server functions and the client types. There is no second definition to keep in step.
import { defineSchema, defineTable, v } from "@lunora/server";
export default defineSchema({
messages: defineTable({
author: v.string(),
body: v.string(),
ts: v.number(),
}),
});Next, write plain functions against it
Write plain functions against it.
A query reads, a mutation writes, and both are ordinary TypeScript with a typed context. No controllers, no route table, no serialisation layer to hand-roll.
import { mutation, query, v } from "./_generated/server";
export const list = query.query(async ({ ctx }) =>
ctx.db.query("messages").order("desc").take(50));
export const send = mutation
.input({ author: v.string(), body: v.string() })
.mutation(async ({ ctx, args }) => {
await ctx.db.insert("messages", { ...args, ts: Date.now() });
});Next, read them from the client
The list stays live.
Queries are subscriptions. The component re-renders when the data behind it changes, on every connected client, without a socket to wire up or a cache to invalidate.
import { useQuery, useMutation } from "@lunora/react";
import { api } from "../lunora/_generated/api";
const messages = useQuery(api.messages.list) ?? [];
const send = useMutation(api.messages.send);Last, where all of this runs
It is your account.
Managed backends ask you to move the data to their servers and price it later. Lunora deploys the same primitives to the Cloudflare account you already own, so idle projects cost roughly nothing and leaving costs you a redeploy.
Workers
Your functions run as Workers, in the same runtime locally and in production.
Durable Objects
SQLite-backed state at the edge. Shard by tenant key or replicate reads globally.
D1
Relational storage for everything that outlives a single object.
R2
File and blob storage without egress fees.
Queues
Background work and scheduled jobs, without a second provider.
Where it sits
The tradeoff Lunora is built around: the developer experience of a managed backend, on infrastructure you control.
| Lunora | Convex | Firebase | Plain Cloudflare | |
|---|---|---|---|---|
| Type-safe end to end | partial | build it yourself | ||
| Realtime subscriptions | build it yourself | |||
| Runs on your own account | ||||
| Scales past one Durable Object | n/a | n/a | build it yourself | |
| Vite-first local development | n/a | n/a | build it yourself |
Start on the free tier.
The starter wires up the schema, the dev server on workerd, and a React client. Lunora is alpha software: install from the alpha tag and expect the API to move.
pnpm dlx lunorash@alpha init my-appcd my-app && pnpm installpnpm devBuild with us
Lunora is built in the open and moving fast. Issues, questions, and pull requests are all welcome.
