# Stack Research **Domain:** Single-user gear management and purchase planning web app **Researched:** 2026-03-14 **Confidence:** HIGH ## Recommended Stack ### Core Technologies | Technology | Version | Purpose | Why Recommended | |------------|---------|---------|-----------------| | Bun | 1.3.x | Runtime, package manager, bundler | User constraint. Built-in SQLite, fast installs, native TS support. Eliminates need for separate runtime/bundler/pkg manager. | | React | 19.2.x | UI framework | Industry standard, massive ecosystem, stable. Server Components not needed for this SPA -- stick with client-side React. | | Vite | 8.0.x | Dev server, production builds | Rolldown-based builds (5-30x faster than Vite 7). Zero-config React support. Bun-compatible. HMR out of the box. | | Hono | 4.12.x | Backend API framework | Built on Web Standards, first-class Bun support, zero dependencies, tiny (~12kB). Perfect for a lightweight REST API. Faster than Express on Bun benchmarks. | | SQLite (bun:sqlite) | Built-in | Database | Zero-dependency, built into Bun runtime. 3-6x faster than better-sqlite3. Single file database -- perfect for single-user app. No server process to manage. | | Drizzle ORM | 0.45.x | Database ORM, migrations | Type-safe SQL, ~7.4kB, zero dependencies. Native bun:sqlite driver support. SQL-like query API (not abstracting SQL away). Built-in migration tooling via drizzle-kit. | | Tailwind CSS | 4.2.x | Styling | CSS-native configuration (no JS config file). Auto content detection. Microsecond incremental builds. Perfect for "light, airy, minimalist" design constraint. | | TanStack Router | 1.167.x | Client-side routing | Full type-safe routing with typed params and search params. File-based route generation. Better SPA experience than React Router v7 (whose best features require framework mode). | | TanStack Query | 5.93.x | Server state management | Handles API data fetching, caching, and synchronization. Eliminates manual loading/error state management. Automatic cache invalidation on mutations. | | Zustand | 5.0.x | Client state management | Minimal boilerplate, ~1kB. For UI state like active filters, modal state, theme. TanStack Query handles server state; Zustand handles the rest. | | Zod | 4.3.x | Schema validation | Validates API inputs on the server, form data on the client, and shares types between both. Single source of truth for data shapes. | | TypeScript | 5.x (Bun built-in) | Type safety | Bun transpiles TS natively -- no tsc needed at runtime. Catches bugs at dev time. Required by Drizzle and TanStack Router for type-safe queries and routes. | ### Supporting Libraries | Library | Version | Purpose | When to Use | |---------|---------|---------|-------------| | @tanstack/react-query-devtools | 5.x | Query debugging | Development only. Inspect cache state, refetch timing, query status. | | drizzle-kit | latest | DB migrations CLI | Run `drizzle-kit generate` and `drizzle-kit migrate` for schema changes. | | @hono/zod-validator | latest | Request validation middleware | Validate API request bodies/params using Zod schemas in Hono routes. | | clsx | 2.x | Conditional class names | When building components with variant styles. Pairs with Tailwind. | | @tanstack/react-router-devtools | latest | Router debugging | Development only. Inspect route matches, params, search params. | ### Development Tools | Tool | Purpose | Notes | |------|---------|-------| | Bun | Test runner | `bun test` -- built-in, Jest-compatible API. No need for Vitest or Jest. | | Biome | Linter + formatter | Single tool replacing ESLint + Prettier. Fast (Rust-based), minimal config. `biome check --write` does both. | | Vite React plugin | React HMR/JSX | `@vitejs/plugin-react` for Fast Refresh during development. | ## Installation ```bash # Initialize project bun init # Core frontend bun add react react-dom @tanstack/react-router @tanstack/react-query zustand zod clsx # Core backend bun add hono @hono/zod-validator drizzle-orm # Styling bun add tailwindcss @tailwindcss/vite # Build tooling bun add -d vite @vitejs/plugin-react typescript @types/react @types/react-dom # Database tooling bun add -d drizzle-kit # Linting + formatting bun add -d @biomejs/biome # Dev tools (optional but recommended) bun add -d @tanstack/react-query-devtools @tanstack/react-router-devtools ``` ## Architecture Pattern **Monorepo-lite (single package, split directories):** ``` /src /client -- React SPA (Vite entry point) /routes -- TanStack Router file-based routes /components -- Shared UI components /stores -- Zustand stores /api -- TanStack Query hooks (fetch wrappers) /server -- Hono API server /routes -- API route handlers /db -- Drizzle schema, migrations /shared -- Zod schemas shared between client and server /public -- Static assets, uploaded images ``` Bun runs the Hono server, which also serves the Vite-built SPA in production. In development, Vite dev server proxies API calls to the Hono backend. ## Alternatives Considered | Recommended | Alternative | When to Use Alternative | |-------------|-------------|-------------------------| | Hono | Elysia | If you want end-to-end type safety with Eden Treaty. Elysia is Bun-native but heavier, more opinionated, and has a smaller ecosystem than Hono. | | Hono | Express | Never for new Bun projects. Express is Node-centric, not built on Web Standards, slower on Bun. | | TanStack Router | React Router v7 | If you want the simplest possible routing with minimal type safety. React Router v7's best features (loaders, type safety) require framework mode which adds complexity. | | Drizzle ORM | Prisma | If you have a complex relational model and want auto-generated migrations. But Prisma is heavy (~8MB), generates a query engine binary, and has weaker SQLite support. | | Drizzle ORM | Kysely | If you want a pure query builder without ORM features. Kysely is lighter but lacks built-in migration tooling. | | Zustand | Jotai | If you prefer atomic state (bottom-up). Zustand is simpler for this app's needs -- a few global stores, not many independent atoms. | | Tailwind CSS | Vanilla CSS / CSS Modules | If you strongly prefer writing plain CSS. But Tailwind accelerates building consistent minimalist UIs and requires less design system setup. | | bun:sqlite | PostgreSQL | If you later need multi-user with concurrent writes. Overkill for single-user. Adds a database server dependency. | | Biome | ESLint + Prettier | If you need specific ESLint plugins not yet in Biome. But Biome covers 95% of use cases with zero config. | | Vite | Bun's built-in bundler | Bun can serve HTML directly as of 1.3, but Vite's ecosystem (plugins, HMR, proxy) is far more mature for SPA development. | ## What NOT to Use | Avoid | Why | Use Instead | |-------|-----|-------------| | Next.js | Server-centric framework. Massive overhead for a single-user SPA. Forces Node.js patterns. No benefit without SSR/SSG needs. | Vite + React + Hono | | Remix / React Router framework mode | Adds server framework complexity. This is a simple SPA with a separate API -- framework routing is unnecessary overhead. | TanStack Router (SPA mode) | | better-sqlite3 | Requires native compilation, compatibility issues with Bun. bun:sqlite is built-in and 3-6x faster. | bun:sqlite (built into Bun) | | Redux / Redux Toolkit | Massive boilerplate for a small app. Actions, reducers, slices -- all unnecessary when Zustand does the same in 10 lines. | Zustand | | Mongoose / MongoDB | Document DB is wrong fit. Gear items have relational structure (items belong to setups, threads reference items). SQL is the right model. | Drizzle + SQLite | | Axios | Unnecessary abstraction over fetch. Bun and browsers both have native fetch. TanStack Query wraps fetch already. | Native fetch | | styled-components / Emotion | CSS-in-JS adds runtime overhead and bundle size. Tailwind is faster (zero runtime) and better for consistent minimalist design. | Tailwind CSS | | Jest / Vitest | Bun has a built-in test runner with Jest-compatible API. No need for external test frameworks. | bun test | | ESLint + Prettier | Two tools, complex configuration, slow (JS-based). Biome does both in one tool, faster. | Biome | ## Version Compatibility | Package A | Compatible With | Notes | |-----------|-----------------|-------| | Bun 1.3.x | bun:sqlite (built-in) | SQLite driver is part of the runtime, always compatible. | | Drizzle ORM 0.45.x | bun:sqlite via `drizzle-orm/bun-sqlite` | Official driver. Import from `drizzle-orm/bun-sqlite`. | | Drizzle ORM 0.45.x | drizzle-kit (latest) | drizzle-kit handles migration generation/execution. Must match major drizzle-orm version. | | React 19.2.x | TanStack Router 1.x | TanStack Router 1.x supports React 18+ and 19.x. | | React 19.2.x | TanStack Query 5.x | TanStack Query 5.x supports React 18+ and 19.x. | | React 19.2.x | Zustand 5.x | Zustand 5.x supports React 18+ and 19.x. | | Vite 8.x | @vitejs/plugin-react | Check plugin version matches Vite major. Use latest plugin for Vite 8. | | Tailwind CSS 4.2.x | @tailwindcss/vite | v4 uses Vite plugin instead of PostCSS. Import as `@tailwindcss/vite` in vite config. | | Zod 4.x | @hono/zod-validator | Verify @hono/zod-validator supports Zod 4. If not, pin Zod 3.23.x until updated. | ## Key Configuration Notes ### Bun + Vite Setup Vite runs as the dev server for the frontend. The Hono API server runs separately. Use Vite's `server.proxy` to forward `/api/*` requests to the Hono backend during development. ### SQLite WAL Mode Enable WAL mode on database initialization for better performance: ```typescript import { Database } from "bun:sqlite"; const db = new Database("gearbox.db"); db.run("PRAGMA journal_mode = WAL"); db.run("PRAGMA foreign_keys = ON"); ``` ### Tailwind v4 (No Config File) Tailwind v4 uses CSS-native configuration. No `tailwind.config.js` needed: ```css @import "tailwindcss"; @theme { --color-primary: #2563eb; --font-sans: "Inter", sans-serif; } ``` ### Drizzle Schema Example (bun:sqlite) ```typescript import { sqliteTable, text, integer, real } from "drizzle-orm/sqlite-core"; export const gearItems = sqliteTable("gear_items", { id: integer("id").primaryKey({ autoIncrement: true }), name: text("name").notNull(), category: text("category").notNull(), weightGrams: real("weight_grams"), priceCents: integer("price_cents"), source: text("source"), notes: text("notes"), createdAt: integer("created_at", { mode: "timestamp" }).notNull(), }); ``` ## Sources - [Bun official docs](https://bun.com/docs) -- bun:sqlite features, runtime capabilities (HIGH confidence) - [Hono official docs](https://hono.dev/docs) -- Bun integration, static serving (HIGH confidence) - [Drizzle ORM docs - Bun SQLite](https://orm.drizzle.team/docs/connect-bun-sqlite) -- driver support verified (HIGH confidence) - [Vite releases](https://vite.dev/releases) -- v8.0 with Rolldown confirmed (HIGH confidence) - [Tailwind CSS v4.2 blog](https://tailwindcss.com/blog/tailwindcss-v4) -- CSS-native config, Vite plugin (HIGH confidence) - [TanStack Router docs](https://tanstack.com/router/latest) -- v1.167.x confirmed (HIGH confidence) - [TanStack Query docs](https://tanstack.com/query/latest) -- v5.93.x for React (HIGH confidence) - [Zustand npm](https://www.npmjs.com/package/zustand) -- v5.0.x confirmed (HIGH confidence) - [Zod v4 release notes](https://zod.dev/v4) -- v4.3.x confirmed (MEDIUM confidence -- verify @hono/zod-validator compatibility) - [React versions](https://react.dev/versions) -- v19.2.x confirmed (HIGH confidence) - [Bun SQLite vs better-sqlite3 benchmarks](https://bun.com/docs/runtime/sqlite) -- 3-6x performance advantage (HIGH confidence) --- *Stack research for: GearBox -- gear management and purchase planning web app* *Researched: 2026-03-14*