Serving NestJS via Firebase Functions

Intro

This is a simple step-by-step guide/note of how to deploy NestJS in Firebase Functions to go serverless as of September 2021. What I am writing here is almost entirely from the following link of Fireship.io.

It is an incredible source but I had to write this post (1) because I am amateur developer and I need a more digestible details, and (2) I wanted to record some of the changes I made after a few failed tries.

Details

I chose Option A of 'Point a function to Nest' from the site. It seemed to make NestJS and Firebase more decoupled than Option B of 'Add Nest to the Functions Source'.

Prerequisites:

  • You need to set up your project for 'Pay-as-you-go' tier in Firebase to use Functions. It is a good idea to set up your Firebase project before Step 0.

Step 0: Install Firebase tools and NestJS

You need both Firebase tools and NestJS installed on your machine.

$ npm i -g firebase-tools && npm i -g @nestjs/cli

Step 1: Create a folder for Firebase Functions.

Note the directory structure:

  • The parent directory has firebase.json and .firebaserc files, and a NestJS project directory is laid as its child.
    $ mkdir my_functions_project && cd my_functions_project
    
  • Inside the newly created my_functions_project directory, initialize for firebase functions.
    $ firebase init functions
    
  • You will need functions directory within the NestJS project directory (not immediately in my_functions_project), so you can delete the functions directory now.
    $ rm -rf functions
    

Step2: Adjust firebase.json to the NestJS directory

  • Inside the firebase.json file, add the line of "source": "my_nestjs_project" under functions.
    "functions": {
      "predeploy": "npm --prefix \"$RESOURCE_DIR\" run build",
      "source": "my_nestjs_project"
    }
    }
    

Step3: Create a NestJS project.

  • Inside my_functions_project directory, type in the following command:
    $ nest new my_nestjs_project
    

Step 4: Add Firebase and Express in NestJS Project.

  • We need Firebase Functions and Firebase Admin in our NestJS project directory.
  • We also need to install Express and its adaptor for NestJS, so run the following commands: (I broke lines for improved readability.)
    $ npm i firebase-functions firebase-admin 
    $ npm i express @nestjs/platform-express
    

Step 5: Create main.firebase-functions.ts in the NestJS project

  • In my_functions_project/my_nestjs_project/src, create main.firebase-functions.ts with the following content.
  • N.B. Yes, this is in addition to your main.ts. DO NOT DELETE IT.
import { NestFactory } from '@nestjs/core';
import { ExpressAdapter } from '@nestjs/platform-express';
import { AppModule } from './app.module';
import * as express from 'express';
import * as functions from 'firebase-functions';

const server = express();

export const createNestServer = async (expressInstance) => {
  const app = await NestFactory.create(
    AppModule,
    new ExpressAdapter(expressInstance),
  );

  return app.init();
};

createNestServer(server)
  .then((v) => console.log('Nest Ready'))
  .catch((err) => console.error('Nest broken', err));

export const api = 
  functions.region('asia-northeast3').https.onRequest(server);

Step 6: Edit eslintrc.js to make eslint happier.

  • VSCode can give an annoying error that import is wrong. This can be corrected by changing parserOptions.project from tsconfig.json to my_nestjs_project/tsconfig.json.
module.exports = {
  parser: '@typescript-eslint/parser',
  parserOptions: {
    project: 'my_nestjs_project/tsconfig.json',
    sourceType: 'module',
  },

Step 7: Update package.json of your NestJS project.

  • You need to add the following lines at the top level of package.json.
    "main": "dist/main.firebase-functions.js",
    "engines": {
      "node": "14"
    },
    
  • I have also added the following lines for convenience.
    "scripts":{
    ...
      "serve:firebase": "nest build && firebase serve --only functions",
      "deploy:firebase": "nest build && firebase deploy --only functions",
    ...
    }
    

Step 8: Test to see if it works.

In the my_functions_project/my_nestjs_project, run the following commands to see if everything works:

$ npm run serve:firebase
$ npm run deploy:firebase
$ npm run start:dev

Conclusion

I wrote this post as a note to myself but for others who may benefit from it. Leave your comments and/or questions how you like it.

Versions info (as of Sept 19, 2021)

  • Firebase: 9.18.0
  • NestJS: 8.1.1
  • NodeJS: 14.17.5