NestJS Boilerplates Comparison
Tags: node, javascript, typescript, opensource
Published: 2023-04-11 13:31:30

Hi Dev community! 

When you start development of a new project on NestJS you have quite a big range of options: starting from scratch or taking one of multiple boilerplates developed by the community. Starting from scratch is quite a good option, if you’d like to have full control of everything in your project and you have some time to set it all up. But if you have tight deadlines (almost always =) ), you can save quite a lot of time by taking one of the pre-setup solutions: boilerplates.

In the [Awesome NestJS](https://github.com/nestjs/awesome-nestjs#boilerplate) list I found 32 repositories under the Boilerplate section by the time this article was written. Quite a lot, huh? How would you choose what to take for your next project?
I must admit here that we are the authors of one of such boilerplates. But I promise, in this article we’ll try to be as objective as we can and try to help you to choose what fits you best.

## Pre-filter

Before we start, we need to filter those solutions somehow, because analyzing all 32 of them would take way too much time. We are lazy developers, so, better try to find just decent candidates first for our research. 

The main criterias will be:
- Support and Maintenance: if the project is active at all?
- Production readiness: if the project is ready to be used in production now?
- Performance
- Code quality

So finally we chose 5 boilerplates that more or less satisfy our requirements and added them to the table *:

<table>
<tr>
<th></th>
<th>Stars</th>
<th>Contributors</th>
<th>Last Commit Date</th>
<th>Open Issues</th>
<th>Approach</th>
</tr>

<tr>
<td><a href="https://github.com/brocoders/nestjs-boilerplate">NestJS REST API Boilerplate</a></td>
<td>860</td>
<td>8 contributors, most of code written by 1 developer, supported and used by <a href="https://brocoders.com/">Brocoders</a></td>
<td>26-03-2023</td>
<td>3</td>
<td>REST API</td>
</tr>

<tr>
<td><a href="https://github.com/NarHakobyan/awesome-nest-boilerplate">Awesome NestJS Boilerplate</a></td>
<td>1.6K</td>
<td>15 contributors, most of code written by 1 developer</td>
<td>18-03-2023</td>
<td>9</td>
<td>REST API</td>
</tr>

<tr>
<td><a href="https://github.com/notiz-dev/nestjs-prisma-starter">NestJS Prisma Starter</a></td>
<td>1.7K</td>
<td>22 contributors, most of code written by 1 </td>
<td>23-01-2023</td>
<td>4</td>
<td>GraphQL</td>
</tr>

<tr>
<td><a href="https://github.com/squareboat/nestjs-boilerplate">Squareboat NestJS Boilerplate</a></td>
<td>469</td>
<td>10 contributors, most of code written by 1 developer</td>
<td>01-03-2023</td>
<td>4</td>
<td>REST API</td>
</tr>

<tr>
<td><a href="https://github.com/ahmetuysal/nest-hackathon-starter">Nest Hackathon Starter</a></td>
<td>279</td>
<td>6 contributors, most of code written by 1 developer</td>
<td>24-01-2023</td>
<td>1</td>
<td>REST API</td>
</tr>
</table>

_* the data from Apr 2023_

Now we are going to compare them by features.

## Features

<table>
  <thead>
    <tr>
   <th></th>
   <th>NestJS REST API Boilerplate</th>
   <th>Awesome NestJS Boilerplate</th>
   <th>NestJS Prisma Starter</th>
   <th>Squareboat NestJS Boilerplate </th>
   <th>Nest Hackathon Starter</th>
</tr>
<tr>
   <td>Documentation</td>
   <td>+</td>
   <td>Legacy</td>
   <td>+</td>
   <td>+</td>
   <td>-</td>
</tr>
<tr>
   <td>Sign in / Sign up</td>
   <td>+</td>
   <td>+</td>
   <td>+</td>
   <td>-</td>
   <td>+</td>
</tr>
<tr>
   <td>Social sign in</td>
   <td>+</td>
   <td>-</td>
   <td>-</td>
   <td>-</td>
   <td>-</td>
</tr>
<tr>
   <td>Roles</td>
   <td>+</td>
   <td>+</td>
   <td>+</td>
   <td>-</td>
   <td>-</td>
</tr>
<tr>
   <td>Confirm email</td>
   <td>+</td>
   <td>-</td>
   <td>-</td>
   <td>-</td>
   <td>+</td>
</tr>
<tr>
   <td>Forgot password</td>
   <td>+</td>
   <td>-</td>
   <td>-</td>
   <td>-</td>
   <td>-</td>
</tr>
<tr>
   <td>Config Service</td>
   <td>+</td>
   <td>+</td>
   <td>+</td>
   <td>-</td>
   <td>-</td>
</tr>
<tr>
   <td>Mailing</td>
   <td>+</td>
   <td>-</td>
   <td>-</td>
   <td>+</td>
   <td>+</td>
</tr>
<tr>
   <td>Translations</td>
   <td>+</td>
   <td>+</td>
   <td>-</td>
   <td>+</td>
   <td>-</td>
</tr>
<tr>
   <td>Database</td>
   <td>+ (PostgreSQL + TypeORM or MongoDB)</td>
   <td>+ (PostgreSQL, TypeORM)</td>
   <td>+ (PostgreSQL, Prisma)</td>
   <td>+ (Knex)</td>
   <td>+ (PostgreSQL, Prisma)</td>
</tr>
<tr>
   <td>Migrations</td>
   <td>+</td>
   <td>+</td>
   <td>+</td>
   <td>+</td>
   <td>+</td>
</tr>
<tr>
   <td>Seeding</td>
   <td>+</td>
   <td>-</td>
   <td>+</td>
   <td>+</td>
   <td>-</td>
</tr>
<tr>
   <td>File upload</td>
   <td>Local, AWS S3, Can extend </td>
   <td>AWS S3, Can not extend</td>
   <td>-</td>
   <td>-</td>
   <td>-</td>
</tr>
<tr>
   <td>Tests</td>
   <td>+</td>
   <td>+</td>
   <td>+</td>
   <td>+</td>
   <td>+</td>
</tr>
<tr>
   <td>CI</td>
   <td>E2E tests, linter</td>
   <td>Linter</td>
   <td>Unit tests</td>
   <td>-</td>
   <td>-</td>
</tr>
<tr>
   <td>Swagger</td>
   <td>+</td>
   <td>+</td>
   <td>+</td>
   <td>-</td>
   <td>+</td>
</tr>
<tr>
   <td>Docker</td>
   <td>+</td>
   <td>+</td>
   <td>+</td>
   <td>-</td>
   <td>-</td>
</tr>
<tr>
   <td>Auto updating dependencies</td>
   <td>+</td>
   <td>-</td>
   <td>-</td>
   <td>-</td>
   <td>+ (But without tests. It can break build)</td>
</tr>
  </tbody>
</table>

## Code Review

Here I will briefly take a look into the repositories and give my notes about the source code of each selected repository. I would say that I didn’t find any critical issues, just a few things that make sense to keep in mind. Hopefully this code review can help you to avoid some common mistakes in your projects.

### Awesome NestJS Boilerplate

There is some performance-related issues:

1. Redundant queries to DB in jwt.strategy which will execute on each request.
    ```
    const user = await this.userService.findOne({
      // FIXME: issue with type casts
      id: args.userId as never,
      role: args.role,
    });
    ```
    [Code](https://github.com/NarHakobyan/awesome-nest-boilerplate/blob/1d64e30d5ca02ee4cc9e3655fc0cfc4fcd702347/src/modules/auth/jwt.strategy.ts#L32-L36)
    This can reduce performance of your application.

2. Tables are not optimized (indexies are not created) 
    ```
    @ManyToOne(() => UserEntity, (userEntity) => userEntity.posts, {
      onDelete: 'CASCADE',
      onUpdate: 'CASCADE',
    })
    @JoinColumn({ name: 'user_id' })
    user: UserEntity;
    ```
    [Code](https://github.com/NarHakobyan/awesome-nest-boilerplate/blob/1d64e30d5ca02ee4cc9e3655fc0cfc4fcd702347/src/modules/post/post.entity.ts#L15-L20)
    On a large dataset the application will work slowly, for example for `get posts by user`.

There are imperfections with file upload:

- There is no validation for file size and mime type.
- File uploading follows some bad practices: for each endpoint we need to write weird logic for handling files.

Also the Auth flow is not complete. Email confirmation and Forgot password flows are missing.

### NestJS Prisma Starter

1. Performance issues:
    The issue is similar to Awesome NestJS Boilerplate: redundant queries to DB. 
    
    ```
    validateUser(userId: string): Promise<User> {
      return this.prisma.user.findUnique({ where: { id: userId } });
    }
    ```
    [Code](https://github.com/notiz-dev/nestjs-prisma-starter/blob/5158511c4a617aaa1e2850d49b6125fd440e43f0/src/auth/auth.service.ts#L75-L77)
    This can reduce performance of your application.
2. Some tables are not optimized (indexies not created): [Code](https://github.com/notiz-dev/nestjs-prisma-starter/blob/5158511c4a617aaa1e2850d49b6125fd440e43f0/prisma/migrations/20220118074231_init/migration.sql#L1-L35). On a large dataset the application will work slowly.

Auth flow is not complete. Email confirmation and Forgot password flows are missing.
File uploading is missing.

### Squareboat NestJS Boilerplate

There is only a NestJS + database setup, with its own solutions which will be hard to support in the future.

### Nest Hackathon Starter

This boilerplate has good designed schema, with optimization, but still there is problem with performance:
 - jwt.strategy makes redundant queries to DB which will execute on each request.
    ```
        const user = await this.authService.validateUser(payload);
    ```
    [Code](https://github.com/ahmetuysal/nest-hackathon-starter/blob/83f2fb9999b2978a52fd935276c6722b9d4b82a3/src/auth/jwt.strategy.ts#L20)

Bad designed mailing:
1. Own template solution
    ```
      const mail = confirmMail
        .replace(new RegExp('--PersonName--', 'g'), name)
        .replace(new RegExp('--ProjectName--', 'g'), config.project.name)
        .replace(new RegExp('--ProjectAddress--', 'g'), 
...
    ```
    [Code](https://github.com/ahmetuysal/nest-hackathon-starter/blob/83f2fb9999b2978a52fd935276c6722b9d4b82a3/src/mail-sender/mail-sender.service.ts#L46-L60)
    It will be hard to support.
2. A part of templates are stored in a service file:
    ```
    this.socials = config.project.socials
      .map(
        (social) =>
          `<a href="${social[1]}" style="box-sizing:border-box;color:${config.project.color};font-weight:400;text-decoration:none;font-size:12px;padding:0 5px" target="_blank">${social[0]}</a>`,
      )
      .join('');
  }
    ```
    [Code](https://github.com/ahmetuysal/nest-hackathon-starter/blob/83f2fb9999b2978a52fd935276c6722b9d4b82a3/src/mail-sender/mail-sender.service.ts#L34)

Bad designed service config. Configs are [stored in JS object](https://github.com/ahmetuysal/nest-hackathon-starter/blob/83f2fb9999b2978a52fd935276c6722b9d4b82a3/src/config.ts#L1-L38), without env configuration. This can cause problems with security.

### Brocoders NestJS Boilerplate

I wouldn’t say too much about this Boilerplate as I wrote most of it and it would be difficult to criticise it :-) 
But I’d like to note that I mostly followed official documentation of REST API and [NestJS techniques](https://docs.nestjs.com/techniques/configuration). I tried to focus on performance and long support along with e2e tests.


It includes all necessary features [for auth](https://github.com/brocoders/nestjs-boilerplate/blob/main/docs/auth.md) (sign in, sign up, social sign up, confirm email, forgot password and roles) and [file uploading](https://github.com/brocoders/nestjs-boilerplate/blob/main/docs/file-uploading.md) (this allows one endpoint for file uploading and then attach it to any other entity). I decided to have it from the box, because all the projects we started required these features.

> Read more about [Brocoders NestJS Boilerplate on Dev.to](https://dev.to/rodik/fast-project-start-with-nestjs-boilerplate-3992)

## Conclusion

Actually from the code review standpoint all of the selected solutions are good. Nothing critical, any of such issues can be easily resolved in your own implementation. However, it makes sense to select the starter kit knowing all the differences between solutions and make your choice consciously.

Full credits to [Vlad Shchepotin](https://github.com/Shchepotin) for this article and the Boilerplate!