A single Cloudflare Worker serves both the static frontend and /api/* endpoints; pages as static assets do not count toward Worker requests
arzan — Laravel Starter Template
By hammadzafar05
Arzan is a Laravel-style full-stack starter for Cloudflare's free tier, with a React frontend and a Hono and D1 backend, including accounts, database migrations, tests, and one-command deployment.
Explore the design
Compare the page layouts and mobile experience. Open any screenshot for a closer look.
Actual screenshot captured by the server browser.
All pages & views 2
Screenshots show visual appearance; interactive behavior may differ.
What stands out
A quick read of the recorded project description.
Built-in complete account flows: registration, login, logout, remember me, forgot/reset password, email verification, change password, delete account, session management
D1 database schema is typed via Drizzle, and migrations are applied automatically on the first request after deployment, with no separate migration step
API tests run against a real in-memory D1, and Playwright end-to-end tests cover desktop and mobile and fail on CSP violations
Default security settings include PBKDF2 password hashing, revocable HttpOnly sessions, CSRF protection, per-IP rate limiting, and a strict CSP
AGENTS.md explains the architecture and conventions to coding agents, with a migration comparison table from Laravel
Template Details
Arzan is a full-stack starter deployed on Cloudflare Workers, positioned as a "Laravel-style" convention-based scaffold: the account system, starting layout, settings pages, and tests are ready after installation, and deployment takes a single command. It is not a PHP project; the underlying stack is TypeScript: the frontend uses React + Vite + TanStack Router/Query + shadcn/ui, and the backend uses Hono + D1 + Drizzle + Better Auth, all served by a single Cloudflare Worker.
The project includes registration, login, logout, remember me, forgot/reset password, email verification, change password, delete account, view and log out other sessions, and per-IP rate limiting. The app shell provides sidebar or top navigation layouts, three login page styles, a dashboard and settings pages (profile, password, sessions, appearance), supports light/dark/system themes, and adapts to mobile widths. The backend provides a Hono API and requireUser middleware; D1 uses Drizzle to manage a typed schema, and migrations are applied automatically on the first request after deployment; emails are printed to the terminal in development and can be connected to Resend in production.
Quality tools include strict TypeScript, Biome, API tests based on a real in-memory D1, Playwright end-to-end tests for desktop and mobile, and GitHub Actions CI. The repository also includes AGENTS.md, which explains the architecture and conventions to coding agents such as Claude Code, Cursor, and Codex.
Limitations: email is not free on Cloudflare; without a provider such as Resend configured, a deployed app will not send reset or verification emails, and the interface will indicate that password reset email is not set up and hide the email verification reminder. The free tier limits Worker CPU to 10 milliseconds per request, and the project uses WebCrypto PBKDF2 instead of the default pure-JS scrypt to fit that limit. Preview deployments do not inherit bindings by default, so a separate D1 database must be created. Roadmap items such as request helpers, example CRUD features, workspaces, and roles are not yet complete.
Is it right for your project?
Use Cases
- You want to build a full-stack app with an account system on Cloudflare's free tier at zero hosting cost
- You need a clearly conventional TypeScript project starting point that includes authentication, database migrations, tests, and CI
- You use coding agents such as Claude Code, Cursor, or Codex to develop features and want the agent to follow the existing architecture and security rules
- You are migrating from Laravel or Inertia and looking for corresponding implementations of routing, ORM, authentication, and testing
- You need desktop and mobile end-to-end tests and want the tests to be sensitive to CSP violations
Suitable For
- Developers familiar with TypeScript and React who are willing to use Cloudflare Workers and D1
- Full-stack projects that need a built-in account system and settings pages and do not want to build the authentication flow from scratch
- Teams or individuals who want to use coding agents for development and need clear architectural conventions
- Developers with Laravel experience who want to compare and migrate to a TypeScript full-stack stack
Getting started & customization
Use these recorded setup notes alongside the repository instructions for your chosen version.
- 1
Requires Node 22 or higher; you can create the project with npm create cloudflare@latest -- my-app --template=hammadzafar05/arzan
- 2
Copy .dev.vars.example to .dev.vars and set BETTER_AUTH_SECRET (you can generate one with openssl rand -hex 32)
- 3
Running npm run dev locally starts the app, API, and local D1 together; verification and reset emails are printed to the terminal
- 4
Before deployment, run npx wrangler login and set the secret with npx wrangler secret put BETTER_AUTH_SECRET; the first deployment automatically creates the D1 database
- 5
Preview deployments do not have a database by default; if you need a separate database, create arzan-preview and configure it in the previews section of wrangler.jsonc
License & source material
Usage conditions & limitations
Free to use · keep license noticeThis entry covers the free version under the MIT license in the public repository; the free scope is the code in that version and does not mean external services or third-party assets are free.
Must comply with when using
- You may use, modify, commercialize, and distribute this version of the code for free.
- When distributing copies or substantial portions of the code, retain the original author's copyright notice and the complete MIT license notice.
- The code is provided as is; warranties and limitations of liability are governed by the original license and applicable law.
Additional costs & items to verify
- Email functionality is not free on Cloudflare: in local development, emails and links are only printed to the terminal; after deployment, you must connect Resend (free tier 3,000 emails per month) or another email service provider yourself, otherwise the deployed app will not send any email.
- Without an email service provider configured, the deployed app will not send reset or verification emails, the interface will indicate that password reset email is not set up and hide the email verification reminder, and the related account flows will be unavailable.
- Preview deployments (one per branch or PR) do not inherit bindings by default and have no database out of the box; their API will return a corresponding notice. If you need a database, you must create and configure one separately.
- The one-click deploy button is only available after the repository is public.
- The deploy button requires the repository to be public; otherwise it cannot be used.
- Running and building require Node 22 or higher.
- Roadmap request helpers (zod validation, fail(), id helper, in-batch race protection) are not yet implemented and are planned features.
- Example CRUD features (server-side pagination, URL filtering, create/edit panels, empty and error states, tests) are not yet implemented and are planned features.
- Workspaces and roles (private workspace created on registration, role permissions, registration toggle) are not yet implemented and are planned features.
- Admin panel, file uploads (R2), background jobs (Queues), 2FA and passkeys, and billing plans are follow-up add-ons and are not included currently.
- Social login, 2FA, passkeys, and organization features require you to add Better Auth plugins, client plugins, and data tables and generate migrations yourself; they are not built in by default.
- If you add other analytics or third-party scripts yourself, you must add their sources in public/_headers yourself, otherwise CSP errors will occur.
- After changing the database or BETTER_AUTH_SECRET, old session cookies become invalid; you need to clear site data and register again, and accounts will not migrate to the new database.
- Demo images, fonts, icons, and other third-party assets must be checked against their respective licenses; you cannot judge them solely by the code's MIT license.
- External services such as domains, hosting, databases, payments, or AI may incur additional charges.
View Original Text Basis
Permission is hereby granted, free of charge
Original License Text
**Email** isn't free on Cloudflare. Locally, emails (with their links) print to the terminal. On a deployed site, add a [Resend](https://resend.com) key (free tier: 3,000 emails/month) or swap in another provider in `worker/email/index.ts`.
Original README
Until then, a deployed app sends nothing and **never writes reset or verification links to your logs**. The UI tells users that password-reset email isn't set up, and hides the "verify your email" nag.
Original README
**Preview deployments** (one per branch or pull request) don't inherit bindings. Out of the box a preview has no database, and its API says so.
Original README
**Option C — Deploy button** (works once the repository is public)
Original README
**The Deploy button doesn't work:** it needs the repository to be public.
Original README
Requires Node 22+.
Original README
- [ ] **Request helpers:** zod body validation with friendly errors, `fail()`, id helper, and in-batch guards that turn a race into a clear 409
Original README
- [ ] **Example CRUD feature:** a list with server-side paging and filters kept in the URL, add/edit sheet, empty and error states, tests
Original README
- [ ] **Workspaces & roles:** a private workspace per sign-up, roles and permissions, a sign-up on/off switch
Original README
- [ ] Add-ons later: admin panel, file uploads (R2), background jobs (Queues), 2FA and passkeys, billing recipes
Original README
**Social login, 2FA, passkeys, organizations:** add the Better Auth plugin in `worker/auth/index.ts` and its client plugin in `src/lib/auth-client.ts`, then add the tables it needs to `schema.ts` and run `npm run db:generate`.
Original README
**CSP error for `cloudflareinsights.com`:** that's Cloudflare Web Analytics, and `public/_headers` allows it. If you add other analytics or third-party scripts, add their origins there too.
Original README
https://github.com/hammadzafar05/arzan/blob/main/LICENSEhttps://github.com/hammadzafar05/arzan/blob/main/README.md**Signed out, or "something went wrong", after redeploying with a new database or `BETTER_AUTH_SECRET`:** old session cookies no longer match. Clear the site's data in your browser (or try a private window) and register again. Accounts don't carry over to a new database.
Original README
Compiled by DeepSeek based on repository license and README ·2026-10-01. Results only cover the materials read; dependencies, images, fonts, and subsequent term changes are subject to their respective original texts.
Project checks & description sources
Template Information
- Source platforms
- GitHub
- Documentation and maintenance reference score
- More documented · 85 / 100
- Technologies
- Laravel · React
- Website type
- Starter
How this score is calculated
Our heuristic uses license records (up to 30), a demo link (12), a preview (10), stars (15), recorded maintenance (15), description completeness (8), feature records (5) and classification data (5). It is not a code, security or performance test, or a Google score. A link does not establish tested functionality.
What to verify for this project
- Repository update recorded
- 2026-09-28
- Screenshot last checked
- 2026-10-01
A demo link is listed. Check it with your own content and viewport sizes; its presence does not confirm that forms, authentication or payments work.
The catalog identifies Laravel as the primary stack. Check the actual dependency manifest and lockfile for versions and hosting requirements. These notes use recorded metadata, not a code audit or a deployment test.
Use a selection guide →How this description was prepared
AI-assisted description based on catalog records and repository material. Repository authors are not automatically the reviewers of this description.
Automatically checked against source and license rules; no manual editorial review.
Inspect the recorded source material
SHA-256: 891fe2b995721556ea233f1a0a16ec3e05786a2a8fce26a26ba8eaeb38b87c3d
2026-10-01T02:25:40.246Z
Source file / repository<p align="center">
<img src="docs/screenshots/hero.png" alt="The Arzan dashboard right after installing: desktop and phone, light and dark" width="900">
<br><sub>The dashboard right after installing: desktop and phone, light and dark.</sub>
</p>
# Arzan
**A Laravel-style starter kit for full-stack apps on Cloudflare's free tier: auth, database, tests and one-command deploy, for $0/month.**
**Arzan** (ارزاں) means *affordable* in Urdu: real apps on $0/month hosting.
"Laravel-style" means the conventions, not PHP: accounts, starter layouts, settings and tests are ready on day one, there's one obvious place for everything, and deploying is one command. Underneath it's TypeScript: React + Vite + TanStack Router/Query + shadcn/ui on the front, Hono + D1 + Drizzle + Better Auth on the back, all served by **one Cloudflare Worker**. You own every line.
```sh
npm create cloudflare@latest -- my-app --template=hammadzafar05/arzan
```
[](https://deploy.workers.cloudflare.com/?url=https://github.com/hammadzafar05/arzan) · **[Live demo](https://arzan.softgrammer.com)** · [Quick start](#quick-start) · [Roadmap](#roadmap)
### Why Arzan
- **$0 hosting for real apps.** Pages are static assets (free and unlimited); only `/api/*` runs the Worker. Password hashing is tuned for the Free plan's 10 ms CPU limit.
- **Made for AI coding agents.** `AGENTS.md` gives Claude Code, Cursor or Codex the architecture and the rules, so "build me a feature" stays secure and on the free tier.
- **Tests against a real database.** API tests run against an in-memory D1 (not mocks), plus Playwright tests on desktop and phone that **fail on any CSP violation**.
- **Secure by default:** PBKDF2 passwords, revocable sessions, CSRF protection, per-IP rate limits, a strict CSP and safe redirects.
- **Migrations apply themselves.** Edit the schema, run `npm run db:generate`, deploy. The Worker migrates on its first request.
### What's included
| | |
|---|---|
| **Accounts** | Register, log in, log out, remember me, forgot / reset password, email verification, change password, delete account, see and sign out other sessions, per-IP rate limiting |
| **App shell** | Sidebar *or* header layout, three sign-in page styles, dashboard, settings (profile, password, sessions, appearance), light / dark / system theme, responsive to phone width |
| **Backend** | Hono API with a `requireUser` middleware, D1 via Drizzle (typed schema, generated migrations that apply themselves on deploy), pluggable email (console in dev, Resend in production) |
| **Quality** | Strict TypeScript, Biome, API tests on a real local D1, Playwright end-to-end tests (desktop + mobile), GitHub Actions CI |
| **AI-ready** | `AGENTS.md` explains the architecture and conventions to coding agents (Claude Code, Cursor, Codex…) |
## Built with Arzan
Built something with Arzan? Share it in [Discussions](https://github.com/hammadzafar05/arzan/discussions) and it can be featured here.
## Coming from Laravel or Inertia?
| Laravel | Arzan |
|---|---|
| `routes/web.php` + controllers | Pages: file routes in `src/routes/` (TanStack Router). API: Hono routers in `worker/routes/` |
| Blade / Inertia pages | A React app built once into static files; pages fetch JSON from `/api/*` with TanStack Query |
| Form Requests | Zod schemas; errors come back as `{ error: "…" }` and are shown as they are |
| Eloquent + migrations | Drizzle schema, `npm run db:generate`; migrations apply on the first request |
| `DB::transaction()` | `db.batch([...])` (one D1 transaction: validate first, then write in one go) |
| Breeze / Fortify | Better Auth; `requireUser` middleware is the `auth` middleware |
| `php artisan test` | `npm test` (Vitest + real in-memory D1), `npm run test:e2e` (Playwright) |
| A server to pay for | Cloudflare's free tier |
## Why it fits the free tier
| Free-plan limit | How Arzan stays inside it |
|---|---|
| 100,000 Worker requests / day | The app is a single-page app served as **static assets, which are free and unlimited**. Only `/api/*` calls run the Worker (`run_worker_first`). |
| 10 ms CPU per request | Better Auth's default password hashing on Workers is pure-JS scrypt (~150 ms) and can fail sign-ups with "exceeded CPU limit". Arzan plugs in **native WebCrypto PBKDF2** (~20 ms, already running in production on the Free plan) — only sign-up, sign-in and password changes hash; every other request is cheap. |
| D1: 5 M row reads, 100 k writes / day, 500 MB | Sessions are one indexed lookup per request; rate-limit state is a single row per IP and endpoint. Add indexes for anything you filter on. |
| Worker size 3 MB (gzipped) | The Worker bundle is ~370 KB gzipped. |
**Email** isn't free on Cloudflare. Locally, emails (with their links) print to the terminal. On a deployed site, add a [Resend](https://resend.com) key (free tier: 3,000 emails/month) or swap in another provider in `worker/email/index.ts`. Until then, a deployed app sends nothing and **never writes reset or verification links to your logs**. The UI tells users that password-reset email isn't set up, and hides the "verify your email" nag.
## Security defaults
| | |
|---|---|
| Passwords | PBKDF2-SHA256, 100,000 iterations (the Workers maximum), random salt. OWASP recommends more (600k), but Workers caps PBKDF2 at 100k; the iteration count is stored per hash so it can be raised later |
| Sessions | HttpOnly, Secure, SameSite cookies; server-side sessions you can list and revoke; password reset or change can sign out every device |
| CSRF | `csrf()` on every API route (blocks cross-site form posts, including login CSRF) plus no CORS headers (blocks cross-site JSON) |
| Rate limits | Per client IP (Cloudflare's `cf-connecting-ip`, not spoofable `X-Forwarded-For`): 5/min for sign-in and sign-up, 3/min for reset and verification emails |
| Headers | Strict Content-Security-Policy (no inline scripts), HSTS, X-Frame-Options, Referrer-Policy and Permissions-Policy on every page (`public/_headers`); secure headers and `no-store` on the API |
| Redirects | Post-login redirects must be same-site paths (`safeRedirect`) |
## Quick start
```sh
npm create cloudflare@latest -- my-app --template=hammadzafar05/arzan
cd my-app
cp .dev.vars.example .dev.vars # then set BETTER_AUTH_SECRET (openssl rand -hex 32)
npm run dev # http://localhost:5173 — app, API and a local D1 in one process
```
Or clone the repo and run `npm install` first. Requires Node 22+.
Local emails (verification, password reset) are printed in the terminal running `npm run dev`; click the link there.
## Deploy
**Option A — CLI**
```sh
npx wrangler login
npx wrangler secret put BETTER_AUTH_SECRET # paste a random 32+ character string
npm run deploy
```
The first deploy creates the D1 database automatically, and the Worker applies `drizzle/*.sql` on its first request. There's no separate migration step.
**Option B — Git (Workers Builds).** In the Cloudflare dashboard go to *Workers & Pages → Create → Import a repository*. The defaults work: `wrangler.jsonc` runs `npm run build` itself before `wrangler deploy` / `wrangler preview`, so no build command is needed. (Setting Build command to `npm run build` is fine too; wrangler then reuses that output.) Under *Settings → Variables and Secrets*, add `BETTER_AUTH_SECRET` (and optionally `RESEND_API_KEY`, `EMAIL_FROM`). The Worker `name` in `wrangler.jsonc` must match the dashboard.
**Preview deployments** (one per branch or pull request) don't inherit bindings. Out of the box a preview has no database, and its API says so. To give previews their own database, so they never touch production data:
```sh
npx wrangler d1 create arzan-preview
```
Then add it under `"previews"` in `wrangler.jsonc` (there's a commented example there). The Worker migrates it on the first request.
**Option C — Deploy button** (works once the repository is public)
[](https://deploy.workers.cloudflare.com/?url=https://github.com/hammadzafar05/arzan)
## Scripts
| Command | What it does |
|---|---|
| `npm run dev` | App + API + local D1 with hot reload (Vite + the Cloudflare plugin) |
| `npm run build` | Typecheck and build the app and the Worker |
| `npm run preview` | Build, then run the production bundle locally in workerd |
| `npm run deploy` | Build and deploy to Cloudflare |
| `npm test` | API and unit tests (Vitest, real in-memory D1) |
| `npm run test:e2e` | Playwright end-to-end tests against `npm run preview` |
| `npm run lint` / `format` | Biome check / fix |
| `npm run db:generate` | Create a migration in `drizzle/` from changes to `worker/db/schema.ts` |
| `npm run check` | Lint, typecheck, test and build (what CI runs) |
## Project layout
```
worker/ Cloudflare Worker (Hono)
app.ts routes: /api/health, /api/auth/* (Better Auth), then protected routes
auth/ Better Auth config + free-tier-safe password hashing
db/schema.ts Drizzle schema (auth tables + yours)
db/migrate.ts applies drizzle/*.sql on first request
email/ sendEmail() + templates
middleware.ts requireUser
routes/ your API routes (dashboard.ts is an example)
src/ React app
config.ts layout choice + navigation
routes/ file-based routes (TanStack Router)
_guest/ login, register, forgot/reset password (signed-out only)
_app/ dashboard, settings/* (signed-in only)
components/ui/ shadcn/ui components
components/layouts/ app (sidebar/header) and auth (simple/card/split) layouts
lib/auth-client.ts Better Auth client + session query
shared/config.ts app name, email verification, password rules (used by both sides)
drizzle/ generated SQL migrations
test/ API tests e2e/ Playwright tests
```
## Customize
- **Name and auth rules:** `shared/config.ts`. Set `requireEmailVerification: true` to block sign-in until the email is verified.
- **Layouts:** `src/config.ts`. Choose `app: "sidebar" | "header"` and `auth: "simple" | "card" | "split"`, and add navigation items.
- **Brand colours:** the CSS variables in `src/styles.css`, using the shadcn/ui theme tokens.
- **More components:** `npx shadcn@latest add <component>` (`components.json` is set up).
- **Social login, 2FA, passkeys, organizations:** add the Better Auth plugin in `worker/auth/index.ts` and its client plugin in `src/lib/auth-client.ts`, then add the tables it needs to `schema.ts` and run `npm run db:generate`.
## Add a feature, end to end
1. **Table:** add it to `worker/db/schema.ts`, then run `npm run db:generate`.
2. **API:** create `worker/routes/things.ts` (a Hono router; `c.get("user")` is the signed-in user), then mount it in `worker/app.ts` after `requireUser`.
3. **Page:** create `src/routes/_app/things.tsx`. Fetch with TanStack Query and `api("/things")`. Add it to `mainNav` in `src/config.ts`.
4. **Tests:** add them to `test/things.test.ts` using `createTestApp()`.
## Roadmap
Improvements coming next, drawn from building real client apps on Arzan. Progress is shared as it lands; ideas are welcome in Discussions.
- [ ] **Request helpers:** zod body validation with friendly errors, `fail()`, id helper, and in-batch guards that turn a race into a clear 409
- [ ] **Example CRUD feature:** a list with server-side paging and filters kept in the URL, add/edit sheet, empty and error states, tests
- [ ] **Workspaces & roles:** a private workspace per sign-up, roles and permissions, a sign-up on/off switch
- [ ] **Everyday helpers:** money and phone formatting, WhatsApp links, phone-first layout fixes, demo data in small steps
- [ ] Add-ons later: admin panel, file uploads (R2), background jobs (Queues), 2FA and passkeys, billing recipes
## Troubleshooting
- **`The package "@cloudflare/workerd-linux-64" could not be found`** when running tests: npm skipped the platform binary (this happens with some mirrors or cached installs). Run `rm -rf node_modules && npm install`, or install the matching version: `npm i --no-save @cloudflare/workerd-linux-64@$(node -p "require('workerd/package.json').version")`.
- **`npm run preview` shows old code after a rebuild:** stop and restart the preview server. Playwright reuses a running server locally (`reuseExistingServer`), so restart it before `npm run test:e2e` too.
- **The Deploy button doesn't work:** it needs the repository to be public.
- **The dashboard says "The API returned a web page instead of data":** requests to `/api/*` aren't reaching the Worker. Open `/api/health` on your site; it must return JSON. Check `run_worker_first: ["/api/*"]` in `wrangler.jsonc`, and that no route or Page Rule on your domain sends `/api/*` somewhere else.
- **Signed out, or "something went wrong", after redeploying with a new database or `BETTER_AUTH_SECRET`:** old session cookies no longer match. Clear the site's data in your browser (or try a private window) and register again. Accounts don't carry over to a new database.
- **CSP error for `cloudflareinsights.com`:** that's Cloudflare Web Analytics, and `public/_headers` allows it. If you add other analytics or third-party scripts, add their origins there too.
## License
[MIT](LICENSE)
Explore similar templates
Compare previews and descriptions within the same stack and category.

sage
Sage is a WordPress starter theme maintained by Roots, using Laravel Blade components and templates, Vite builds, Tailwind CSS, and built-in block editor support.
Laravel · Starter

wave
Wave is an open-source SaaS starter kit built on Laravel and released under the MIT license.
Laravel · SaaS

filament-starter
A Laravel TALL stack starter template maintained by Log1x, with a preconfigured Filament admin panel and plugins including Curator, Gravatar, Exceptions, Jobs Monitor, Breezy, Peek, and Logger.
Laravel · Starter

electrik
Electrik is a Laravel SaaS starter kit installed as a Composer package, with authentication, teams, Stripe subscription billing, and the Slate 3 interface under the Electrik\ namespace rather than copied into App\.
Laravel · SaaS

php-saas
php-saas is a Laravel-based SaaS starter positioned as an everything-included kit. It generates new projects via a global Composer command and includes authentication with two-factor, API tokens, Stripe and Paddle billing, and project, team, and organization management.
Laravel · SaaS

filament-jetstream
A Laravel starter kit that implements Jetstream-like authentication and account features using Filament's native panels and components. It includes login, registration, two-factor authentication, session management, user profiles, and optional teams and API tokens.
Laravel · Starter
