Perfect Nest.js with Docker Compose and MongoDB Mongoose
Posted July 5, 2024
This is a deep dive tutorial to Running Nest.js and MongoDB with Docker and Docker Compose. Nest.js lets you use Mongoose. We’ll use Nest.js with MongoDB alongside Mongoose. We’ll then configure the Wholde Nest.js MongoDB App with Docker and Docker Compose.
⚠️ Please note: This tutoril will need Docker installed and running on your computer. You will learn:
- How to package Nest.js with MongoDB using Mongoose.
- Running Nest.js MongoDB Docker Containers.
- Connecting Nest.js to a MongoDB Docker service.
- How to access a Nest.js MongoDB server with Mongo Express and Docker only.
Ready? Let’s spin MongoDB and Nest.js with Docker like PROs.
Setting up Nest.js with MongoDB and Docker
First, we’ll need a working Nest.js app. I hope you have one. If not, run the following commands:
# Make sure you have Nest.js CLI
npm i -g @nestjs/cli
# Set Up a New app
nest new nest-docker
You will now point your app to this new nest-docker
directory:
cd nest-docker
Nest.js will require you to have Mongoose installed as a dependency. We’ll use the following command. Run it as such:
npm i mongoose @nestjs/mongoose
This app is fine, up to this point. Let’s dive into the Docker setup.
Packaging Nest.js and MongoDB with Docker
To run any app with Docker, we will need a Dockerfile—a Dockerfile layout all the commands and instructions Docker will need to move this Nest.js app to Docker.
First, create a Dockerfile in your new nest-docker
directory:
touch Dockerfile
A Dockerfile needs to be optimized. And in this case, we’ll ensure that. For this case, we’ll use Docker with a multistage build approach. In the previous blog, we covered the Strategies to Slim and Reduce Docker Image Size. The multistage build is one of them. It will ensure we have a minimalist and optimized packaged Nest.js Docker Image.
Go to the created Dockerfile
and lay out the following:
###################
# The Build Stage
###################
FROM node:20-alpine AS build
# Docker working dir for Nest.js
WORKDIR /app
# Copy both .json files
# The * lets package-lock.json and package.json get copied
COPY package*.json .
## Install the packages on your package.json file
RUN npm install
# Copy over all the Nest.js source code
COPY . .
# Create the build
RUN npm run build
###################
# The Production Stage
###################
FROM node:20-alpine AS prod
# Setting up the production space
WORKDIR /app
COPY package*.json .
# Only run dependencies need for production
RUN npm install --only=production
# Copy dist from the build stage
COPY --from=build /app/dist ./dist
# State the port you need Nest.js to use
ENV PORT=3000
EXPOSE ${PORT}
# Command to run Nest.js on Docker
CMD ["npm","run", "start:prod"]
This Dockerfile gets Nest.js into an image. We’ll:
- Let the Build Stage package the build of Nest.js.
- Let the production stage optimize the build and only use the build for production to run the image.
To optimize this image further, we will create a .dockerignore
and remove the files and folder that Docker doesn’t need to copy:
touch .dockerignore
Then we add:
# Ignored these files and directories at any application level
**/README.md
**/.dockerignore
**/Dockerfile
**/docker-compose.yml
**/npm-debug.log
# Ignored these files and directories at any application level
**/.git/
**/dist/
**/coverage/
**/node_modules/
**/.next/
**/tmp/
Adding MongoDB Mongoose with Docker Compose
The next step is to prepare the MongoDB server. Because we’re running this example on Docker, we’ll need a way to access the server. MongoDB Express will act at the MongoDB UI in this case.
Docker Compose compose lay ots the instruction Dpcker will need to package all the services of your application. It runs the image from Docker Hub or the custom one. Like the one we’ve set up using Dockerfile for Nest.js.
In this first case, we’ll use Docker Compose to create access to MongoDB. Docker Compose will look up your directory and check if you have a docker-compose.yml
file. This means we must create this file within the same path as the Dockerfile. Do so using this command:
touch docker-compose.yml
Let’s now add the instruction into this docker-compose.yml
file and spin up a MongoDB Nest.js local Docker development environment as follows:
version: "3.8"
services:
mongo:
image: mongo:latest
container_name: mongo-db-server
environment:
MONGO_INITDB_ROOT_USERNAME: 'admin'
MONGO_INITDB_ROOT_PASSWORD: 'pass'
MONGO_INITDB_DATABASE: 'test'
security_opt:
- seccomp:unconfined
ports:
- "0.0.0.0:27017:27017"
networks:
- MONGO
volumes:
- type: volume
source: MONGO_DATA
target: /data/db
- type: volume
source: MONGO_CONFIG
target: /data/configdb
mongo-express:
image: mongo-express:latest
container_name: mongo-db-ui
environment:
ME_CONFIG_MONGODB_ADMINUSERNAME: 'admin'
ME_CONFIG_MONGODB_ADMINPASSWORD: 'pass'
ME_CONFIG_MONGODB_SERVER: mongo
ME_CONFIG_MONGODB_PORT: "27017"
ports:
- "0.0.0.0:8081:8081"
networks:
- MONGO
depends_on:
- mongo
restart: unless-stopped
networks:
MONGO:
name: mongo_mongo
volumes:
MONGO_DATA:
name: MONGO_DATA
MONGO_CONFIG:
name: MONGO_CONFIG
This layout creates a complete setup for running MongoDB with Mongo Express in a Docker environment. Let’s highlight some key parts of this layout:
- Creating MongoDB container (
mongo-db-server
). - Setting initial root username and password.
- Configuring Mongo Express to connect to the MongoDB server.
- Creating the services shared custom network (
MONGO
). - Defining volumes
MONGO_DATA
andMONGO_CONFIG
for persistent storage.
Spinning up MongoDB with Docker for Nest.js
The moment you have the above docker-compose.yml
file ready, you’ll run the following command to start the servers:
docker compose up --build -d
[+] Running 5/5
✔ Network mongo_mongo Created 0.1s
✔ Volume "MONGO_DATA" Created 0.0s
✔ Volume "MONGO_CONFIG" Created 0.0s
✔ Container mongo-db-server Started 0.6s
✔ Container mongo-db-ui Started 0.9s
Docker should have these two services running as such:
Next, check that Mongo Express can connect to the MongoDB server:
2024-07-05 13:37:59 Waiting for mongo:27017...
2024-07-05 13:38:00 Fri Jul 5 10:38:00 UTC 2024 retrying to connect to mongo:27017 (2/10)
2024-07-05 13:38:01 Fri Jul 5 10:38:01 UTC 2024 retrying to connect to mongo:27017 (3/10)
2024-07-05 13:38:02 Fri Jul 5 10:38:02 UTC 2024 retrying to connect to mongo:27017 (4/10)
2024-07-05 13:38:03 Fri Jul 5 10:38:03 UTC 2024 retrying to connect to mongo:27017 (5/10)
2024-07-05 13:38:04 Fri Jul 5 10:38:04 UTC 2024 retrying to connect to mongo:27017 (6/10)
2024-07-05 13:38:05 No custom config.js found, loading config.default.js
2024-07-05 13:38:05 Welcome to mongo-express 1.0.2
2024-07-05 13:38:05 ------------------------
2024-07-05 13:38:05
2024-07-05 13:38:05
2024-07-05 13:38:05 Mongo Express server listening at http://0.0.0.0:8081
Should get a welcome message from MongoDB express and the port it’s listening to. Open http://localhost:8081/
to access it.
We’ll use the following environments to log in:
- ME_CONFIG_MONGODB_ADMINUSERNAME: ‘admin’
- ME_CONFIG_MONGODB_ADMINPASSWORD: ‘pass’
Thus:
- Username is
admin
. - Password is
pass
.
⚠️ Note: We had the MONGO_INITDB_DATABASE: 'test'
environment to create a test database. It Didn’t work on my End. This means I will need to use the already available databases such as local
or admin
. Check your Express to confirm if you have the same issue and share solutions.
Accessing Dockerized MongoDB with Nest.js and Mongoose
We have all the Docker setups ready and running. Now. Nest.js should be able to connect to Docker. To do so, remember to have Mongoose installed:
npm i mongoose @nestjs/mongoose
Go ahead and create a new Nest.js module. I will use CATS as an example:
nest generate module cats
You will have a src/cats
folder. Add a new entity using Mongoose. You’ll create a cat.entity.ts
file with cat collections as such:
import { Schema, Prop, SchemaFactory } from '@nestjs/mongoose';
import { Document } from 'mongoose';
@Schema()
export class Cat extends Document {
@Prop()
name: string;
@Prop()
age: number;
}
export const CatSchema = SchemaFactory.createForClass(Cat);
The same CatsModule
on the src\cats\cats.module.ts
file should run this entity using MongooseModule.forFeature as follows:
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { Cat, CatSchema } from './cat.entity';
@Module({
imports: [
MongooseModule.forFeature([{ name: Cat.name, schema: CatSchema }])
],
})
export class CatsModule {}
Finally, create a MongoDB connection using Mongoose at the Nest.js entry point of the src\app.module.ts
file:
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { MongooseModule } from '@nestjs/mongoose';
import { CatsModule } from './cats/cats.module';
@Module({
imports:[
MongooseModule.forRoot('mongodb://admin:pass@mongo:27017/admin'),
CatsModule,],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
Take a keen look at the mongodb://admin:pass@mongo:27017/admin
MongoDB URI. You must
- Add the Password and username as you specified in the
docker-compose.yml
file. - The server is running on Docker. You won’t use localhost but
mongo
as the service responsible for running MongoDB server on Docker. - The MongoDB port 27017 remains the same.
- You will use the database
admin
. It was created by the MongoDB server.
Adding Nest.js to Docker Compose/MongoDB
Now, Make sure you add the following Nest.js service to run a Nest.js Container:
version: "3.8"
services:
nestjs:
build:
context: .
dockerfile: Dockerfile
container_name: nest-app
ports:
- "3000:3000"
depends_on:
- mongo
volumes:
- .:/usr/src/app
networks:
- MONGO
Note that this service:
- Will run Nestjs API and connect to MongoDB.
- Will depend on mongo service and share the same
MONGO
It’s time to spin the containers. We’ll use the same previous docker compose command:
docker compose up --build -d
Now, Docker should have 3 services running:
[+] Running 3/3
✔ Container mongo-db-server Started 1.7s
✔ Container nest-app Started 1.7s
✔ Container mongo-db-ui Started 1.7s
The nest-app
service should have a successful MongoDB connection with MongooseModule:
Finally, check the admin
database using the Mongo Express. Cats collection should be ready as such:
Now, go further and create a fledge Nest.js CRUD RESTfull API with Docker and MongoDB (Mongoose) on this Easy Nest.js Mongoose Example Tutorial with MongoDB