TypeScript strict mode across 18 Next.js sites. Zero any-casts in production API routes.
HOW WE USE IT
TypeScript runs in strict mode across every Next.js application in the Avo stack. The rule is simple: no implicit any, no non-null assertions without a comment explaining why, and tsc --noEmit must pass clean before any deployment proceeds.
The practical effect is that the API layer is self-documenting. Every route handler has an explicit return type inferred from the response shape. When ClickHouse query results come back as Record<string, unknown>[], the TypeScript types force an explicit parse step at the boundary. That parse step is where most production bugs get caught before they reach users.
The stack uses TypeScript 5.4 across all 18 Next.js sites. The strictest site is the multi-tenant SaaS platform, which enforces no-unsafe-call and no-unsafe-member-access ESLint rules on top of strict TypeScript. Those rules caught three genuine bugs during initial build: a missing null check on Clerk session metadata, an unhandled undefined branch in the Stripe webhook handler, and a type widening issue in the ClickHouse response parser that would have silently returned 0 for missing numeric fields.
Example workflow: adding a new ClickHouse-backed API route to a client project. 1. Define the response shape as a TypeScript interface (e.g., BarRow with symbol, ts, open, high, low, close, volume). 2. Write a typed query function that returns Promise<BarRow[]> and parses the ClickHouse HTTP response through a Zod schema. 3. Add a Next.js Route Handler in app/api/bars/route.ts with an explicit NextResponse return type. 4. Run tsc --noEmit. The compiler will catch any field mismatch between the Zod schema and the interface before the route ever serves a request. 5. Add the route to the regression test suite with an expected-shape assertion, not just a 200-status check.
Server Components reduced the surface where TypeScript discipline matters most. Because data fetching now happens at the component level rather than in client-side hooks, the type contract between the database layer and the render layer is enforced at compile time rather than at runtime. A ClickHouse query that returns the wrong shape fails the build, not the page load.
The one area where TypeScript fights back is around Next.js 15 App Router conventions. The params prop is now a Promise on async server components. Any code from before the App Router that accesses params directly produces a type error on upgrade. Migrating the 18 sites from the old pattern to await params took approximately 40 minutes with a codemod, but the type errors made every affected call site immediately visible.
Production numbers
18
Next.js sites
5.4
TypeScript version
All sites
Strict mode
tsc --noEmit
Build gate
We built a 63-line Node.js proxy that gives Vercel serverless functions read-only access to a private ClickHouse instance with zero database exposure.
12ms Proxy overhead (end-to-end)
Read case study →
InfrastructureWe automated Avo site deployments with a GitHub Actions CI/CD pipeline that catches TypeScript errors in 35 seconds and deploys to Vercel production in 90 seconds.
90 sec Frontend deploy time (was 40-60 min)
Read case study →
PlatformsWe built a single-user operator analytics dashboard on ClickHouse that assembles 9 parallel queries in under 450ms, with SVG-native charts and no third-party analytics dependency.
280-450ms API response time (9 queries)
Read case study →
PlatformsWe built a 3-step onboarding wizard that shows live regime signals on users' selected assets during signup, eliminating the blank-dashboard activation gap and placing the upgrade prompt at peak intent.
<1.2 sec Intelligence fetch time (16 symbols)
Read case study →
PlatformsWe built a crypto screener that computes 52-week highs, 30-day returns, and volume rankings for 19,172 symbols from 87M rows in a single ClickHouse GROUP BY scan returning in under 420ms.
19,172 Symbols in screener
Read case study →
PlatformsWe built an intelligence API that serves regime, novelty, and correlation data for any of 19,172 symbols in under 120ms using pipeline-batched Redis fetches and a two-round-trip pattern.
<120ms Cache hit latency
Read case study →
Start a project
Most projects ship in under two weeks. Start with a free 30-minute discovery call.
Start a project →