Deploy NestJS with Prisma to Heroku
Deploy a NestJS application with Prisma 2.0 to Heroku and connect to a PostgreSQL database.
- Authors
- Marc Stammerjohann
- Published at
You will learn how to deploy a NestJS application with Prisma 2.0 to Heroku ๐. Also we will create a PostgreSQL database on Heroku and connect it with Prisma.
Check out my previous tutorial to create a PrismaService
for your Nest application.
Preparing Nest application for Heroku
Let's get started by preparing our Nest application to run on Heroku.
First, we modify main.ts
to use the port provided by Heroku as an environment variable. CORS can also be enabled for web or mobile applications making requests to the Nest application.
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.enableCors();
await app.listen(process.env.PORT || 3000);
}
bootstrap();
Heroku takes care of installing our node_modules for us. Before Heroku can start our Nest application using npm run start:prod
, we need to generate the PrismaClient
and build our app. We add "postinstall": "npx prisma generate && npm run build",
to the scripts in our package.json which generates a new PrismaClient
and performs the app build, creating our dist
folder.
Heroku needs to know how to execute our Nest application via a Procfile
. Create a Procfile
in the root folder with our start script web: npm run start:prod
. Now Heroku will install our dependencies, generate Prisma Client and build the application in the postinstall script and then start the application.
New Heroku app and CLI
Next, sign up or log into your Heroku account. Create a new Heroku app by clicking on New and then Create new app.
Choose an app name to identify your app and the name is also used as your default api endpoint at https://your-app-name.herokuapp.com/. You can also choose between two regions for your app United States and Europe.
Heroku let's you configure a custom domain in your app settings.
Alright, our heroku app is set up.
We install the Heroku CLI and deploy our Nest application by pushing to Heroku git.
heroku login
cd your-nest-app
heroku git:remote -a your-app-name
git push heroku master
After pushing our current application to Heroku, we see the following output in our terminal or in the Activity tab of our Heroku app.
Heroku prints Build succeeded! and our application link at the end like https://nestjs-prisma-heroku.herokuapp.com/.
Let's visit our app by either clicking on the link or on Open app in the toolbar.
I am seeing Hello World!. The Nest app has been successfully deployed to Heroku ๐
In the next step we will setup a PostgreSQL database and use Prisma Migrate to apply our database schema.
Setup PostgreSQL and use Prisma Migrate
Navigate to Resources tab on Heroku and search for the Heroku Postgres addon.
We select a plan for our Postgres database, we start with the Hobby Dev - Free plan and click Provision. We can upgrade the database plan later at anytime.
Our database has been setup and it appears in the addon list.
To connect Prisma to the database, we need to provide the database connection URL found in the Settings of our database. Select Heroku Postgres and switch to the Settings tab and View Credentials.... Copy the whole URI starting with postgres://
.
.env file support is included in Prisma 2.0. Hence, we provide the database connection URL as the environment variable DATABASE_URL
.
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
Paste the URI from the Heroku Postgres dashboard into the prisma/.env
file.
DATABASE_URL=postgres://ytodrxnfzdnxlr:005777fd...
Do not commit .env
files into version control.
Right now our database is empty and has no tables.
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
}
model NationalPark {
id Int @id @default(autoincrement())
name String
country Country @relation(fields: [countryId], references: [id])
countryId Int
}
model Country {
id Int @id @default(autoincrement())
name String @unique
parks NationalPark[]
}
Let's use Prisma Migrate to save and apply our migrations for the following schema.
npx prisma migrate dev
We can use Prisma Studio to view if our migration was successful. Run and open studio at http://localhost:5555.
npx prisma studio
Our migration was successful ๐ We see the NationalPark and Country table was created in our database. We can use Prisma Studio to create our test data, start creating a new Country and then new NationalParks as they require a connection to a country.
Since we have our database ready, we create two REST endpoints to query all NationalParks and to create a new NationalPark in our Nest application.
Prisma CRUD operations in Nest
Before we implement our CRUD operations in Nest, we need to generate a new PrismaClient
whenever we make a change to our schema.prisma
or our .env
file. Run npx prisma generate
and now we have access to the CRUD operations of our models.
Find Many National Parks
We setup the GET
endpoint for all NationalParks at /nationalParks
.
import { Controller, Get } from '@nestjs/common';
import { PrismaService } from './prisma/prisma.service';
@Controller()
export class AppController {
constructor(private readonly prisma: PrismaService) {}
@Get('nationalParks')
getNationalParks() {
return this.prisma.nationalPark.findMany();
}
}
Start the Nest app locally in dev mode npm run start:dev
and try the request at http://localhost:3000/nationalParks.
I have added one national park via Prisma Studio, but we don't see the Country in the response. To return the countries in the national park response we include country in the findMany()
query using the include
keyword.
@Get('nationalParks')
getNationalParks() {
return this.prisma.nationalPark.findMany({ include: { country: true } });
}
Awesome, our response now includes Country.
Create New National Park
We can query our national parks, but we also want to add new national parks. Create the NationalParkDto
class with the two properties name
for the national park and country
as the country name.
export class NationalParkDto {
name: string;
country: string;
}
We use this DTO class in the POST
endpoint for creating a new national park.
@Post('nationalPark')
createNationalPark(@Body() nationalParkDto: NationalParkDto) {
}
As we need a country id
to connect to a national park we use prisma.country.findOne
to see if this country already exists in our database. Use async/await
to find the country as PrismaClient
CRUD operations always return Promise
's.
@Post('nationalPark')
async createNationalPark(@Body() nationalParkDto: NationalParkDto) {
const country = await this.prisma.country.findOne({
where: { name: nationalParkDto.country },
});
if (country) {
// create national park and connect country
});
} else {
// create national park and create country
}
}
When we create our national park we have two options for how to create the connection to a country. If the country exists we use connect
using the country id country: { connect: { id: country.id } }
. Otherwise we create
the country alongside the national park country: { create: { name: nationalParkDto.country } }
. Let's also return the created NationalPark including the Country in our response. Our POST
endpoint looks like this:
@Post('nationalPark')
async createNationalPark(@Body() nationalParkDto: NationalParkDto) {
const country = await this.prisma.country.findOne({
where: { name: nationalParkDto.country },
});
if (country) {
return this.prisma.nationalPark.create({
data: {
name: nationalParkDto.name,
country: { connect: { id: country.id } },
},
include: { country: true },
});
} else {
return this.prisma.nationalPark.create({
data: {
name: nationalParkDto.name,
country: { create: { name: nationalParkDto.country } },
},
include: { country: true },
});
}
}
Yeah! ๐ The request works locally.
We are ready to push our Nest application to Heroku again to expose the two new REST endpoints.
Push to Heroku and test new Endpoints
Run git push heroku master
in your Nest application and wait for the build to succeed. Also, we need to see if the environment variable DATABASE_URL
is added to the Heroku app. Head over to the Settings tab and click on Reveal Config Vars. DATABASE_URL
has already been added when we installed the Heroku Postgres addon. If you like to change your database you can update the URL here.
Our new endpoints have been successfully deployed. Time to test it out https://nestjs-prisma-heroku.herokuapp.com/nationalParks.
To wrap up, we have successfully deployed ๐ our Nest application ๐ป on Heroku and connected Prisma to a PostgreSQL database.
Sponsor us
Did you find this post useful? We at notiz.dev write about our experiences developing Apps, Websites and APIs and develop Open Source tools. Your support would mean a lot to us ๐. Receive a reward by sponsoring us on Patreon or start with a one-time donation on GitHub Sponsors.