type Technology = "TypeScript"

interface TypeScript

type Engagement = {
  headline:"Across the product.";
  mode:"strict";
  shared: true;
}

Zupitrix writes TypeScript on the frontend and on Node services so the shape of data is checked before it ships. Shared packages hold API types, domain models, and validation — one change updates every caller.

strictCompiler settings that bite
1 modelShared domain types
CITypecheck on every PR
DXAutocomplete at the boundary

// code we write

Schemas and shared contracts, not cast-away anys

Boundary parsing and one package of domain types — so React, Next.js, and Node agree before CI merges.

// practice

Strict by default

Shared types across UI, API, and packages so refactors fail in CI instead of in production.

Prop<1>

Strict from the start

New packages compile with strict settings. Escape hatches are local and commented, not a project-wide off switch. We document the approach, name owners, and attach acceptance checks so “Strict from the start” is reviewable in demos and durable after handoff.

Prop<2>

Parse external data

JSON from APIs, webhooks, and forms is validated. The type is the result of that parse, not a cast. We document the approach, name owners, and attach acceptance checks so “Parse external data” is reviewable in demos and durable after handoff.

Prop<3>

Shared domain types

IDs, money, and status unions live once. UI and API import them instead of redefining strings. We document the approach, name owners, and attach acceptance checks so “Shared domain types” is reviewable in demos and durable after handoff.

Prop<4>

Refactors that fail early

Renames and removed fields break the build. That is the point — production is the wrong place to discover a mismatch. We document the approach, name owners, and attach acceptance checks so “Refactors that fail early” is reviewable in demos and durable after handoff.

// deliverables

Exported surfaces

export

Typed React and Next.js apps

Components, routes, and data hooks with types that match the API they call. We document the approach, name owners, and attach acceptance checks so “Typed React and Next.js apps” is reviewable in demos and durable after handoff.

export

Typed Node services

Handlers whose inputs and outputs are the same types the client imports. We document the approach, name owners, and attach acceptance checks so “Typed Node services” is reviewable in demos and durable after handoff.

export

Incremental migrations

A path from JavaScript to TypeScript that keeps the product shipping while coverage grows. We document the approach, name owners, and attach acceptance checks so “Incremental migrations” is reviewable in demos and durable after handoff.

// pipeline

Compile → ship

  1. 01

    Baseline

    Turn the compiler on and list the modules that fail. Exit criteria and owners are written down before the next step starts.

  2. 02

    Boundaries

    Type the API edge and the UI data layer first. Exit criteria and owners are written down before the next step starts.

  3. 03

    Share

    Move duplicated models into one package or a generated client. Exit criteria and owners are written down before the next step starts.

  4. 04

    Guard

    Typecheck and lint in CI so the baseline does not slide back. Exit criteria and owners are written down before the next step starts.

  5. 05

    Harden

    Validate budgets, failure modes, observability, and rollback before traffic. Exit criteria and owners are written down before the next step starts.

  6. 06

    Handoff

    Runbooks, access, and training so the client team can operate without us. Exit criteria and owners are written down before the next step starts.

// imports

  • import "TypeScript"
  • import "React"
  • import "Next.js"
  • import "Node.js"
  • import "Zod"
  • import "OpenAPI"
  • import "Prisma"
  • import "tRPC"
  • import "Vitest"

// services

Outcomes

What we optimize for

Product and engineering goals we keep visible from the first slice through handoff — so velocity never quietly trades away quality.

strictCompiler mode
0 driftShared models
CITypecheck every PR
ParseRuntime boundaries
CodegenClients from contracts
any↓Debt trending down

At a glance

Delivery facts

Typical timelines, coverage, and operating constraints we set expectations against before the build surface expands.

TopicValueNote
New codestrictNon-negotiable. Tracked against TypeScript delivery milestones.
Migration styleIncrementalKeep shipping. Tracked against TypeScript delivery milestones.
Boundary ruleParse firstNever cast JSON. Tracked against TypeScript delivery milestones.
Monorepopnpm + turboCommon setup. Tracked against TypeScript delivery milestones.
CItsc requiredMain protected. Tracked against TypeScript delivery milestones.
ClientsGeneratedWhen multi-language. Tracked against TypeScript delivery milestones.

Ecosystem

Technologies that sit beside it

Real stack partners we wire into delivery with clear roles — not decorative logos on a slide.

TypeScript

Language — integrated deliberately into delivery with TypeScript.

React

UI types — integrated deliberately into delivery with React.

Node.js

Server types — integrated deliberately into delivery with Node.js.

Zod

Runtime parse — integrated deliberately into delivery with Zod.

tRPC

End-to-end types — integrated deliberately into delivery with tRPC.

Prisma

Generated models — integrated deliberately into delivery with Prisma.

Vitest

Typed tests — integrated deliberately into delivery with Vitest.

ESLint

Strict rules — integrated deliberately into delivery with ESLint.

Next.js

Routing, SSR/SSG, and deployment shell for React apps.

OpenAPI

Codegen — integrated deliberately into delivery with OpenAPI.

pnpm

Workspaces — integrated deliberately into delivery with pnpm.

Turborepo

Monorepo — integrated deliberately into delivery with Turborepo.

Integrations

Systems we commonly connect

CMS, identity, commerce, analytics, and edge services joined with typed contracts, webhooks, and ownership — not ad-hoc glue.

GraphQL

Codegen clients — integrated deliberately into delivery with GraphQL.

PostgreSQL

Typed SQL/ORM — integrated deliberately into delivery with PostgreSQL.

React

Component props — integrated deliberately into delivery with React.

Node.js

Service types — integrated deliberately into delivery with Node.js.

Docker

Build images — integrated deliberately into delivery with Docker.

Vercel

Typed env — integrated deliberately into delivery with Vercel.

Architecture

Layers we design explicitly

Boundaries, ops knobs, and rollback policy for each layer — so one team can change without rewriting everything.

01

Domain package

Statuses, money, IDs, branded types.

  • npm/pnpm
  • SemVer
  • Exports
02

Boundary parsers

HTTP, forms, webhooks → domain.

  • Zod
  • io-ts
  • Valibot
03

App surfaces

React/Next and Node import domain only.

  • Web
  • API
  • Workers
04

Codegen

ORM and OpenAPI keep models fresh.

  • Prisma
  • openapi-ts
  • gql
05

CI gates

tsc + eslint on every change.

  • GitHub Actions
  • Caching
  • Fail closed

Capabilities

What we actually deliver

Concrete workstreams with owners, acceptance checks, and a path for your engineers to extend after handoff.

Strict compiler baselines

No silent any; escape hatches are local and reviewed.

Shared domain models

One source for statuses, IDs, and money across surfaces.

Parse then type

Network JSON is validated at the boundary — never cast.

CI typecheck gates

tsc and lint on every PR so baselines do not slide.

DX for the team

Autocomplete and rename safety across the stack.

Safe refactors

Removed fields break the build before they break production.

Codegen pipelines

OpenAPI/GraphQL/Prisma models regenerated in CI.

Monorepo project refs

Project references keep builds incremental and honest.

Typed test helpers

Factories and fixtures that cannot invent invalid states.

Patterns

Approaches we reach for

Reference implementations and conventions in the repo — so reviews reject one-off variants that bypass the agreed shape.

01

Branded types

UserId ≠ string at compile time.

Reference implementation of “Branded types” lives in the repo, not only slides.
02

Discriminated unions

Exhaustive handling of statuses.

Reference implementation of “Discriminated unions” lives in the repo, not only slides.
03

satisfies operator

Config objects stay checked without widening.

Reference implementation of “satisfies operator” lives in the repo, not only slides.
04

Parse, don’t cast

unknown → schema → domain.

Reference implementation of “Parse, don’t cast” lives in the repo, not only slides.
05

Public API exports

Packages expose intentional surfaces only.

Reference implementation of “Public API exports” lives in the repo, not only slides.
06

Gradual migration paths

allowJs / path aliases while converting.

Reference implementation of “Gradual migration paths” lives in the repo, not only slides.

Industries

Domains we apply this in

Same technical playbook, different module depth — regulation, uptime, and partner APIs baked in early.

01

Multi-surface products

Web, API, and workers sharing models.

Typical systems (identity, payments, CMS, partners) listed with owners.
02

Regulated domains

Statuses and money types that cannot silently widen.

Typical systems (identity, payments, CMS, partners) listed with owners.
03

Platform teams

Published contracts for product squads.

Typical systems (identity, payments, CMS, partners) listed with owners.
04

Legacy modernization

Slice-by-slice JS → TS with shipping cadence.

Typical systems (identity, payments, CMS, partners) listed with owners.
05

Design systems

Variant props as unions.

Domain constraints for “Design systems” mapped before the first TypeScript milestone.
06

Integration-heavy SaaS

Webhook payloads validated every time.

Typical systems (identity, payments, CMS, partners) listed with owners.

Decide with us

Choose vs avoid

Defaults we defend in architecture reviews — and shortcuts we challenge before they become expensive.

Choose

strict from day one on new code

Avoid

loose tsconfig “temporarily” forever

  • Default on TypeScript because it keeps ownership and reviews objective.
Choose

Shared domain package

Avoid

Copy-pasted interfaces per app

  • Default on TypeScript because it keeps ownership and reviews objective.
Choose

Runtime parse at edges

Avoid

as MyType on fetch JSON

  • Default on TypeScript because it keeps ownership and reviews objective.
Choose

Codegen for public APIs

Avoid

Hand-written drifting clients

  • Default on TypeScript because it keeps ownership and reviews objective.
Choose

CI blocks on tsc

Avoid

Optional typecheck jobs

  • Default on TypeScript because it keeps ownership and reviews objective.

Tooling

Day-to-day instruments

Lint, test, preview, and observability tools that stay in the repo — not optional add-ons after launch.

ESLintPR rules that keep quality from drifting.
TurborepoMonorepo — integrated deliberately into delivery with Turborepo.
pnpmWorkspaces — integrated deliberately into delivery with pnpm.
SwaggerAPI docs — integrated deliberately into delivery with Swagger.
VitestTests — integrated deliberately into delivery with Vitest.
ZodParsers — integrated deliberately into delivery with Zod.
PrismaModels — integrated deliberately into delivery with Prisma.
GitHub Actionstsc in CI — integrated deliberately into delivery with GitHub Actions.

// faq

Want TypeScript that the whole stack shares?

We will look at where types drift today and put a single contract in front of the UI and the API.

Start Project
Contact Us

Get In Touch

Let's build something amazing together. Contact us to discuss your project and see how we can help bring your vision to life.

New project inquiry

Start project.
We'd love to help.

Fill in the form and we'll respond within one business day — personally, not with a template.

Your info stays private