The Stack
Billet is a server-rendered TypeScript starter built on Bun. Templates are JSX, compiled by Bun and rendered to HTML in the same process that answers the request—no client framework, no virtual DOM, no hydration step. Pages arrive as plain HTML, and a few hundred lines of signals bind interactivity to that markup where a page needs it.
How data flows
Every request follows the same three-step path. Services fetch or mutate data, controllers decide what to do with it, and templates turn it into HTML. There are no loading states because data is always resolved before the template renders.
services/ → controllers/ → templates/ query the db call services receive props return typed pick a template render HTML data pass data in return Response
Project structure
src/ ├── client/ # Browser-side code │ ├── main.ts # Entry point: registers pages and components │ ├── page-lifecycle.ts # Per-page init and cleanup │ ├── reactive/ # Signals, components, bind(), submit helper │ ├── style.css # Global styles (CSS entry point) │ ├── components/ # Shared components + CSS (nav, todo list) │ └── pages/ # Page JS & CSS (co-located) │ ├── server/ # Server-side code (Bun) │ ├── main.ts # Server entry point │ ├── routes/ # URL → controller mapping │ ├── controllers/ # Request handlers │ │ ├── app/ # View controllers (HTML) │ │ ├── api/ # API controllers (JSON) │ │ ├── auth/ # Auth flows │ │ └── team/ # Team management (TEAMS_ENABLED) │ ├── templates/ # Full-page JSX templates │ ├── components/ # Reusable server JSX │ ├── services/ # Business logic & data │ ├── middleware/ # Auth, CSRF, rate limiting │ ├── utils/ # Shared helpers │ └── database/ # Migrations │ └── shared/ # The data-* vocabulary and header names both sides import
Feedback stack
Five layers of automated checks run before code reaches production.
| Layer | What it catches |
|---|---|
| TypeScript strict mode | Type errors, null safety violations, implicit any |
| Biome linting | Code quality, unused variables, console statements, unsafe patterns |
| Pre-commit hooks | Formatting, lint errors, and type checks before every commit |
| Test suite | Regressions across services, controllers, templates, and client scripts |
| GitHub Actions CI | Lint, build, and the full suite against a real PostgreSQL before a branch can merge; a scheduled audit flags vulnerable dependencies |
Technology choices
A small, deliberate set of tools chosen for speed, simplicity, and minimal abstraction.
| Technology | Role |
|---|---|
| Bun | Runtime, bundler, test runner, and package manager |
| PostgreSQL | Primary data store with raw SQL via tagged templates |
| Bun CSS bundler | Native @import resolution, CSS nesting, and minification |
| Signals | An in-repo reactive layer that binds to server markup by name—no virtual DOM, no eval, no full SPA |
| Preact | The JSX runtime, used only by renderToString() on the server—none of it reaches the browser |
| Resend | Transactional email in production; a console provider takes its place in development |