Stacks

TypeScript across frontend and backend: what you gain

With TypeScript in frontend and backend you share the types of your API contract. Types only exist at build time, so validate incoming data with a schema.

BorisBy BorisDeveloper · 4 min readLees in het Nederlands
TypeScript code with React hooks in an editor
Photo: Peaky Frames on Unsplash

With TypeScript in both the frontend and the backend, you can share types. Change a field in an API response and the type checker shows what breaks on both sides, before it reaches production. A developer can also pick up a ticket that touches both sides more easily. There are limits too: types only exist at build time, and for some kinds of work another language is the better fit.

What shared types give you

The main benefit is one definition of your API contract. Put the types for requests and responses in a shared package, and have the frontend and the backend both import from it. Rename customerName to name in the backend and the type checker in the frontend points at every place you need to change.

Without shared types, you write the contract twice: once in the backend and once as an interface in the frontend. The two drift apart, and you only notice when a field shows up empty on screen.

A developer can also work on both sides more easily. Someone who mostly does frontend work can add a field to an endpoint without first learning another language and its tooling. In a small team that saves handovers.

Types do not exist at runtime

TypeScript checks your code at build time. At runtime it is plain JavaScript. Node.js can now run TypeScript files itself by stripping the types. That has been on by default since Node.js 22.18 and 23.6, and the feature has been marked stable since 24.12 and 25.2. Node.js does no type checking while doing so, so you still need a CI step that runs tsc --noEmit.

The more important consequence is that incoming data is unchecked. A request body, a webhook or a response from an external API can contain anything, whatever your type claims. Validate that data at the edge of your system.

I would make the schema the source and derive the type from it. With Zod you write one schema, use it to validate input and extract the TypeScript type with z.infer. Put that schema in the shared package so the frontend can use it for form validation too.

How to share the types

The simplest option is a monorepo, with the frontend, the backend and the shared package side by side. A change to the contract and the updates on both sides then go into one pull request. The trade-offs between a monorepo and separate repositories are covered in monorepo or separate repositories.

With separate repositories, you publish the shared package with a version number, or you generate the types from an OpenAPI specification. The second option also works when the backend is not written in TypeScript. A .NET or Python backend can publish an OpenAPI specification that the frontend generates its types from. How to set up such a contract is described in designing API-first.

Hiring for a TypeScript stack

The pool of developers who know TypeScript is large. According to GitHub's Octoverse report, TypeScript became the most used language on GitHub for the first time in August 2025, measured by monthly contributors, overtaking Python and JavaScript.

A developer who knows TypeScript does not automatically know both sides, though. Frontend work needs knowledge of rendering and accessibility. Backend work needs knowledge of databases, queues and security, and of what happens under load. Sharing a language does not transfer that knowledge. With a "full-stack TypeScript" profile, check where someone has real experience. The stacks we work with are listed on our technology page.

Where one language stops

For data analysis and machine learning, Python keeps you closer to the libraries you need. Run a separate Python service next to your TypeScript stack rather than forcing everything into one language. You generate that service's types from its OpenAPI specification as well.

If you already have a working backend in .NET or Java, one language is no reason to rewrite it. Generate the types from the API specification and leave the backend as it is.

In large codebases, type checking is slow. TypeScript 7.0 was released in July 2026 as a native port of the compiler, written in Go. Microsoft reports full builds that are typically 8 to 12 times faster. That release has no API yet, so tooling that embeds TypeScript, such as for Vue, Svelte and Astro, will likely not be able to switch yet. Check your own toolchain before you plan the upgrade.

Ground rules for shared types

  • Turn on strict in every package.
  • No any in the shared package. If you do not know the type, use unknown and validate.
  • Run the type check in CI on every pull request, for frontend and backend together.
  • Keep the shared package small: contracts and schemas, no business logic.
  • If you run TypeScript directly with Node.js, turn on erasableSyntaxOnly. The compiler then reports syntax Node.js cannot strip, such as enums.

Sources

Frequently asked questions

What is the benefit of using TypeScript in both frontend and backend?

You can share the types of your API contract. When a field changes in the backend, the type checker shows every place in the frontend that needs updating. Developers can also pick up tickets that touch both sides more easily.

Does TypeScript check data at runtime?

No. Types only exist at build time, even when Node.js runs your TypeScript files directly. Validate incoming data with a schema, for example with Zod, and derive the type from that schema.

When should you not use TypeScript in the backend?

When you already have a working backend in another language, or when the work is mostly data analysis or machine learning, where Python keeps you closer to the libraries you need. Generate the frontend types from an OpenAPI specification instead.

About the author

Boris

Boris

Developer

Boris is a developer at Brainpower Group and works from Serbia inside client teams.

More from Boris
Contact
Bas Leijder HavenstroomMaarten ter VeldeBarry Willems

Tell us who you are looking for.

An introduction takes half an hour, online or at our office in Amsterdam. In the chat we usually reply within a few minutes.

Or call +31 20 210 1978hello@brainpowergroup.eu

Bas, Maarten and BarryLive now · replies within a few minutes

The chat opens once you send.