Self-hosted service
monstar-lab-oss/nestjs-starter-rest-api avatar
monstar-lab-oss/nestjs-starter-rest-api

nestjs-starter-rest-api: a GitHub template for a NestJS service

NestJS Starter Kit. Monolithic Backend. REST API.

638 stars119 forksTypeScriptMIT

At a glance

What is it?
This starter kit is a monolithic NestJS REST API repository published as a GitHub template, with JWT authentication, role based authorization, TypeORM migrations, winston logging, Docker and a devcontainer already wired up. It is maintained as a consulting artefact by MonstarLab, and its scripts and tooling are the more interesting part than the sample application.
Who is it for?
Adopt nestjs-starter-rest-api if you want a NestJS service with the plumbing decisions already made, especially the JWT key handling, the migration commands and the Docker and devcontainer setup, and you are willing to restructure the generated code to fit your own conventions.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 145 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A repository you start a project from

The shape of this project is unusual in a good way. It is not a library that you install, and it is not an application with a domain. It is a GitHub Template Repository, which the README says can be easily used as a starter template for other repositories, and the outline it advertises is short: a monolithic project with a REST API.

The primary language is TypeScript, the licence is MIT, and the README describes it as the NestJS 11 starter kit. The name in package.json is nestjs-starter-rest-api, and the package is marked private, which is right for something that is meant to be copied rather than consumed from a registry.

The maintainers are MonstarLab. The README points at a separate repository, nestjs-sample-solutions, for sample implementations built on the kit, and the consulting section is candid about the intent: most of the features have already been tried in production applications at MonstarLab, their own production applications are more feature rich, and they are always pushing those features into the open source kit. A more feature rich commercial option is offered as a collaboration.

So the kit is best understood as the open source half of a consultancy's tooling, which tells you both what it does well and where its priorities come from.

The feature table, and the one row still marked WIP

The README states the guiding principle plainly: one of the main principals has been to keep the starter kit as lightweight as possible. The feature table follows from that.

Authentication is JWT, authorization is role based, the ORM integration and the database migrations are both TypeORM, logging is winston, request validation is class-validator, and pagination is SQL offset and limit rather than anything more elaborate. The infrastructure rows are a Dockerfile and a devcontainer, and the documentation rows are auto-generated OpenAPI and an auto-generated changelog.

That last row is the only one not marked Done. The changelog entry reads WIP, and the README says the progress column exists precisely to say so. It is a small thing, but it is the kind of honesty that makes the rest of the table usable: a reader knows which rows they are inheriting as working code and which one they will be finishing themselves.

Beneath the table the README lists the smaller things that come along: prettier integration, commit-linting husky hooks, package import sorting, SonarCloud GitHub actions, and a docker-compose setup for the database dependencies. Those are the parts that usually get skipped in a template and then re-added in every project.

Installing, the env file and the JWT key pair

The installation path is short. Dependencies first:

bash
$ npm install

Then you create a .env file from the .env.template template in the repository root. The README also notes that when using Docker, all the npm commands can be performed using ./scripts/npm, for example ./scripts/npm install, so that the same commands run inside the same environment and versions as the service without relying on what is installed on the host.

The one genuinely fiddly step is the JWT key pair, and the README gives two routes. With Docker there is a script:

bash
./scripts/generate-jwt-keys

which prints the two values to add to your .env file. Without Docker, you generate an RSA key pair yourself:

bash
$ ssh-keygen -t rsa -b 2048 -m PEM -f jwtRS256.key
# Don't add passphrase
$ openssl rsa -in jwtRS256.key -pubout -outform PEM -out jwtRS256.key.pub

The comment about the passphrase is a real requirement rather than advice, since the key is read by the service at startup. The files can be kept in a ./local directory, which is ignored by git, and then encoded:

bash
$ base64 -i local/jwtRS256.key

$ base64 -i local/jwtRS256.key.pub

The two base64 strings then go into the environment file as JWT_PUBLIC_KEY_BASE64 and JWT_PRIVATE_KEY_BASE64. Encoding them into a single environment variable is what lets the same key pair be passed through Docker, compose and CI without putting PEM newlines in a configuration file.

Running it locally, or inside a container

Locally, the prerequisite is a running Postgres server, and the three run modes are the standard Nest ones:

bash
# development
$ npm run start

# watch mode
$ npm run start:dev

# production mode
$ npm run start:prod

The package scripts confirm the shape: start is nest start, start:dev is nest start with watch and preserveWatchOutput, start:debug adds the debug flag, and start:prod runs the compiled output with node dist/src/main. There is also a cli:dev and cli:prod pair, which means the project ships a second entry point, src/cli.ts, for command line work alongside the HTTP server.

The Docker route is a build, a run and a compose variant:

bash
# build image
$ docker build -t my-app .

# run container from image
$ docker run -p 3000:3000 --volume 'pwd':/usr/src/app --network --env-file .env my-app

# run using docker compose
$ docker compose up

The run command mounts the working directory, which is what makes the container useful in development rather than as a deployment artefact. The link to the Docker conventions document is marked WIP because it currently points at an internal organisation link, which is a small reminder that this repository is maintained from inside a company rather than as a community project.

Migrations are TypeORM commands with a name parameter

The migration section is where the starter kit saves the most time, because the commands are already parameterised.

Generating a migration takes a name, with CreateUsers used as the example:

bash
# generate migration (replace CreateUsers with name of the migration)
$ npm run migration:generate --name=CreateUsers

# run migration
$ npm run migration:run

# revert migration
$ npm run migration:revert

Under the hood these run ts-node against the TypeORM CLI with ormconfig.ts as the data source, and the generated files land in the migrations/ directory at the repository root. The generate script is the interesting one, because it interpolates the npm config name into the output path, so a migration called CreateUsers is created in its own directory rather than being appended to a shared one.

The same commands work inside a container, which is the path the README shows first:

bash
# using docker
$ docker compose exec app npm run migration:run

Whether a migration is applied by hand or by a deploy step is left open, which is the right call for a template, since the answer depends on whether the team deploys immutable images or runs migrations inside a release job.

Tests, linting and the hooks in between

The test commands are the standard Jest set, with an end to end suite separated out:

bash
# unit tests
$ npm run test

# e2e tests
$ npm run test:e2e

# test coverage
$ npm run test:cov

The scripts behind them are jest --runInBand for the unit tests and jest with the ./test/jest-e2e.json configuration for the end to end tests, both forced serial, which is the sane choice for a suite that talks to a database. There is a watch mode, a debug mode that attaches the inspector, and a coverage mode.

Around the tests sits a full toolchain. Linting is ESLint over src, apps, libs and test, formatting is Prettier over the same source and test trees, and the repository has a commitlint.config.js together with a .husky/ directory, which is the commit-linting hook mentioned in the feature list. The prepare script runs husky install, so the hooks are set up as part of npm install rather than by a manual step.

The remaining top level files describe the working environment rather than the application: .tool-versions pins the toolchain version, .vscode/ and .devcontainer/ describe the editor and the containerised development environment, .editorconfig, .npmrc and .prettierrc handle formatting and package manager defaults, sonar-project.properties feeds the SonarCloud analysis, nest-cli.json and the two tsconfig files configure the Nest CLI and the TypeScript build, and docs/ holds the project structure document the README links to.

The compose file is where the defaults live

The docker-compose.yml is worth reading before anything else, because it lists the environment variables the application actually expects, and it shows what the development stack looks like.

There are three services. The app service builds from the repository context, runs npm run start:dev, maps port 3000, mounts the working directory into /usr/src/app with a named volume for node_modules so the container's dependencies are not shadowed by the host's, and passes through APP_ENV, APP_PORT, the DB_* variables, the two JWT expiry settings, the two JWT key variables and DEFAULT_ADMIN_USER_PASSWORD. It depends on the database service.

The database is a postgres:16.3 image with its own user, password and database name taken from the same environment variables, port 5432 published, and a named volume for the data directory. The third service is adminer, a database admin interface on port 8080, which is a small convenience that makes a composable development environment work.

The Dockerfile behind the app service is a development image built on node:20.19.6-bookworm-slim, which pins both the Node version and the base distribution. The first fifteen lines are enough to see the approach:

dockerfile
# Development Dockerfile
FROM node:20.19.6-bookworm-slim

# Install additional tools for development
RUN apt-get update && apt-get install -y \
  vim \
  curl \
  wget \
  git \
  && apt-get clean \
  && rm -rf /var/lib/apt/lists/*

WORKDIR /usr/src/app

The image installs the usual developer tools, copies package.json and package-lock.json before the rest of the source so the dependency install is cached, and a separate Dockerfile.prod exists for a production build.

Two details in the compose file deserve a second look before you deploy anything. The default admin password arrives as an environment variable, and the database port is published to the host, so a default compose up exposes a Postgres instance on the machine's network interface.

An open source kit that is also a sales funnel

The honest summary of this repository is that it is a consultancy's working template, published openly, with the commercial version sold alongside it.

The consulting section is explicit about it: most of the features have been tried out in production applications by MonstarLab, their production applications are more feature rich, and if you want a more feature rich starter kit with more features from day one you can reach out and collaborate as technology partners. The sample implementations live in a separate repository so you can see how the kit was used.

The maintenance picture is mixed. The tagged releases are old, with v1.0.0 on 2020-09-02 and v2.0.0 on 2021-03-09, while the last push to the repository was on 2026-06-01, so the code keeps moving without new tags. The package.json version field still reads 1.0.0 even though the README describes a NestJS 11 kit, which tells you the version field in a template repository is not a reliable signal.

The licence is MIT, which means you can take the whole thing, restructure it and ship it without asking. The named contributors are listed in both the README and the package.json manifest.

The one piece of documentation that is internal is the Docker conventions link, which the README marks as WIP and currently a private address. That is the clearest signal of the project's shape: everything a user needs is public, and the parts that are still being written are being written inside the company.

Editorial conclusion

Adopt nestjs-starter-rest-api if you want a NestJS service with the plumbing decisions already made, especially the JWT key handling, the migration commands and the Docker and devcontainer setup, and you are willing to restructure the generated code to fit your own conventions. Skip it if you want a service split into modules or a microservice, since the kit is explicitly monolithic, or if you need to keep the dependency set current, since the tagged releases are old even though the repository is still being pushed to. Before you build on it, read docs/project-structure.md, replace the .env.template values including the default admin password, and run the unit and end to end test commands to see which parts actually work out of the box. The last push was on 2026-06-01 and the newest tagged release is v2.0.0 from 2021-03-09.

Frequently asked questions

How do I generate the JWT keys for nestjs-starter-rest-api?

With Docker you run ./scripts/generate-jwt-keys and copy the two printed values into your .env file. Without Docker you create the pair with ssh-keygen and openssl, then base64 encode both files into JWT_PUBLIC_KEY_BASE64 and JWT_PRIVATE_KEY_BASE64.

What does the nestjs-starter-rest-api kit include out of the box?

JWT authentication, role based authorization, TypeORM for the ORM and for migrations, winston logging, class-validator request validation, SQL offset and limit pagination, a Dockerfile, a devcontainer, and auto-generated OpenAPI. The auto-generated changelog is the one item the README marks as work in progress.

How do I create and run a database migration?

Run npm run migration:generate --name=CreateUsers to create one, npm run migration:run to apply it, and npm run migration:revert to undo it. Inside Docker the same script is run with docker compose exec app npm run migration:run.

Which database does the docker-compose setup use?

The compose file defines a pgsqldb service from the postgres:16.3 image with a named volume for the data directory, and an adminer service on port 8080 for database administration. The app service reads its connection settings from the DB_HOST, DB_PORT, DB_NAME, DB_USER and DB_PASS environment variables.

Official sources

  1. Issues
  2. License: MIT
  3. monstar-lab-oss/nestjs-starter-rest-api on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/monstar-lab-oss-nestjs-starter-rest-api.svg)](https://hysenlabs.com/projects/monstar-lab-oss-nestjs-starter-rest-api)

Was this useful?