# afteracademy/nodejs-backend-architecture-typescript: an Express and TypeScript backend skeleton for a blogging platform

> A production-oriented Node.js and TypeScript starter that wires Express, Mongoose, Redis, JWT and Docker Compose into a layered blogging API. It is best read as a reference architecture and a testable starting point rather than a finished product.

**afteracademy/nodejs-backend-architecture-typescript** — Node.js Backend Architecture Typescript - Learn to build a backend server for production ready blogging platform like Medium and FreeCodeCamp. Main Features: Role based, Express.js, Mongoose, Redis, Mongodb, Joi, Docker, JWT, Unit Tests, Integration Tests.

- Repository: https://github.com/afteracademy/nodejs-backend-architecture-typescript
- Website: https://afteracademy.com/article/design-node-js-backend-architecture-like-a-pro
- Stars: 3,071 · Forks: 709
- Language: TypeScript
- License: Apache-2.0
- Published: 2026-09-24 · Updated: 2026-09-24 · Language: en
- Canonical page: https://hysenlabs.com/projects/afteracademy-nodejs-backend-architecture-typescript

## What the project is and who it is aimed at

This repository is a complete backend for a blogging platform in the Medium and FreeCodeCamp style, written in TypeScript on top of Express.js. The README frames it as a production-ready environment that can handle a demanding application, and it says the code is used by MindOrks, AfterAcademy and CuriousJr. Treat that last statement as the author's claim about his own deployments, not as an independent audit. The project is a learning vehicle with a working implementation attached: the homepage links to an article titled "Design Node.js Backend Architecture like a Pro" and a YouTube walkthrough, and the repository ships diagrams for the 3RE architecture, the blogging platform outline and the request-response flow.

The audience is narrow and identifiable. You are a backend developer who already knows JavaScript and wants a worked example of how to lay out an Express service in TypeScript so that routes, handlers, responses and errors live in separate places. You are not the audience if you want a library you can npm install into an existing service, or a finished product with a changelog you can trust for breaking changes. The README describes it as "a pure backend project" that deliberately excludes a frontend, on the argument that a backend coupled to a frontend becomes hard to scale later. That decision shapes everything else: the API is meant to serve many websites and mobile apps, so there is no server-rendered view layer to read through.

## The 3RE layering: Router, RouteHandler, ResponseHandler, ErrorHandler

The architectural centre of the repository is what the README calls 3RE. A request enters through a router, which is responsible for matching the path and attaching middleware. It is then passed to a route handler, which contains the feature logic and does not format output itself. The response handler takes whatever the route handler produced and turns it into a consistent API envelope, so success shapes are decided in one place rather than per endpoint. The error handler catches failures from anywhere in the chain and renders them in the same centralised way. The README lists centralised error handling and centralised response handling as separate highlights, and the schematic diagram in addons/github_assets/api-structure.png shows how the pieces connect.

The practical consequence is that a route handler returns data or throws, and never calls res.json directly. That constraint is what makes the unit tests possible without a database: the README states that the tests exercise functions and routes without needing the database server, and that unit tests are favoured over integration tests even though both exist. Feature encapsulation is the second organising rule. Files belonging to one feature are grouped together unless they are needed by several features, which is the mechanism behind the README's claim that code can be shared across projects.

MongoDB is accessed through Mongoose, and Redis is used as a cache for items that do not change often. The cache duration is a configuration value rather than a constant in code: CONTENT_CACHE_DURATION_MILLIS is set to 600000 in .env.example, which is ten minutes. That is a design choice worth noticing. A ten-minute default cache on blog content means an edit can take up to ten minutes to appear to other readers, and nothing in the README describes an invalidation path on write. If you adopt this skeleton for content that changes frequently, that is the first thing you will need to reason about.

## Installing it and getting the API answering on port 3000

The README gives Docker Compose as the primary path. You need Docker and Docker Compose installed, and the compose file builds two application images: Dockerfile for the app and Dockerfile.test for the tester container. Clone the repository, then bring the stack up. The compose file names the containers blogs-app and blogs-tester, and it maps the PORT value from your .env onto port 3000 inside the container.

```bash
git clone https://github.com/afteracademy/nodejs-backend-architecture-typescript.git
docker-compose up --build
```

When the build finishes, the README says the API is reachable at http://localhost:3000. The app container has a healthcheck that curls http://localhost:3000/health every five seconds, and it waits for both mongo and redis to report healthy before starting. If the stack does not come up, the first thing to check is port contention: the README explicitly warns that 3000, 27017 and 6379 must be free, and that otherwise you should change PORT, DB_PORT and REDIS_PORT in the .env file. The .env.example already sets DB_HOST=mongo and REDIS_HOST=redis, which are the service names inside the compose network.

To run the test suite, the README uses the tester container rather than the host:

```bash
docker exec -t blogs-tester npm run test
```

That command runs Jest with the flags defined in package.json: --forceExit --detectOpenHandles --coverage --verbose. If you prefer to work outside Docker, the README says to install Node.js and npm locally, change DB_HOST and REDIS_HOST to localhost in both .env and .env.test, then run npm install from the project root. After that, npm start builds and serves, and npm run watch runs the TypeScript compiler and nodemon concurrently. On install, a postinstall script runs ts-node ./addons/init-project.ts, so the first npm install does more than fetch packages. The README does not document what that script generates, which is a gap you should close by reading it before you run it on a machine where you care about side effects.

## Where the skeleton stops being enough

The honest limitation is that this is a reference implementation, not a maintained product. The most recent release listed is 2.0.3, tagged "Libraries & Docker Upgrades" and dated 2024-01-05, while package.json declares version 2.1.0. That mismatch between the released tag and the manifest version is the kind of detail that matters if you plan to depend on version numbers. The last push to the default branch was on 2026-07-02, so the repository is not abandoned, but the release history is sparse and there is no changelog file in the top-level listing. Upgrading means reading commits, not release notes.

The dependency set is another place where the skeleton makes decisions for you. Express is pinned at ^5.2.1, Mongoose at ^9.6.3 and the redis client at ^6.0.0. Those are major versions with their own migration stories, and the project's own upgrade scripts, npm run upgrade and npm run upgrade-latest, will move them forward within the declared ranges. New Relic is a runtime dependency, not a dev dependency, which means the agent is part of the default install even if you never configure it. Winston with winston-daily-rotate-file handles logging, and the README notes that LOG_DIR defaults to the project directory, so logs land next to your source unless you set it.

Authentication is JWT with an access token and a refresh token, with validity configured in seconds: ACCESS_TOKEN_VALIDITY_SEC=172800 and REFRESH_TOKEN_VALIDITY_SEC=604800. The issuer and audience are placeholders (api.dev.xyz.com and xyz.com) that you must replace. The README does not document token revocation, refresh rotation, or a rollback path for a bad deploy. If your requirements include any of those, you are writing them yourself on top of this structure.

## How it compares with NestJS and with a plain Express starter

The closest alternative in spirit is NestJS. Both give you a TypeScript backend with a prescribed structure, dependency injection and testable units. The difference in approach is that NestJS is a framework you install and whose conventions are enforced by decorators and a module system, while this repository is a codebase you clone and whose conventions are enforced by review and by the shape of the folders. NestJS publishes versioned packages with migration guides; this project publishes a repository you fork. If you want the structure to be a dependency you can upgrade, NestJS is the more conventional choice. If you want to read and modify every line of the request pipeline, the 3RE layout is easier to hold in your head because there is no framework layer between you and Express.

The other alternative is a minimal Express plus TypeScript starter, of which there are many. Those give you routing, a build script and not much else. What this project adds on top is the opinionated part: the centralised response and error handlers, the Redis cache with a configurable duration, the JWT access and refresh pair, the Docker Compose stack that includes MongoDB and Redis with health checks, and a test setup that runs without a database. That combination is the actual value. If you already have a house style for error envelopes and caching, the skeleton will mostly be in your way, and a thinner starter plus your own conventions is the better trade.

## Licence, maintenance and what an upgrade actually costs

The project is licensed under Apache-2.0, and the LICENSE file is in the repository root. Apache-2.0 is a permissive licence that includes an explicit patent grant and requires you to preserve notices and state changes you make to the files. It does not require you to open your own modifications. This is not legal advice, and if you are embedding the code in a commercial product you should have your own counsel read the LICENSE and the NOTICE situation rather than relying on a summary.

The maintenance cost is the more concrete question. Because this is a template rather than a published dependency, an upgrade is a merge, not a version bump. You will be diffing your fork against upstream and resolving conflicts in src/, which is exactly the directory you are expected to modify most. The practical approach is to keep your feature code in clearly separated files so that upstream changes to the router, handler and response layers can be applied without touching your business logic. If you instead edit the shared layers directly, every upstream change becomes a manual merge.

On the dependency side, package.json gives you two scripts for keeping current: npm run upgrade, which runs npm update for dev and production dependencies, and npm run upgrade-latest, which uses npm-check-updates to move past the declared ranges and then reinstalls. The second one will cross major versions of Express, Mongoose and the Redis client, so run it on a branch with the test suite green before and after. The README does not describe a supported upgrade path or a compatibility matrix, so the test suite is your only safety net.

## Conclusion

Adopt it if you want a TypeScript Express codebase with separated router, handler, response and error layers, plus Docker Compose that brings up the app, MongoDB and Redis together. Skip it if you need a published package, documentation beyond the README and Postman collection, or a project that is not primarily a teaching reference. Before committing, read src/ to confirm the layering matches your team's conventions, check .env.example against your own port and credential plan, and decide whether you want to inherit the build and test scripts as they are.

## FAQ

### What is the backend architecture of this Node.js project?

The README describes a 3RE architecture: Router, RouteHandler, ResponseHandler and ErrorHandler. Requests are matched by a router, handled by feature logic in a route handler, formatted centrally by the response handler, and failures are caught centrally by the error handler.

### Can TypeScript be used for the backend in afteracademy/nodejs-backend-architecture-typescript?

Yes. The project is written in TypeScript, built with tsc against tsconfig.build.json, and the README argues that type safety at build time catches code vulnerabilities during the build phase. The build output goes to build/ and is served by node.

### How do I install and run afteracademy/nodejs-backend-architecture-typescript?

The README's primary path is git clone followed by docker-compose up --build, after which the API is reachable at http://localhost:3000. A local path also exists: npm install, set DB_HOST and REDIS_HOST to localhost in .env and .env.test, then npm start or npm run watch.

### Which databases and services does afteracademy/nodejs-backend-architecture-typescript need?

MongoDB is used through Mongoose, and Redis is used to cache content that does not change frequently. The docker-compose.yml brings up the app, a tester container, MongoDB and Redis, and the app waits for both data services to report healthy before starting.

### How are tests run in afteracademy/nodejs-backend-architecture-typescript?

The README runs them inside the tester container with docker exec -t blogs-tester npm run test. Locally, npm test invokes Jest with --forceExit --detectOpenHandles --coverage --verbose, and the README states the tests are written to run without a database server.

## Sources

- [afteracademy/nodejs-backend-architecture-typescript on GitHub](https://github.com/afteracademy/nodejs-backend-architecture-typescript)
- [License: Apache-2.0](https://github.com/afteracademy/nodejs-backend-architecture-typescript/blob/main/LICENSE)
- [Project website](https://afteracademy.com/article/design-node-js-backend-architecture-like-a-pro)
- [README](https://github.com/afteracademy/nodejs-backend-architecture-typescript/blob/main/README.md)
- [Releases](https://github.com/afteracademy/nodejs-backend-architecture-typescript/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/afteracademy-nodejs-backend-architecture-typescript
