In this tutorial, you will deploy your API to production so that you and others can access it publicly. You will also refactor the project to make it ready for deployment on Heroku. Additionally, you will automate the deployment process using GitHub Actions — also referred to as continuous deployment.
You will need to install a few command line utilities and create some accounts to follow this chapter. We suggest you do this now so as not to break the flow of the tutorial.
Note: Docker and Docker Compose will be used to run an instance of the PostgreSQL database. If you prefer, you can install and run PostgreSQL natively as well. If you choose to run natively, you will need to make some slight changes to the instructions shown in this tutorial.
With that out of the way, you can get started!
To automate the deployment process, you will need version control to synchronize the changes on your local machine with the production deployment. This tutorial will not cover the basics of using version control.
Note 1: If you’re unfamiliar with the basics git, I would suggest this series by Atlassian. To understand the git commands used in this tutorial, the first two articles of this series are sufficient.
Note 2: If you have already set up version control and a repository on GitHub for this project, you can jump ahead to the Changing SQLite to PostgreSQL section.
Before you commit any file, you need to add some files to the
Now it’s time to create your first commit. 🎉
Now that you have a local commit, it’s time to create a remote repository on GitHub. You can do this entirely from your terminal using the GitHub command line tool (also known as
Note 1: If you haven’t installed
ghand logged in with your GitHub credentials, you can do so with the
gh auth logincommand.
Note 2: If you’re not comfortable using the CLI to create a repository, you can do it using GitHub’s graphical user interface (GUI). However, this tutorial will not demonstrate how to do this.
This command will create a private repository inside your GitHub account called
hackernews-typescript. The final results of the above command should look like the following, with ”__username__” being replaced by your actual GitHub handle:
✓ Created repository __username__/hackernews-typescript on GitHub ✓ Added remote email@example.com:__username__/hackernews-typescript.git
Once this command finishes execution, you should see the repository with all your code under your GitHub profile.
Note: This tutorial assumes the name of your default branch is “master”. In case it is “main”, replace “master” with “main” in the above command.
The previous tutorials have been using SQLite as the database for your API. However, SQLite is not typically used for production web backends for several reasons. So, before you start working on deployment, you will migrate from SQLite to a more conventional and powerful database: PostgreSQL.
Note: We chose SQLite for this tutorial as it requires minimal setup and configuration. However, deploying SQLite to Heroku would be difficult and need a lot of extra configuration (more info here). This is why you will migrate to PostgreSQL for this chapter.
Now that all SQLite assets have been removed, it’s time to update your Prisma schema to use PostgreSQL.
There are two fields that you should understand:
providerfield signifies the underlying database type. You changed the field from
urlfield specifies the database connection string. For SQLite, this was a path to the file. In the case of PostgreSQL, the database connection string will be read from the
DATABASE_URLenvironment variable that will be defined in the project’s
Now you need a PostgreSQL database running on your local machine. You are going to do this using a containerized version of PostgreSQL.
Here is what is happening inside the
# 1: The
imageoption defines what Docker image to use.
# 2: The
environmentoption specifies the environment variables passed to the container during initialization. You can define the configuration options and secrets – such as the username and password – the container will use here.
# 3: The
volumesoption is used for persisting data in the host file system.
# 4: The
portsoption maps ports from the host machine to the container. The format follows the convention of “host_port:container_port”. In this case, you are mapping the port
5432of the host machine to port
5432is conventionally the port used by PostgreSQL.
With that out of the way, you can now spin up the database with one command. Before you move on to the next instruction, make sure that nothing is already running on port
5432, in which case, the following command will fail.
If everything worked properly, the new terminal window should show logs saying that the database system is ready to accept connections. The logs should be similar to this
.... postgres_1 | 2022-03-05 12:47:02.410 UTC  LOG: listening on IPv4 address "0.0.0.0", port 5432 postgres_1 | 2022-03-05 12:47:02.410 UTC  LOG: listening on IPv6 address "::", port 5432 postgres_1 | 2022-03-05 12:47:02.411 UTC  LOG: listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432" postgres_1 | 2022-03-05 12:47:02.419 UTC  LOG: database system is ready to accept connections
Note 1: You cannot close the new terminal window as it will also stop the container. You can avoid this if you add
-dto the previous command, like this:
docker-compose up -d.
Note 2: Once started, the container will persist even if you restart your machine. At any point if you want to stop the database container, use the following command from the terminal in the root folder of your project:
You will also need to securely provide the connection URL to the newly created PostgreSQL instance to Prisma. To do this, you will use the
Now it’s time to provide a connection string that Prisma can connect to PostgreSQL. Remember that inside the
schema.prisma file you defined the connection string environment variable as
This is the format used by Prisma for PostgreSQL connection strings:
Note that the Arguments portion is optional and is absent in your connection string.
Now it’s time to recreate the migrations, but this time specific to PostgreSQL.
Chapter 4 covers the core concept behind the
migrate command. This command will also regenerate Prisma Client based on the most recent schema.
Restart server with
npm run dev. While your previous data will have disappeared, all functionality should remain intact. Feel free to test out all the queries/mutations to confirm they work as expected.
index.tsto make it deployment ready
You will need to make a few changes to the
index.ts to make the API ready for deployment.
You have made the following changes:
// 1: Introspection is a feature that allows a GraphQL client to ask a GraphQL server for information about what queries it supports. Apollo turns off introspection in production by default as a security measure. However, you are keeping introspection as it makes it easier to explore the API, though this is not something you usually do in a production application.
// 2: Similar to introspection, Apollo also turns off Apollo Sandbox in the production version of an app. Once again, as this is not a real application with production workloads, we explicitly decided to keep it on for convenience.
// 3: Previously, Apollo Server was running on port
3000on your local machine. Heroku will provide the port number the app will run on through the
portenvironment variable in production.
Note: Apollo Server determines whether your app is running in development or production by using the
NODE_ENVenvironment variable, which is set automatically to “production” during deployment by Heroku.
So far, you have been using
node. To do this, you will need to create two additional scripts in your
package.json. You will also add a new script to apply database migrations to your production database.
Here’s what the scripts are doing:
migrate:deployscript applies all pending migrations to the production database by running
prisma migrate deploy. This command is somewhat different from
prisma migrate dev, which you have used to generate/apply migrations in your development database. You can find more information about the
migrate deploycommand in the Prisma docs.
buildscript first runs
prisma generateto create the Prisma Client, then runs
node. Notice that the code generated by
tscgoes into the
distfolder because of the
outDiroption specified in your
Now you will create another commit.
With that out of the way, it’s time to get started deploying the app! 🚀
In this section, you will create the Heroku app along with a PostgreSQL database to host your API. Make sure you have created a Heroku account and logged into the CLI with the
heroku login command before proceeding with this section.
After the command finishes executing, you should see a result like this:
Creating ⬢ app-name-placeholder... done https://app-name-placeholder.herokuapp.com/ | http://app-name-placeholder.herokuapp.com/
We will use “app-name-placeholder” as a placeholder name for the Heroku app throughout the rest of the tutorial; replace it with your app name when appropriate.
You can also go to your Heroku dashboard on a browser to verify the newly created app.
Heroku add-ons are components that support your application, such as data storage, monitoring, analytics, data processing, and more. You will now use the heroku-postgres add-on to create a database for your app.
You should see an output similar to the following:
Creating heroku-postgresql:hobby-dev on ⬢ app-name-placeholder... free Database has been created and is available ! This database is empty. If upgrading, you can transfer ! data from another database with pg:copy Created postgresql-cubic-54990 as DATABASE_URL
This command also creates a new environment variable called
DATABASE_URL in the Heroku app, the connection string to the PostgreSQL database. This is very convenient because when you deploy the API, Prisma will have access to the production database automatically, without any additional configuration on your end. The connection string uses the same format as Prisma too!
Note: You can check your production database connection string with this command:
heroku config:get DATABASE_URL.
Now that we have set up the necessary resources on Heroku, it’s time to set up a deployment pipeline that will ensure continuous deployment.
GitHub Actions is an automation tool used for continuous integration (CI) and continuous deployment (CD). It allows orchestrating workflows based on events in GitHub and can be used to build, test, and deploy your code directly from GitHub.
To configure GitHub Actions, you define workflows using the “yaml” file format. These workflows are stored in the
.github/workflows directory of your project. You can configure workflows to run on different repository events, e.g., when a commit is pushed to the repository or when a pull request is created.
Each workflow can contain one or more jobs which are dedicated tasks, which run in an isolated environment (known as a “runner”). A single job can also have one or more steps. In this project, you will create a single workflow with a job called
Here’s what is going on here:
# 1: The
namekeyword defines the name of the workflow.
onis used to define which events will trigger the workflow to run automatically. In this case, it will run on a push to the
# 3: The
useskeyword specifies that this step will run
actions/checkoutaction. This action checks-out your repository to the runner so your workflow can access it.
# 4: The
runkeyword is used to execute any arbitrary shell command on the runner. In this case, you are using
npm ciwhich is similar to
npm install, but more suitable for automated environments. Details are available on the npm docs
# 5: The runner will execute the
migrate:deploynpm script. This is to synchronize any database changes to the production database. The
envproperty provides the database connection string to the runner.
# 6: This command uses the
firstname.lastname@example.org to deploy the final code to Heroku. The
withkeyword is used to pass certain parameters to the action.
In the GitHub Actions workflow you just created, you referenced quite a few
secrets. Secrets allow you to store sensitive information in your repository instead of keeping them in your code. These secrets can be accessed by your GitHub Action when executing a workflow.
You can set secrets using the GitHub website GUI or the
gh CLI tool. In this tutorial, you will learn how to do it using the CLI. If you prefer to do it using the website, take a look at this guide.
The syntax for creating a new secret using
gh secret set SECRET_NAME, where
SECRET_NAME should be replaced with the name of your secret. Running this command will initiate an interactive prompt where you will have to enter the secret value.
The first secret you will set will be
HEROKU_EMAIL. This is the email account you used to create your Heroku account.
Note: If you make a mistake and need to update the value of a secret, running the
gh secret setcommand again with the same secret name will update the value of that particular secret.
You can check or verify the Heroku app name by running the following command in the root of your project:
Now you will need to retreive your
HEROKU_API_KEY. This key is available under the Account tab of your Heroku Account Settings. Go to the Account Settings and scroll down to API Key. Finally press the Reveal button to retreive the key.
The final secret is
DATABASE_URL which contains the connection string to your production database. This is already available in Heroku as an environment variable under the same name (
DATABASE_URL). You can fetch it from Heroku using the following command:
heroku config:get DATABASE_URL
That’s it! All the secrets have been set and it is now possible to deploy and execute your GitHub Action. If you want to see the name of the secrets available in your repository, you can do so using the
gh secret list command.
This should create and trigger the
deploy-hackernews-app-heroku workflow on GitHub. You can trigger the workflow at any time creating an empty commit:
git commit --allow-empty -m "trigger build" git push
Once you have pushed a commit, quickly go to the Actions tab of your GitHub repository, and you should see that the workflow is in progress.
You can also go inside the workflow to inspect the status of any job. To verify that the deployment went successfully: Click on the most recent workflow in the All workflows table in the Actions tab for your repository. Then click on the deploy job located in the Jobs table to the left-hand side. Finally, Click on the Run email@example.com step to expand the logs.
If everything goes successfully, you should see something similar to the following near the end of the logs:
remote: -----> Launching... remote: Released v2 remote: https://***.herokuapp.com/ deployed to Heroku
Your API should now be live on Heroku. Every time you push a new commit to the
master branch to GitHub, the workflow will be triggered automatically, rebuilding the app and redeploying it to Heroku.
Note: Heroku will use the
npm run buildand
npm run startcommands to start the application by itself. For all Node.js apps, Heroku will check for the
buildscript and run it if it is available. Finally, it will start the app using the
startscript. So a Node.js app deployed to Heroku needs to have a
Press the Query Your Server button to be redirected to Apollo Studio Explorer. At this point, you should run a few queries to test out all functionality. The commands tested at the end of Chapter 6 are a good way to test out the main functionalities.
Note: The URL for your Heroku App is also provided as Web URL by the following CLI command:
Previously, you were using Prisma Studio to interact with your data directly. However, Prisma Studio is meant to be used with your development or test database and is not a great option to interact with production data. To solve this problem, Prisma has a hosted version of Prisma Studio inside the Prisma Data Platform, called the Data Browser.
To get started with the Prisma Data Platform, sequentially follow the steps outlined below:
The next time you log in to the Prisma Data Platform, the project you just created should be available for you to access. The project will also be synced with any schema changes pushed to the selected branch on GitHub.
Like Prisma Studio, the Data Browser allows you to explore and edit your data. The Prisma Data Platform also has collaboration features and permission levels, helpful when working with a team. It also has a Query Console, which allows you to write and execute Prisma queries against your production database. Feel free to explore all the features or learn more about the Prisma Data Platform by reading the docs.