AboutExpertiseProjectsJourneyBlogContact
Discuss
AboutExpertiseProjectsJourneyBlogContactDiscuss

Yao David Logan

Software Engineer fullstack specialized in SaaS, business automation and scalable web/mobile platforms.

NavigationExpertiseProjectsJourneyBlogContact
LinksGitHubLinkedInEmail
© 2026 Yao David Logan. All rights reserved.
DX 2026 — picking your Node.js + TypeScript stack without falling into traps
Back to blog

Tech

Xin@

DX 2026 — picking your Node.js + TypeScript stack without falling into traps

YDLYao David Logan7 min readMay 23, 2026

CategoryTech

Read7 min read

PublishedMay 23, 2026

Views29

Shares0

Comments0

Contents
  1. 011. Why DX matters so much
  2. 022. The runtime — Node, Deno or Bun?
  3. 033. The bundler — esbuild or Vite?
  4. 044. Typing — strict TypeScript, no compromise
  5. 055. Runtime validation — Zod or Valibot
  6. 066. The linter — ESLint flat config + TypeScript ESLint
  7. 077. The formatter — Prettier or Biome?
  8. 088. Testing — Vitest, Bun test or node:test
  9. 099. The package manager — pnpm
  10. 1010. The monorepo — Turborepo or Nx?
  11. 1111. CI — GitHub Actions by default
  12. 1212. The default stack that works
  13. 1313. Pitfalls to avoid
  14. 1414. Closing

Node 22 LTS, pnpm, Vite, Vitest, ESLint flat, Zod, Turborepo: the stack I default to in 2026 and why boring beats revolutionary.

Choosing your Node.js + TypeScript stack in 2026 is less a matter of fashion than of cumulative DX over 2 years. Here's the default stack I use and why.

1. Why DX matters so much

DX (Developer Experience) isn't comfort, it's investment. A stack that costs you 15 minutes a day waiting for builds or decoding cryptic errors is 60 hours per year per developer. On a team of 4, that's a half-FTE lost.

This article condenses the stack I default to in 2026, with the trade-offs that led me there. Not "you must use this" — criteria to decide.

2. The runtime — Node, Deno or Bun?

Three contenders in 2026, context by context:

CriterionNode 22 LTSBun 1.xDeno 2.x
Production maturity★★★★★★★★★★★★
Performance★★★★★★★★★★★★
npm ecosystem★★★★★★★★★★★★★
Integrated tooling★★★★★★★★★★★★
Native TypeScriptWith --experimentalYesYes
Hosting adoptionAll platformsLimitedGrowing

My default: Node 22 LTS. Reasons:

  • Absolute maturity, universal hosting support
  • Full ecosystem compatibility
  • Performance largely sufficient for 95% of cases

Bun: for highly perf-critical workloads (parsers, transformers, mass tests). 4x faster startup changes CI.

Deno: for edge / short serverless projects. Permission model and native HTTPS imports are elegant, but ecosystem friction weighs.

3. The bundler — esbuild or Vite?

For a web app: Vite, period. DX is unmatched: sub-1-second startup, instant HMR, native TS + JSX, rich plugin ecosystem.

For a backend service: esbuild, because you don't need Vite's dev server. esbuild in watch mode rebundles in <200ms, perfect for fast tests.

To publish an npm package: tsup (esbuild wrapper) or tsdown. Generates dual ESM/CJS + types in one command.

JSON
1{
2 "scripts": {
3 "build": "tsup src/index.ts --dts --format esm,cjs",
4 "dev": "tsup src/index.ts --watch --dts --format esm,cjs"
5 }
6}

4. Typing — strict TypeScript, no compromise

TypeScript in strict mode plus a few extra flags:

JSON
1{
2 "compilerOptions": {
3 "strict": true,
4 "noUncheckedIndexedAccess": true,
5 "noImplicitOverride": true,
6 "noPropertyAccessFromIndexSignature": true,
7 "exactOptionalPropertyTypes": true,
8 "noFallthroughCasesInSwitch": true,
9 "forceConsistentCasingInFileNames": true,
10 "isolatedModules": true,
11 "verbatimModuleSyntax": true,
12 "target": "ES2022",
13 "module": "NodeNext",
14 "moduleResolution": "NodeNext"
15 }
16}
  • noUncheckedIndexedAccess: arr[0] becomes T | undefined, forcing empty-case handling
  • exactOptionalPropertyTypes: { a?: string } no longer accepts explicit undefined, only absence
  • isolatedModules + verbatimModuleSyntax: perfect compatibility with esbuild/Vite

These flags cost time upfront but eliminate an entire class of bugs. On Nexus, enabling noUncheckedIndexedAccess revealed 17 latent bugs in a one-day refactor.

5. Runtime validation — Zod or Valibot

TypeScript validates at compile time. To validate at runtime (HTTP input, queue message, external payload), a runtime schema is essential.

Zod: de facto standard, massive ecosystem, integration with tRPC, OpenAPI, etc.

Valibot: 7x lighter, ideal for client bundles. API very close to Zod.

TypeScript
1import { z } from "zod";
2 
3export const depositSchema = z.object({
4 amount: z.number().int().positive().max(10_000_000),
5 currency: z.enum(["XOF", "USD", "EUR"]),
6 gateway: z.enum(["mtn_momo", "orange_money", "stripe"]),
7 reference: z.string().min(3).max(64),
8});
9 
10export type Deposit = z.infer<typeof depositSchema>;

Rule: all data coming from outside passes through a runtime schema. No blind as Deposit. No "it comes from the frontend, it's OK".

6. The linter — ESLint flat config + TypeScript ESLint

ESLint v9 in flat config (eslint.config.js) is now standard.

JavaScript
1import tseslint from "typescript-eslint";
2import unicorn from "eslint-plugin-unicorn";
3 
4export default tseslint.config(
5 ...tseslint.configs.strictTypeChecked,
6 ...tseslint.configs.stylisticTypeChecked,
7 unicorn.configs.recommended,
8 {
9 languageOptions: {
10 parserOptions: {
11 projectService: true,
12 tsconfigRootDir: import.meta.dirname,
13 },
14 },
15 rules: {
16 "@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_" }],
17 "@typescript-eslint/consistent-type-imports": "error",
18 "no-console": ["warn", { allow: ["warn", "error"] }],
19 },
20 },
21);

strictTypeChecked adds rules requiring type analysis (slow but valuable): no-floating-promises, no-misused-promises, require-await. These three alone catch 80% of typical async bugs.

7. The formatter — Prettier or Biome?

Prettier remains the mature standard. Its plugin ecosystem (Tailwind, etc.) is unmatched.

Biome is 10–30x faster. On big monorepos, life-changing. Its linter (Biome includes its own) is still behind ESLint but catching up fast.

My 2026 default: Biome for new projects, Prettier+ESLint for existing. Biome migration is work but the speed gain is tangible.

8. Testing — Vitest, Bun test or node:test

Vitest: Jest-compatible, native ESM, ultra-fast watch, snapshot, mocking, v8 coverage. The modern Swiss Army knife.

Bun test: integrated with Bun runtime, instant startup. Excellent if you already run Bun.

node:test: native Node 20+ module, no dependency. Enough for simple tests but ecosystem is thin.

TypeScript
1import { describe, it, expect, vi } from "vitest";
2import { PaymentRouter } from "./PaymentRouter";
3 
4describe("PaymentRouter", () => {
5 it("resolves the right gateway for a method", () => {
6 const router = new PaymentRouter();
7 const fakeGateway = { name: "mtn", supports: ["mobile_money_mtn"] };
8 router.register(fakeGateway as never);
9 expect(router.resolve("mobile_money_mtn")).toBe(fakeGateway);
10 });
11 
12 it("throws on unregistered method", () => {
13 const router = new PaymentRouter();
14 expect(() => router.resolve("card")).toThrow(/no gateway/i);
15 });
16});

9. The package manager — pnpm

pnpm by default. Three reasons:

  1. Disk: ~5x smaller node_modules (shared hardlinked store)
  2. Strict: no access to undeclared dependencies (prevents phantom imports)
  3. Speed: install 2–3x faster than npm

npm stays OK for very small projects or a well-structured monorepo with npm workspaces. Yarn berry is technically excellent but learning curve and smaller ecosystem make it less justifiable in 2026.

10. The monorepo — Turborepo or Nx?

For a monorepo of 3 to 15 packages: Turborepo. Simple config, Vercel remote cache, perfectly integrated with pnpm.

For an enterprise monorepo with 30+ packages and strong architectural constraints: Nx. More powerful, more complex, steeper curve.

JSON
1{
2 "$schema": "https://turbo.build/schema.json",
3 "tasks": {
4 "build": {
5 "dependsOn": ["^build"],
6 "outputs": ["dist/**", ".next/**"]
7 },
8 "lint": { "dependsOn": ["^build"] },
9 "test": { "dependsOn": ["^build"] },
10 "dev": { "cache": false, "persistent": true }
11 }
12}

11. CI — GitHub Actions by default

GitHub Actions became the practical standard in 2026. GitLab CI stays excellent if you're already on GitLab.

For a TypeScript/Node project:

YAML
1name: CI
2on: [push, pull_request]
3jobs:
4 ci:
5 runs-on: ubuntu-latest
6 steps:
7 - uses: actions/checkout@v4
8 - uses: pnpm/action-setup@v3
9 with: { version: 9 }
10 - uses: actions/setup-node@v4
11 with: { node-version: 22, cache: pnpm }
12 - run: pnpm install --frozen-lockfile
13 - run: pnpm typecheck
14 - run: pnpm lint
15 - run: pnpm test
16 - run: pnpm build

Well-done pnpm cache: 2 minutes vs 6 without on an average project.

12. The default stack that works

My 2026 stack for a new Node/TS project:

CategoryPick
RuntimeNode 22 LTS
Package managerpnpm
TypeScriptstrict + extra flags
Runtime validationZod
LinterESLint flat + typescript-eslint strict
FormatterBiome (new) or Prettier (existing)
TestsVitest
Web app bundlerVite
Service bundleresbuild + tsup for packages
MonorepoTurborepo + pnpm workspaces
CIGitHub Actions

This stack is boring, and that's exactly the point. No component is revolutionary. All are mature, documented, hireable. Time not spent on the stack is time spent on the product.

13. Pitfalls to avoid

PitfallSymptomFix
Exotic stack to look coolDegraded DX, hard hiringDefault choice unless precise justification
Non-strict TypeScriptFrequent runtime bugsstrict: true + extra flags
No runtime validationCrash on unexpected inputZod or Valibot on all inputs
Too lax linterNormalized dubious patternstypescript-eslint strict + async rules
No CI cacheSlow builds demoralizepnpm cache + Turbo cache
Premature monorepoComplexity without benefitSingle package up to 2-3 apps
Targetless testsSymbolic coverageTests on business logic, not framework

14. Closing

The best 2026 stack isn't the newest. It's the one that saves the most minutes per day without cognitive overhead.

My selection criteria, in order:

  1. Maturity and stability
  2. Daily DX (build speed, error quality, hot reload)
  3. Ecosystem and hireability
  4. Raw performance (often secondary)

A team of 4 developers with the right stack ships 30–50% faster than with a poorly chosen stack. The math is rarely spelled out but it's massive.

If starting today, take the default stack. Customize only when a precise, quantified need justifies it. The rest is cosmetics.

Comments

Reader reactions

No comment yet

No spam — email is only used to verify your identity.

·

Be the first to share your reaction.

NextObservability for a fintech platform — logs, metrics, traces and auditTech · 9 min read→
Next conversation

Turn this reading into a product decision.

If this topic feels close to a real product problem, I can help on diagnosis, architecture, backend, interface and automations that make a platform usable in production.

Format
Full-time, freelance, long mission
Focus
SaaS, API, back-office, automation
Discuss the topicDownload CV

Newsletter

Get the next technical notes.

A short selection on SaaS, backend architecture, business automation and product quality. No noise, only applicable ideas.