TypeScript / Python API Tutorial
A hands-on tutorial that walks through building simple CRUD APIs with several popular frameworks. Each framework lives in its own sub-folder and is demonstrated through a shared Next.js UI.
Complete Tutorial Code
Follow along with the complete source code for this tutorial. Includes five framework implementations — Next.js, Express, NestJS, Flask, and FastAPI — all demonstrated through a shared Next.js UI.
View on GitHubWhy Compare These Frameworks?
Choosing the right API framework is one of the most consequential decisions in a project. Next.js, Express, NestJS, Flask, and FastAPI each represent a different philosophy — from minimal and unopinionated to structured and feature-rich. This tutorial lets you build the same CRUD API in all five frameworks side by side, so you can see the trade-offs first-hand rather than just reading about them.
Framework Comparison at a Glance
Not sure which framework to reach for? Here is a quick reference across the five frameworks covered in this tutorial.
Next.js
Express
NestJS
Flask
FastAPI
Project Structure
Each framework lives in its own sub-folder. A shared Next.js UI at port 3000 drives all five backends, so you can switch between them without leaving the browser.
ts-python-api-tutorial/
├── nextjs/ # Next.js app (UI + API route handlers) → port 3000
├── express/ # Express.js REST API → port 3001
├── nestjs/ # NestJS REST API → port 3002
├── flask-api/ # Flask REST API (Python, managed with UV) → port 3003
├── fastapi-api/ # FastAPI REST API (Python, managed with UV) → port 3004
├── docs/ # Per-tab documentation
│ ├── nextjs.md
│ ├── express.md
│ ├── nestjs.md
│ ├── advanced-nestjs.md
│ └── flask.md
└── scripts/
└── start-servers.sh # Starts all tutorial servers (Ctrl-C to stop all)Prerequisites
- Node.js ≥ 20.9 (required by Next.js 16)
- npm — comes with Node.js
- Python ≥ 3.9 and UV — for the Flask and FastAPI tabs
Install UV if you don't have it:
curl -LsSf https://astral.sh/uv/install.sh | shQuick Start
- 1Clone the repository:
git clone https://github.com/audoir/ts-python-api-tutorial.git - 2Install dependencies for each framework:
Next.js
cd nextjs && npm installExpress
cd ../express && npm installNestJS
cd ../nestjs && npm installFastAPI (Flask uses UV on first run — no manual step needed)
cd ../fastapi-api && uv sync - 3Run all servers from the repo root:
./scripts/start-servers.shThen open http://localhost:3000 in your browser. The script starts every tutorial server in the background and kills them all when you press Ctrl-C.
💡 Tip — Start servers individually
cd nextjs && npm run dev → http://localhost:3000
cd express && npm run dev → http://localhost:3001
cd nestjs && npm run dev → http://localhost:3002
cd flask-api && uv run python main.py → http://localhost:3003
cd fastapi-api && uv run uvicorn main:app --host 0.0.0.0 --port 3004 --reload → http://localhost:3004
💡 Tip — FastAPI interactive docs
Once the FastAPI server is running you can explore the auto-generated API documentation at:
- Swagger UI: http://localhost:3004/docs
- ReDoc: http://localhost:3004/redoc
Framework Deep Dives
Each framework has its own advantages and disadvantages. Here is a detailed breakdown to help you decide which one fits your use case.
Next.js
Next.js is a full-stack React framework. API routes live alongside your UI in the same project — no CORS, no separate deploy. File-system routing maps app/api/route.ts directly to HTTP endpoints.
✅ Advantages
- Frontend and backend in one project — no CORS, no separate deploy
- File-system routing is intuitive for small projects
- Server Components reduce client-side JavaScript
- Excellent developer experience (Turbopack, hot reload)
- Vercel deployment is seamless
❌ Disadvantages
- API routes are not a first-class REST framework — no built-in guards, interceptors, or DI
- Tightly coupled to React — not suitable if you need a standalone API
- File-system routing can become hard to navigate in very large projects
- Harder to test API routes in isolation
- Vendor lock-in risk if you rely on Vercel-specific features
Express
Express is the most widely used Node.js web framework. It is extremely lightweight — almost no overhead — and gives you full control over routing, middleware, and error handling. Great for microservices and simple REST APIs.
✅ Advantages
- Extremely lightweight — almost no overhead
- You control everything — no magic, no hidden behaviour
- Massive ecosystem (passport, multer, helmet, …)
- Easy to learn — the entire API surface is small
- Great for microservices and simple REST APIs
❌ Disadvantages
- No enforced structure — large projects can become messy quickly
- No built-in DI, guards, interceptors, or modules
- Error handling requires discipline (easy to forget next(err))
- TypeScript support requires manual type annotations for req, res
- No built-in validation — you must wire up Zod/Joi/etc. yourself
NestJS
NestJS brings Angular-style architecture to Node.js. It enforces a module-based structure with built-in dependency injection, guards, interceptors, and pipes — making it the go-to choice for large, team-maintained backend APIs.
✅ Advantages
- Enforced structure scales well to large teams
- Built-in DI makes testing and swapping dependencies easy
- Guards, interceptors, pipes, and filters are first-class concepts
- Excellent TypeScript integration
- Built on Express — all Express middleware works
❌ Disadvantages
- Steeper learning curve — decorators, DI, and modules take time
- More boilerplate for simple use cases
- Requires experimentalDecorators and emitDecoratorMetadata in TypeScript
- Heavier than Express — more dependencies, slower cold start
- Angular-style architecture can feel unfamiliar
Flask
Flask is the Python equivalent of Express — minimal, unopinionated, and easy to get started with. It is a natural fit for data science and ML backends where the team already writes Python.
✅ Advantages
- Extremely simple to get started — minimal boilerplate
- Python ecosystem — great for data science, ML, and scripting
- Pydantic provides powerful, Pythonic validation with type hints
- UV makes dependency management fast and reproducible
- Easy to integrate with SQLAlchemy, Celery, and other Python libraries
❌ Disadvantages
- No enforced structure — large projects can become disorganised
- No built-in async support (use Flask 2+ async views or switch to FastAPI)
- No built-in DI, guards, or interceptors
- Slower than Node.js for pure I/O-bound workloads
- WSGI by default — requires extra setup for production (gunicorn, nginx)
FastAPI
FastAPI is the modern, async-first Python framework. Pydantic validation is built in, auto-generated Swagger and ReDoc docs come for free, and native async/await via ASGI (uvicorn) delivers performance comparable to Node.js frameworks.
✅ Advantages
- Pydantic validation is built-in — request bodies are validated automatically
- Auto-generates interactive API docs (Swagger UI at /docs, ReDoc at /redoc)
- Native async/await support via ASGI (uvicorn)
- Type hints drive both validation and editor autocompletion
- Very high performance — comparable to Node.js frameworks
- UV makes dependency management fast and reproducible
❌ Disadvantages
- Async-first design can be confusing if you mix sync and async code
- Smaller ecosystem than Flask — fewer third-party extensions
- Requires uvicorn (or another ASGI server) — not WSGI-compatible
- Dependency injection system is powerful but has a learning curve
- Less mature than Flask for non-API use cases
When to Use Which
Core Concepts Reference
New to web APIs, or encountering an unfamiliar term in one of the tab docs? The Core Concepts reference explains the foundational ideas that appear across all five frameworks.
HTTP and REST APIs
HTTP methods, status codes, and REST conventions
CRUD
Create, Read, Update, Delete — and how they map to HTTP
Middleware
The request pipeline and (req, res, next) functions
Routing
How each framework maps URLs to handler functions
Validation and Schemas
Zod (TypeScript) and Pydantic (Python) compared
Dependency Injection
What DI is and why NestJS uses it
Decorators
@Something annotations in TypeScript and Python
Modules
NestJS module system
Guards
NestJS request authorisation
Interceptors
NestJS response transformation
CORS
Why cross-origin requests are blocked and how to allow them
WSGI vs ASGI
Python server interfaces — Flask vs FastAPI
Sync vs Async
Synchronous and asynchronous request handling
In-Memory Store
Why this tutorial uses arrays/dicts instead of a database
OpenAPI / Swagger
Auto-generated API documentation
Tab Documentation
Detailed documentation for each tab lives in the docs/ folder of the repository: