the best lightweight web dev stack built on bun
at main 115 lines 3.2 kB view raw view rendered
1# Tacy Stack 2 3This is (in my very biased opinion) the absolute best and most enjoyable way to build detailed web apps on top of Bun. 4 5It uses Lit, Bun, and Drizzle as the main stack and they all work together to make a wonderful combo. 6 7## Quick Start 8 9```bash 10bunx tacy-stack@latest 11``` 12 13The CLI will guide you through creating a new project with an interactive prompt. 14 15**Manual setup:** 16 17```bash 18git clone <this-repo> my-app 19cd my-app 20bun run setup 21bun dev 22``` 23 24Your server will be running at `http://localhost:3000` with hot module reloading. Just edit any `.ts`, `.html`, or `.css` file and watch it update in the browser. 25 26## How does it work? 27 28The development flow is really nice in my opinion. The server imports HTML files as route handlers. Those HTML files import TypeScript components using `<script type="module">`. The components are just Lit web components that self-register as custom elements. Bun sees all this and bundles everything automatically including linked styles. 29 30```typescript 31// src/index.ts - Server imports HTML as routes 32import indexHTML from "./pages/index.html"; 33 34Bun.serve({ 35 port: 3000, 36 routes: { 37 "/": indexHTML, 38 }, 39 development: { 40 hmr: true, 41 console: true, 42 }, 43}); 44``` 45 46```html 47<!-- src/pages/index.html --> 48<!DOCTYPE html> 49<html lang="en"> 50 <head> 51 <link rel="stylesheet" href="../styles/main.css" /> 52 </head> 53 <body> 54 <counter-component count="0"></counter-component> 55 <script type="module" src="../components/counter.ts"></script> 56 </body> 57</html> 58``` 59 60```typescript 61// src/components/counter.ts 62import { LitElement, html, css } from "lit"; 63import { customElement, property } from "lit/decorators.js"; 64 65@customElement("counter-component") 66export class CounterComponent extends LitElement { 67 @property({ type: Number }) count = 0; 68 69 static styles = css` 70 :host { 71 display: block; 72 padding: 1rem; 73 } 74 `; 75 76 render() { 77 return html` 78 <div>${this.count}</div> 79 <button @click=${() => this.count++}>+</button> 80 `; 81 } 82} 83``` 84 85The database uses Drizzle ORM for type-safe SQLite access. Schema changes are handled through migrations: 86 87```bash 88# Make changes to src/db/schema.ts, then: 89bun run db:push # Push schema to database 90bun run db:studio # Visual database browser 91``` 92 93## Commands 94 95```bash 96bun dev # Development server with hot reload 97bun test # Run tests 98bun run db:generate # Generate migrations from schema 99bun run db:push # Push schema to database 100bun run db:studio # Open Drizzle Studio 101``` 102 103The canonical repo for this is hosted on tangled over at [`dunkirk.sh/tacy-stack`](https://tangled.org/@dunkirk.sh/tacy-stack) 104 105<p align="center"> 106 <img src="https://raw.githubusercontent.com/taciturnaxolotl/carriage/main/.github/images/line-break.svg" /> 107</p> 108 109<p align="center"> 110 <i><code>&copy 2025-present <a href="https://dunkirk.sh">Kieran Klukas</a></code></i> 111</p> 112 113<p align="center"> 114 <a href="https://tangled.org/dunkirk.sh/tacy-stack/raw/main/README.md"><img src="https://img.shields.io/static/v1.svg?style=for-the-badge&label=License&message=MIT&logoColor=d9e0ee&colorA=363a4f&colorB=b7bdf8"/></a> 115</p>