# The TypeScript stack we would set up today

> Source: https://learn-typescript.org/tools/
> Part of Learn TypeScript, free to read.

The TypeScript ecosystem spent a decade accumulating tools and has spent the last three consolidating them. Most of what a 2020 setup guide told you to install is now either built in or replaced.

:::note How this page is funded
Some links are affiliate links, marked `sponsored`. We earn a commission if you buy; it costs you nothing and it does not buy placement. Most of what follows is free.
:::

## The core

### `tsconfig.json` — the most important file you will write

Configuration is where most of the value is, and the defaults are too loose. The full reasoning is in [the type system as a harness](/ai/types-as-harness/); the short version:

```json
{
  "compilerOptions": {
    "strict": true,
    "noUncheckedIndexedAccess": true,
    "exactOptionalPropertyTypes": true,
    "noFallthroughCasesInSwitch": true,
    "verbatimModuleSyntax": true,
    "erasableSyntaxOnly": true,
    "target": "ES2023",
    "module": "nodenext",
    "moduleResolution": "nodenext"
  }
}
```

`noUncheckedIndexedAccess` is the one that catches the most real bugs in generated code.

### ESLint with type-aware rules

Not for style — the formatter handles that — but for the rules that need type information and catch real bugs. `no-floating-promises` alone justifies the setup; see [the failure modes](/review/failure-modes/).

```bash
npm i -D eslint typescript-eslint
```

### Vitest

Fast, ESM-native, and the API is close enough to Jest that migration is mostly a find-and-replace. If you are on Jest and it works, there is no urgency; if you are starting fresh, start here.

### A validation library

Zod, Valibot or ArkType. Which one matters far less than the habit: **parse external data at the boundary, never `as` it.** Zod has the largest ecosystem, which also means models generate it most reliably. Valibot is dramatically smaller if bundle size matters.

## Runtime and package manager

Node with `pnpm` remains the safe default: the widest compatibility, the best CI support, and `pnpm`'s strict `node_modules` catches phantom dependencies that `npm` lets through.

Bun and Deno are both genuinely good and both worth trying on a greenfield project. The honest caveat is compatibility — you will occasionally hit a package that assumes Node, and debugging that is a worse use of an afternoon than the speed gain was worth.

## Editor

VS Code with the built-in TypeScript support is free and is what the ecosystem is built around. There is not a strong argument for anything else on the language-support axis.

:::promo jetbrains
:::

WebStorm's case is refactoring across a large codebase and the integrated debugger — both things that matter more when you are reviewing generated code than when you are writing it yourself.

## Learning

:::promo frontendmasters
:::

The strongest recommendation here. The TypeScript workshops are the best long-form teaching available on the type system specifically, which is exactly the knowledge that pays off when you are using types as a harness rather than as documentation.

:::promo educative
:::

Text-first and skimmable when you need one specific thing (conditional types, template literal types) rather than a whole course.

## Hosting

:::promo digitalocean
:::

For a Node API, App Platform is the least-effort path to a URL with TLS. For anything that can run at the edge, Cloudflare Workers' free tier is excellent and we earn nothing from saying so.

## What you can stop installing

The consolidation list, which is longer than most people realise:

| Was needed | Now |
|---|---|
| `ts-node` | `node --experimental-strip-types`, or `tsx` |
| `babel` for TS | `tsc`, `esbuild`, or the runtime |
| `prettier` + `eslint-config-prettier` | still fine; Biome or `oxlint` if you want one fast tool |
| `moment` | `Temporal`, `Intl.DateTimeFormat` |
| `lodash` | most of it is now language built-ins |
| `axios` | `fetch`, stable in Node since 18 |
| `dotenv` | `node --env-file=.env` |
| `uuid` | `crypto.randomUUID()` |
| `rimraf`, `mkdirp` | `fs.rm`, `fs.mkdir` with `recursive` |

Every one of these is still commonly generated, because the training data predates the replacement. A short list in your `AGENTS.md` fixes it.

## Also worth skipping

- **A second formatter.** Pick one. Two formatters is a merge conflict generator.
- **Path aliases without a bundler that understands them.** They break at runtime in ways that waste an evening. Use them only if your whole toolchain agrees.
- **`any` as a migration strategy.** `unknown` plus a narrowing check is barely more work and does not spread.

## Common questions

### Do I still need a bundler for a Node backend?

Usually not. Run TypeScript directly (`tsx`, or Node's built-in type stripping) in development, and `tsc` to `dist/` for production. Bundling a server is worth it mainly for cold-start-sensitive serverless deployments.

### Biome, oxlint, or ESLint?

Biome and oxlint are much faster and cover formatting plus a large rule set. ESLint still has the type-aware rules, and `no-floating-promises` is the single most valuable rule for generated code. Today: ESLint for correctness rules, a fast formatter for everything else.

### Zod or Valibot?

Zod unless bundle size is a hard constraint. The ecosystem is larger, the integrations are better, and models generate it more reliably because there is far more of it in the training data.
