Kilat

Free to start. Zero ops.
A full-stack starter on Cloudflare Workers.

One Cloudflare Worker: Hono +D1 + Inertia v3 with in-process SSR. React, Svelte, or Vue — your choice. Auth, migrations, tests — wired end to end. wrangler deploy and you're live on 300+ edge locations.

zsh
◆ Select a JavaScript framework:
│ ○ React 19
│ ● Svelte 5
│ ○ Vue 3
│ ↑/↓ to navigate • Enter: confirm
◆ Select a styling approach:
│ ● Vanilla CSS
│ ○ Tailwind CSS v4
↓ Downloading Kilat (Svelte 5 + Vanilla CSS)...
└ Kilat project created! Svelte 5 + Vanilla CSS

Have Bun? bun create kilat@latest my-app is faster.

WorkersHonoInertia v3D1Web Crypto
1Worker, three clients
300+edge locations
6templates
0servers to manage

From zero to live in two commands

No DevOps degree required. No YAML files. No Kubernetes.

1
npm create kilat@latest my-app

Scaffold a full-stack app — auth, SSR, migrations, tests, all wired.

2
wrangler deploy

Live on 300+ edge locations. No Docker, no VPS, no reverse proxy.

3
done.

Free tier: 100K requests/day, 500 MB D1. No credit card required.

Outgrew the free tier? Migrate to Dulak— same stack on Bun, zero platform limits, one AI agent prompt.

Working code, not wiring homework

Auth, migrations, SSR, tests — running end to end on Workers, not left for you to wire.

Auth, complete

Register, login, logout, forgot/reset password and Google OAuth — PBKDF2 (Web Crypto), DB-backed sessions, CSRF.

Inertia v3 + SSR

Full HTML on first load, SPA after. In-process SSR inside the Worker, 409 version negotiation, partial reloads, flash.

Edge-native D1

SQLite at the edge via D1. Versioned migrations via Wrangler. Raw prepared statements — no ORM, zero abstraction tax.

One Worker, three clients

React 19, Svelte 5, and Vue 3 templates with Tailwind CSS v4 — same auth, SSR, and test suite.

Web Crypto passwords

PBKDF2-HMAC-SHA256 via crypto.subtle — zero-dependency, runs natively in Workers. No WASM, no native modules.

Production-grade ops

Per-request logging, security headers (CSP, nosniff, frame denial), /health check, HSTS. wrangler deploy = live.

Why Kilat exists

Because your first week should be business logic, not infrastructure.

Edge-native means zero ops

No Docker, no VPS, no process supervisor. The whole stack is Cloudflare Workers: wrangler dev for local, wrangler deploy for production. D1 is the database, Workers Static Assets serves the client bundle, Web Crypto handles password hashing.

Because it is free

100K requests/day, 500 MB D1 database, 20K static assets — all on Cloudflare's free tier. No credit card, no server to rent, no database to provision. Outgrew it? Dulak runs the same stack on Bun with zero platform limits. See the free tier limits and migration guide.

Built for AI agents

Conventions codified in AGENTS.md, validation errors with exact shapes, strict TypeScript that fails at compile time, deterministic tests as the safety net. A codebase an agent can extend without inventing conventions stays coherent.

One Worker. Three clients.

Pick a framework and styling — the same Login page, in your stack.

default (React 19 + vanilla CSS)
import { Head, Link, useForm } from "@inertiajs/react";
import AuthLayout from "../components/AuthLayout";
import Field from "../components/Field";
import "../components/AuthLayout.css";
export default function Login() {
const form = useForm({ email: "", password: "" });
const submit = (e: React.FormEvent) => {
e.preventDefault();
form.post("/login");
};
return (
<AuthLayout>
<Head title="Login" />
<h1 className="auth-sub">Welcome back</h1>
<form onSubmit={submit} noValidate>
<Field id="email" label="Email" error={form.errors.email}>
<input
id="email" type="email" autoComplete="email"
value={form.data.email}
onChange={(e) => form.setData("email", e.target.value)}
/>
</Field>
<button className="btn btn-primary btn-block" type="submit"
disabled={form.processing}>
{form.processing ? "Signing in…" : "Sign in"}
</button>
</form>
</AuthLayout>
);
}
svelte-vanilla (Svelte 5 + scoped <style>)
<script lang="ts">
import { Link, useForm } from '@inertiajs/svelte'
import AuthLayout from '../components/AuthLayout.svelte'
import Field from '../components/Field.svelte'
let { googleEnabled = false, notice = null } = $props()
const form = useForm({ email: '', password: '' })
function submit(e: SubmitEvent) {
e.preventDefault()
form.post('/login')
}
</script>
<AuthLayout>
<h1 class="auth-sub">Welcome back</h1>
<form onsubmit={submit} novalidate>
<Field id="email" label="Email" error={form.errors.email}>
<input id="email" type="email" bind:value={form.email}
onchange={() => form.clearErrors('email')} />
</Field>
<button class="btn btn-primary btn-block" type="submit"
disabled={form.processing}>
{form.processing ? 'Signing in…' : 'Sign in'}
</button>
</form>
</AuthLayout>
vue-vanilla (Vue 3 + scoped <style>)
<script setup lang="ts">
import { Head, Link, useForm } from "@inertiajs/vue3";
import AuthLayout from "../components/AuthLayout.vue";
import Field from "../components/Field.vue";
defineProps<{ googleEnabled?: boolean; notice?: string | null }>();
const form = useForm({ email: "", password: "" });
function submit() {
form.post("/login");
}
</script>
<template>
<Head><title>Login</title></Head>
<AuthLayout>
<h1 class="auth-sub">Welcome back</h1>
<form @submit.prevent="submit" novalidate>
<Field id="email" label="Email" :error="form.errors.email">
<input id="email" type="email" v-model="form.email"
@change="form.clearErrors('email')" />
</Field>
<button class="btn btn-primary btn-block" type="submit"
:disabled="form.processing">
{{ form.processing ? "Signing in…" : "Sign in" }}
</button>
</form>
</AuthLayout>
</template>

Start in one command.

npm create kilat@latest

FAQ

The short version. For the long version, read the comparison article.

How is Kilat different from Next.js, Nuxt, or SvelteKit?

Meta-frameworks give you conventions to learn and leave auth, sessions, and persistence for you to wire. Kilat ships those already wired — auth, DB-backed sessions, CSRF, migrations — as plain TypeScript you own and can grep when something breaks. One command deploys to 300+ edge locations on a free tier of 100K requests/day (3× Vercel's 100K/month). Pick a meta-framework for RSC or edge middleware; pick Kilat for a wired, ownable stack you understand in an afternoon.

How is Kilat different from Dulak?

Same philosophy: fork it, skip the architecture decisions, just build your app and deploy. The difference is the runtime. Kilat runs on Cloudflare Workers — zero ops, 300+ edge locations, free to start (100K req/day, 500 MB D1). Dulak runs on Bun — self-hosted, no platform limits: unlimited requests, CPU time, and database size, argon2 instead of PBKDF2, sync DB access. Start on Kilat's free tier; when you outgrow it, migrate to Dulak with a single AI agent prompt.

Do I have to use React?

No. Kilat ships templates for React 19, Svelte 5, and Vue 3 — each with vanilla CSS or Tailwind CSS v4. The server side (Hono, D1, auth) is identical across all of them.

Why no ORM?

ORMs were built to help humans avoid writing SQL. In 2026, AI generates correct, optimized raw SQL on demand — the human-friction problem ORMs solved is gone. What remains is the cost: an ORM is a dependency you upgrade, audit, and debug, and it adds a layer between you and the database that hides the actual query plan. D1 with prepared statements is explicit and zero-dependency. You see the exact SQL that runs.

Is it production-ready?

Yes — every guardrail a deployed app needs is wired and tested, not scaffolded: PBKDF2 passwords (Web Crypto), DB-backed sessions (not JWT), CSRF origin checks, security headers (CSP, nosniff, frame denial), versioned migrations, HSTS, and an E2E suite that boots the full app. The server side is not a demo — it is the same code path that runs in production. What is missing is your business logic, and that is the point.

Will this still work in 5–10 years?

Yes, and here is why: Kilat is a boilerplate you fork and own, not a framework that can be deprecated out from under you. The stack is chosen for longevity — Cloudflare Workers, Hono, D1, and Inertia are stable, pinned versions with no pending rewrites. When a dependency does release a new major, it is a deliberate migration you schedule and test — not an emergency. And because there is no ORM, no SDK, no proprietary abstraction layer, the code you own is just TypeScript, SQL, and HTTP — readable and maintainable by any developer or AI agent, now and in 2036.