Our Stack
Everything lives in one repo, one package manager, one set of conventions. This page is the map: what we use for each layer, and why it’s the right tool for what we’re building.
The pieces#
| Layer | What we use | Why / where |
|---|---|---|
| Monorepo | pnpm workspaces + Turborepo | apps/* and packages/* in one repo (pnpm-workspace.yaml); turbo run build | dev | lint | typecheck | test shares a cache across every package |
| Language | TypeScript | Every app and package is "type": "module" TS, checked in CI (typecheck) |
| Marketing & docs site | Astro | apps/landing: the static site you’re reading right now |
| Product API | Hono + tRPC + Drizzle ORM + PostgreSQL + better-auth | apps/api: Hono is the HTTP layer, tRPC types the API end-to-end, Drizzle is the “dumb persistence” layer over Postgres (see Database Migrations), better-auth owns sessions |
| Product web app | React + Vite + TanStack Router/Query | apps/web: plus Tiptap and Yjs/Hocuspocus for the collaborative doc editor, shared through packages/editor |
| Shared packages | packages/domain, shared, editor, ui, pgmq | Domain entities and value objects, shared Zod schemas/types, the editor, UI components, and a Postgres-backed queue, reused across the API, web, and Lore apps |
| Observability | OpenTelemetry | HTTP, Postgres, and tRPC are auto-instrumented for free at boot (apps/api/src/instrumentation.ts); see Observability for where traces and metrics land and how to add your own |
| Product analytics & session replay | PostHog | posthog-js in the web app, posthog-node in the API; replay is masked by default; see Session Replay |
| Testing | Vitest everywhere, Playwright for e2e | See Testing & TDD for what to test and what CI runs |
Other apps in the monorepo#
Two more apps follow the same patterns above: lore-api (Hono + Drizzle + PostgreSQL + better-auth, a knowledge-base API with its own database) and lore-web (React + Vite + TanStack, its front end). glide-mcp is smaller and different in kind: an MCP server that lets an AI agent drive Glide directly instead of through a browser; see Glide MCP for what it does.
Why this shape#
The API’s job is to keep business logic in the domain, not the database: Postgres stores rows and enforces shape, nothing more (see Database Migrations for the “no defaults in the schema” rule). tRPC means the web app and the API share types end-to-end with no separate schema to keep in sync. OpenTelemetry and PostHog answer two different questions: OpenTelemetry tells you what the system did (which query was slow, where a trace really started); PostHog’s replay tells you what one user did. You reach for observability to debug the backend, and for a replay to understand a confusing flow from the outside.
None of this is fixed for its own sake. If a lighter tool solves the same problem for a new app in the monorepo, that’s a conversation, not a rule, but changing a piece here is a decision to bring to the team, not a solo call.
Related: Observability, Database Migrations, Session Replay, Environment Setup