How to Build a REST API with Node.js, Express, and TypeScript in 2026

To build a REST API in 2026, install Node.js 22.18 or later, Express 5, and TypeScript, then write route handlers that validate input and return correct HTTP status codes. Node can now run TypeScript files directly by stripping types, so you no longer need ts-node for simple projects. This guide walks through setup, a small CRUD API, validation with Zod, error handling, and status codes. It also flags what changed since older tutorials: Express 5 handles rejected promises for you, and TypeScript 7 has stricter defaults.

What Changed Since the Old Tutorials

TypeScript 7

Microsoft’s announcement says TypeScript 7.0 is “a 10x faster native port,” written in Go, and the command is still tsc. TypeScript 6.0, released March 23, 2026, was the last JavaScript-based version. The post lists breaking changes: strict now defaults to true, module defaults to esnext, and options like target es5, baseUrl, and the older node module resolution modes are hard errors. There is no programmatic API until 7.1, so tools like typescript-eslint use a compatibility package. As of October 17, 2026, the npm registry listed TypeScript 7.0.2.

Node Runs TypeScript Directly

Node’s documentation marks type stripping as stable. It is on by default since versions 23.6.0 and 22.18.0, stable in 25.2.0 and 24.12.0, and prints no warning since 24.3.0. The limits matter: it does no type checking, enums, runtime namespaces, and parameter properties cause errors, tsconfig paths are ignored, imports need the .ts extension, type imports need the type keyword, and .tsx and files under node_modules are not supported.

Express 5

Express 5 requires Node 18 or higher. The npm latest tag for express was 5.3.0, published October 9, 2026, with a latest-4 tag at 4.22.3. Express’s migration guide says handlers and middleware that return rejected promises now forward the error to error middleware automatically. It also notes that req.body is undefined when unparsed, that app.del() and req.param() are removed, and that wildcards need a name, such as /*splat.

Which Node Version?

The Node.js release pages list v24 as Active LTS and v26 as Current, first released May 5, 2026. The release schedule says v26 enters LTS on October 28, 2026, and Node 24 enters maintenance on October 20, 2026. Node 20 is end-of-life. Use an LTS version for anything you deploy.

Step 1: Set Up the Project

Following Express’s installation guide, create a folder and initialize it, then install packages. The commands are mkdir myapp, cd myapp, npm init, npm install express, and npm install –save-dev typescript @types/express @types/node. Add Zod with npm install zod. Zod’s documentation says it is tested against TypeScript 5.5 or newer and that you must enable strict mode.

A tsconfig for Node

Node’s documentation recommends this configuration for TypeScript 5.8 or newer, which is used here for type checking only:

{
  "compilerOptions": {
    "noEmit": true,
    "target": "esnext",
    "module": "nodenext",
    "rewriteRelativeImportExtensions": true,
    "erasableSyntaxOnly": true,
    "verbatimModuleSyntax": true
  }
}

The erasableSyntaxOnly setting makes TypeScript flag syntax that type stripping cannot handle, such as enums. Run npx tsc to check types, and run the app with node app.ts. Express’s own docs say running TypeScript directly needs Node 22.18.0 or newer (or 23.6.0 or newer) and TypeScript 5.8 or newer.

Step 2: Hello World

This is the official Express example, written in CommonJS:

const express = require('express');
const app = express();
const port = 3000;

app.get('/', (req, res) => {
  res.send('Hello World!');
});

app.listen(port, () => {
  console.log(`Example app listening on port ${port}`);
});

In a TypeScript file you would use import syntax instead, with the type keyword for type-only imports, and the filename would end in .ts. Run it, open the browser to port 3000, and you should see the greeting.

Step 3: Design the Resource

REST organizes an API around resources. For a list of users, a typical layout is a GET request on the users collection to list, a POST on the same path to create, a GET on a single user path to read, a PUT or PATCH to update, and a DELETE to remove. Keep paths as nouns, not verbs.

Step 4: Validate Input With Zod

Never trust a request body. Zod’s documentation shows the pattern: define a schema, then parse input against it. For example, a schema built with z.object and a name field of z.string() is used by calling its parse method on the input. When parsing fails, it throws an error you can turn into a 400 or 422 response. Remember that Express 5 leaves req.body undefined unless you add the JSON body parser middleware, so enable it first and check for a missing body.

Step 5: Use the Right Status Codes

MDN’s reference gives these meanings: 200 OK; 201 Created, “typically the response sent after POST”; 204 No Content; 400 Bad Request; 401, “semantically … unauthenticated”; 403 Forbidden; 404 Not Found; 409 Conflict; 422 Unprocessable Content; and 500 Internal Server Error. A reasonable pattern is 201 after creating, 204 after deleting, 400 for malformed requests, 404 when the resource is missing, and 409 when it conflicts with existing data.

Step 6: Handle Errors

With Express 5, an async handler can simply throw or reject, and the error reaches your error middleware. Express’s documentation shows this pattern:

app.get('/user/:id', async (req, res) => {
  const user = await getUserById(req.params.id);
  res.send(user);
});

function errorHandler(err, req, res, next) {
  if (res.headersSent) {
    return next(err);
  }
  res.status(500);
  res.render('error', { error: err });
}

The documentation also says the response status is set from err.status or err.statusCode, and “If this value is outside the 4xx or 5xx range, it will be set to 500.” For a JSON API, send a JSON body instead of rendering a page, and never leak stack traces to clients.

Step 7: Organize Your Code

Keep routes, validation schemas, and business logic in separate files. A common layout has a routes folder, a schemas folder, and a services folder. This article does not claim a standard, since the sources reviewed do not prescribe one.

Testing Your API

Use a tool such as curl or an HTTP client extension to send requests and check responses. Test the unhappy paths: missing fields, wrong types, unknown ids. The sources reviewed do not cover testing frameworks, so this article does not recommend one.

Security Basics

Validate all input, limit body size, and use HTTPS in production. Do not log secrets. Keep dependencies updated. The research for this article did not review authentication libraries, so choose one after reading its current documentation.

Deployment

Pick an LTS Node version, install dependencies, set environment variables, and run with a process manager or container. The free hosting options in our deployment guide may suit hobby projects.

Project Structure That Scales

A small API can live in one file, but a slightly larger one benefits from separation. Keep route definitions in one module, validation schemas in another, and data access in a third. That way, when you swap the in-memory store for a database, only one module changes. The sources reviewed do not prescribe a layout, so treat this as a common-sense suggestion, not a rule from Express’s documentation.

Handling Validation Errors Cleanly

When a Zod parse fails, return a 400 or 422 with a message the client can use, and do not leak internal details. MDN describes 422 as Unprocessable Content, which suits a request that is well formed but has invalid values, while 400 suits one that is malformed. Pick one convention and document it, so API consumers know what to expect. In Express 5, you can throw from an async handler and let your error middleware format the response, which keeps handlers short.

Checking Your Setup After Upgrading

Because TypeScript 7 changed defaults, a project that compiled under older settings may produce errors. The release post says strict now defaults to true, module defaults to esnext, and several old options are hard errors, including target es5 and baseUrl. If you hit these, update tsconfig rather than turning checks off. Also note the compatibility detail for tooling: until version 7.1 there is no programmatic API, so linters that depend on it use a compatibility package. If an editor integration breaks after an upgrade, check whether it relies on that API.

A Short Reading Order for Beginners

If you are new to all three technologies, learn them in this order. First, plain Node with a simple script, using the stable type stripping in a current LTS release. Second, Express with a single route, such as the hello world example. Third, TypeScript types for request and response bodies, checked with npx tsc. Fourth, Zod for validation. Fifth, error middleware. Each step adds one idea, and each can be tested before the next.

Express 5 Gotchas to Remember

Express 5 changed several things that older tutorials get wrong. Wildcard routes need a name, such as /*splat. The app.del() and req.param() methods are removed. The req.body property is undefined unless you use a body parser. And the node version floor is 18. If a tutorial code sample fails with a path-pattern error, the wildcard rule is the most likely cause.

Staying Current

Node and TypeScript move quickly. As of October 17, 2026, the schedule shows Node 24 entering maintenance on October 20, 2026 and Node 26 entering LTS on October 28, 2026, so use an LTS release when starting a project. Check the TypeScript release notes before upgrading, since version 7 changes defaults. Pin versions in package.json so your builds are repeatable.

From In-Memory to Real Database

A tutorial API often keeps data in an array, which resets whenever the server restarts. When you outgrow that, add a database through a module that your routes call, so the route code does not change. The free database options covered in our hosting guide are a starting point for prototypes. The research for this article did not review database libraries for Node, so choose one after reading its current documentation, and confirm that it supports your TypeScript version.

Deploying With Confidence

Before deploying, check that your build runs from a clean install, that environment variables are set on the host, and that you use an LTS Node version. Run npx tsc as a check step in your build, since type stripping at runtime does not check types. Add a simple health route that returns 200, so hosting platforms and monitors can confirm the service is running. Log errors with enough context to debug, without logging secrets or personal data.

Frequently Asked Questions

Do I still need ts-node?

For simple projects, no. Node’s stable type stripping runs .ts files directly. The npm registry shows ts-node 10.9.2 last published in December 2023.

Should I use Express 5 or 4?

Express 5 is the npm latest. It forwards async errors to error middleware. The latest-4 tag is 4.22.3.

Does Node type-check my TypeScript?

No. Type stripping removes types without checking. Run npx tsc for checks.

Which status code should POST return?

201 Created, typically, per MDN.

Which Node version should I use?

An LTS release. Node 24 is LTS, and Node 26 becomes LTS on October 28, 2026.

References and Sources

Node.js, “Previous Releases”: https://nodejs.org/en/about/previous-releases

Node.js, “Download”: https://nodejs.org/en/download

GitHub, “nodejs/Release”: https://github.com/nodejs/Release

Node.js, “End-of-life releases”: https://nodejs.org/en/about/eol

Node.js Docs, “Modules: TypeScript”: https://nodejs.org/api/typescript.html

Microsoft, “Announcing TypeScript 7.0”: https://devblogs.microsoft.com/typescript/announcing-typescript-7-0/

Express, “Migrating to Express 5”: https://expressjs.com/en/guide/migrating-5.html

Express, “Error handling”: https://expressjs.com/en/guide/error-handling.html

Express, “Installing”: https://expressjs.com/en/starter/installing.html

Express, “Hello world example”: https://expressjs.com/en/starter/hello-world.html

Zod, “Zod documentation”: https://zod.dev/

MDN, “HTTP response status codes”: https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status

About The Author

Written By

I write about AI, Web3, Crypto, Fintech, and the technologies shaping the digital economy. Connect with me on LinkedIn: https://www.linkedin.com/in/kenneth-onyebuchi-3b4634228

More From Author

Leave a Reply

You May Also Like

Top VS Code Extensions for AI Coding and Productivity in 2026

Top VS Code Extensions for AI Coding and Productivity in 2026

The most-installed AI coding extensions for VS Code in 2026 are GitHub Copilot and Copilot…

Why Glucose Drops During Sleep: Causes and What Your CGM Shows

Why glucose drops during sleep: learn the normal causes, how compression lows fake a dip…

Continuous Lactate Monitoring: Are Sensors Ready for Zone 2?

Continuous lactate monitoring is moving into wearables. See how the sensors work, what studies show,…