Tech Stack Deep Dive

TypeScript 96%, Node.js runtime, Drizzle ORM (type-safe queries, migrations), PGlite (embedded Wasm PostgreSQL for dev), Vite + React 19 frontend, and pnpm workspace.

Tech Stack Deep Dive

What you'll learn

Every major technology in the Paperclip stack, why it was chosen, and what you need to know about each one before writing any code.


Language — TypeScript

Paperclip is 96% TypeScript. TypeScript adds static typing to JavaScript, which means the compiler catches type mismatches before they become runtime errors.

For Paperclip specifically, TypeScript is critical because:
- The @paperclip/shared package defines types used by both server and frontend — a change to an API response type breaks the frontend immediately at compile time, not at runtime
- Adapter interfaces are typed contracts — you can't implement a broken adapter without the compiler telling you

# Check types across the whole monorepo
pnpm typecheck

Runtime — Node.js 20 LTS

Node.js 20 is the current Long-Term Support release. Paperclip uses:


Package manager — pnpm

pnpm (Performant npm) uses a content-addressable store where each package version is stored once on disk and hard-linked into each project's node_modules. This means:

pnpm install          # install all workspace dependencies
pnpm --filter server dev  # run dev only in apps/server
pnpm -r typecheck     # run typecheck in all workspaces

API framework — Express.js

Express is the minimal HTTP framework for the API server. Paperclip keeps it simple:

This makes the code easy to follow and easy to extend with new routes.


ORM — Drizzle

Drizzle ORM is a TypeScript-first ORM that generates type-safe queries from a schema definition file.

// Schema definition (apps/server/src/db/schema.ts)
export const agents = pgTable('agents', {
  id: uuid('id').primaryKey().defaultRandom(),
  companyId: uuid('company_id').references(() => companies.id),
  name: text('name').notNull(),
  status: text('status', { enum: ['active', 'paused', 'terminated'] }).notNull(),
  // ...
});

// Type-safe query — TypeScript knows the exact shape of the result
const activeAgents = await db
  .select()
  .from(agents)
  .where(eq(agents.status, 'active'));
// activeAgents is typed as typeof agents.$inferSelect[]

Drizzle generates SQL migration files when you change the schema:

pnpm db:generate   # generate migration from schema diff
pnpm db:migrate    # apply pending migrations

Dev database — PGlite

PGlite is a PostgreSQL engine compiled to WebAssembly that runs in-process. Paperclip uses it automatically in development when DATABASE_URL is not set.

Key facts:
- Stores data in a single file (.paperclip/dev.db)
- Full PostgreSQL SQL compatibility (same queries as production)
- Zero setup — no Docker, no service to start
- Not suitable for production (single-process, no network access)


Frontend — React 19 + Vite

The dashboard is a React 19 SPA. Notable choices:

Technology Why
Vite Near-instant HMR (hot module replacement) during development
React Router v6 Client-side routing for the dashboard pages
React Query (TanStack) Server state management — handles caching, refetch, loading states
Recharts Cost and run timeline charts

Project tooling

Tool Purpose
ESLint Code style enforcement
Prettier Code formatting
Vitest Unit testing (same syntax as Jest)
tsx Runs TypeScript files directly in Node without a compile step

Checkpoint ✓

Sign in for progress tracking & Q&A →