Getting Started on Heroku Fir with Node.js
Introduction
Complete this tutorial to deploy a sample Node.js app to Heroku Private Spaces on the Fir generation of the platform. To deploy the app to the Common Runtime or Cedar Private Spaces, follow this guide instead.
The tutorial assumes that you have:
- A verified Heroku Account
- An existing Fir Private Space
- A team admin role or the
app creation
permission - An SSH key added to your Heroku account
- Node.js and npm installed locally
- Postgres installed locally
Using dynos and databases to complete this tutorial counts towards your usage. We recommend using Classic-1X dynos and an Essential-0 Postgres database to complete this tutorial. Delete all resources after completing the tutorial.
Set Up
The Heroku CLI requires Git, the popular version control system. If you don’t already have Git installed, complete the following before proceeding:
Install the Heroku Command Line Interface (CLI). Use the CLI to manage and scale your app, provision add-ons, view your logs, and run your app locally.
Download and run the installer for your platform:
$ brew tap heroku/brew && brew install heroku
Download the appropriate installer for your Windows installation:
More installation options for the Heroku Command Line Interface (CLI) can be found here.
After installation, you can use the heroku
command from your command shell.
To log in to the Heroku CLI, use the heroku login
command:
$ heroku login
heroku: Press any key to open up the browser to login or q to exit:
Opening browser to https://cli-auth.heroku.com/auth/cli/browser/***
heroku: Waiting for login...
Logging in... done
Logged in as me@example.com
This command opens your web browser to the Heroku login page. If your browser is already logged in to Heroku, click the Log In
button on the page.
This authentication is required for the heroku
and git
commands to work correctly.
If you’re behind a firewall that uses a proxy to connect with external HTTP/HTTPS services, set the HTTP_PROXY
or HTTPS_PROXY
environment variables in your local development environment before running the heroku
command.
Clone the Sample App
If you’re new to Heroku, it’s recommended that you complete this tutorial using the Heroku-provided sample application.
To deploy an existing application, follow this article instead.
Clone the sample application to get a local version of the code. Execute these commands in your local command shell or terminal:
$ git clone https://github.com/heroku/node-js-getting-started.git
$ cd node-js-getting-started
You now have a functioning Git repository that contains a simple application. It includes
a package.json
file, which a Node.js dependency manager (like npm
), can use to install
dependencies.
Create Your App in a Fir Space
Delete your app and database as soon as you’re done to control costs.
You can get a list of all Heroku spaces by running $ heroku spaces
Create an app on Heroku to prepare the platform to receive your source code by replacing <space-name>
with the name of your Fir space in the command below:
$ heroku create --space <space-name>
Creating app in space <space name>...
Creating app in space <space name>... done, salty-shelf-87055
http://salty-shelf-87055-5d3af90ffbb3.herokuapp.com/ | https://git.heroku.com/salty-shelf-87055.git
When you create an app, a Git remote called heroku
also gets created and associated with your local Git repository. Git remotes are versions of your repository that live on other servers. You deploy your app by pushing its code to that special Heroku-hosted remote associated with your app.
Heroku generates a random name for your app, in this case, salty-shelf-87055
. You can specify your own app name.
Deploy the App
Using a dyno to complete this tutorial counts towards your usage. Delete your app and database as soon as you’re done to control costs.
Deploy your code. This command pushes the main
branch of the sample repo to your heroku
remote, which then deploys to Heroku:
$ git push heroku main
remote: Updated 18 paths from 3a23670
remote: Compressing source files... done.
remote: Building source:
remote: Waiting on build...
remote: Extracting source
remote: Image with name "salty-shelf-87055/builds" not found
remote: 3 of 6 buildpacks participating
remote: heroku/nodejs-engine 3.3.3
remote: heroku/nodejs-npm-install 3.3.3
remote: heroku/procfile 3.1.2
remote:
remote: [Heroku Node.js Engine Buildpack]
remote:
remote: [Checking Node.js version]
remote: Detected Node.js version range: >=22.0.0 <23.0.0-0
remote: Resolved Node.js version: 22.11.0
remote:
remote: [Installing Node.js distribution]
remote: Downloading Node.js 22.11.0 (linux-arm64) from https://nodejs.org/download/release/v22.11.0/node-v22.11.0-linux-arm64.tar.gz
remote: Verifying checksum
remote: Extracting Node.js 22.11.0 (linux-arm64)
remote: Installing Node.js 22.11.0 (linux-arm64)
remote: Installing application metrics scripts
remote: [1;35m
remote: [1;35m# Heroku Node.js npm Install Buildpack
remote:
remote: - Installing node modules
remote: - Using npm version `[0;33m10.9.0`
remote: - Creating npm cache
remote: - Configuring npm cache directory
remote: - Running `[0;33m[1;36mnpm ci "--production=false"`
remote:
remote: npm warn config production Use `--omit=dev` instead.
remote:
remote: added 162 packages, and audited 163 packages in 3s
remote:
remote: 76 packages are looking for funding
remote: run `npm fund` for details
remote:
remote: found 0 vulnerabilities
remote:
remote: - Done (2.840s)
remote: - Running scripts
remote: - No build scripts found
remote: - Configuring default processes
remote: - Adding default web process for `[0;33mnpm start`
remote: - Done (finished in 3.427s)
remote:
remote: [Discovering process types]
remote: Procfile declares types -> web
remote: Adding layer 'heroku/nodejs-engine:dist'
remote: Adding layer 'heroku/nodejs-engine:node_runtime_metrics'
remote: Adding layer 'heroku/nodejs-engine:web_env'
remote: Adding layer 'heroku/nodejs-npm-install:npm_runtime_config'
remote: Adding layer 'buildpacksio/lifecycle:launch.sbom'
remote: Added 1/1 app layer(s)
remote: Adding layer 'buildpacksio/lifecycle:launcher'
remote: Adding layer 'buildpacksio/lifecycle:config'
remote: Adding layer 'buildpacksio/lifecycle:process-types'
remote: Adding label 'io.buildpacks.lifecycle.metadata'
remote: Adding label 'io.buildpacks.build.metadata'
remote: Adding label 'io.buildpacks.project.metadata'
remote: Setting default process type 'web'
remote: Saving salty-shelf-87055/builds...
remote: *** Images (sha256:e2bf21073c72abde7772d8d296ed27dcc318d49d34ebf1e732f4378ea5eb13db):
remote: salty-shelf-87055/builds:84e1233d-2779-4eff-8de4-36eb4067980c
remote: Adding cache layer 'heroku/nodejs-engine:dist'
remote: Adding cache layer 'heroku/nodejs-npm-install:npm_cache'
remote: Uploading cache
remote: Launching...
remote: http://salty-shelf-87055-5d3af90ffbb3.herokuapp.com/ deployed to Heroku
remote: Verifying deploy... done.
To https://git.heroku.com/salty-shelf-87055.git
* [new branch] main -> main
The app is now deployed. The default dyno size for Fir Private Spaces is 1X-Classic.
Visit the app at the URL shown in the logs. As a shortcut, you can also open the website as follows:
$ heroku open
Define a Procfile
Use a Procfile, a text file in the root directory of your application, to explicitly declare what command to execute to start your app.
The Procfile
in the example app looks like this:
web: npm start
This Procfile declares a single process type, web
, and the command needed to run it. The
name web
is important here. It declares that this process type is attached to
Heroku’s HTTP routing stack and receives web traffic when deployed. This command
uses the start
script specified in package.json
to run the application.
A Procfile can contain additional process types. For example, you can declare a background worker process that processes items off a queue.
Declare App Dependencies
Heroku recognizes an app as Node.js from a package.json
file in the root directory. For
your own apps, you can create one by running npm init --yes
.
The demo app you deployed already has a package.json
that looks like:
{
"name": "node-js-getting-started",
"version": "0.3.0",
...
"engines": {
"node": "22.x"
},
...
"dependencies": {
"ejs": "^3.1.9",
"express": "^4.15.2"
},
...
The package.json
file determines the version of Node.js to run your application on Heroku
and the dependencies to install with your application.
Run this command in your local directory to install the dependencies, preparing your system to run the app locally.
$ npm install
added 162 packages, and audited 163 packages in 1s
76 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
After installation, a package-lock.json
file is generated when npm install
is run. Make
sure to check this into Git. When subsequent dependencies are added, npm makes changes
to this file, so make sure to add those changes to Git too.
When an app is deployed, Heroku reads the package.json
to install the appropriate node
version and the package-lock.json
to install the dependencies.
Run the App Locally
Start your application locally using the heroku local
command, which installed as part
of the Heroku CLI.
$ heroku local web --port 5006
[OKAY] Loaded ENV .env File as KEY=VALUE Format
4:18:16 p.m. web.1 | > node-js-getting-started@0.3.0 start
4:18:16 p.m. web.1 | > node index.js
4:18:16 p.m. web.1 | Listening on 5006
Just like Heroku, heroku local
examines the Procfile to determine what to run.
Open http://localhost:5006 with your web browser to see your app running locally.
To stop the app from running locally, in the CLI, press Ctrl
+C
to exit.
Push Local Changes
In this step, you learn how to propagate a local change to the application through to Heroku. As an example, lets modify the application to add a dependency and the code to use it.
Begin by adding a dependency for cool-ascii-faces
in package.json
. Run this command.
$ npm install cool-ascii-faces
added 11 packages, and audited 174 packages in 2s
76 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
Modify index.js
so that it requires
this module at the start. Also add a new route (/cool
) that uses it. You want the final code to look like:
const express = require('express')
const path = require('path')
const cool = require('cool-ascii-faces')
const PORT = process.env.PORT || 5001
express()
.use(express.static(path.join(__dirname, 'public')))
.set('views', path.join(__dirname, 'views'))
.set('view engine', 'ejs')
.get('/', (req, res) => res.render('pages/index'))
.get('/cool', (req, res) => res.send(cool()))
.listen(PORT, () => console.log(`Listening on ${ PORT }`))
Test locally.
When you visit your application at http://localhost:5001/cool,
the sample application shows you cute faces on each refresh: ( ⚆ _ ⚆ )
.
Deploy. Almost every deploy to Heroku follows this same pattern. First, add the modified files to the local Git repository.
$ git add .
Commit the changes to the repository.
$ git commit -m "Add cool face API"
[main ea104fb] Add cool face API
3 files changed, 95 insertions(+)
Deploy, just as you did previously.
$ git push heroku main
remote: Updated 18 paths from f94b083
remote: Compressing source files... done.
remote: Building source:
remote: Extracting source
remote: Restoring cache
remote: Restoring data for SBOM from previous image
remote: 3 of 6 buildpacks participating
remote: heroku/nodejs-engine 3.3.3
remote: heroku/nodejs-npm-install 3.3.3
remote: heroku/procfile 3.1.2
remote: Restoring metadata for "heroku/nodejs-engine:node_runtime_metrics" from app image
remote: Restoring metadata for "heroku/nodejs-engine:web_env" from app image
remote: Restoring metadata for "heroku/nodejs-engine:dist" from app image
remote: Restoring metadata for "heroku/nodejs-npm-install:npm_runtime_config" from app image
remote: Restoring metadata for "heroku/nodejs-npm-install:npm_cache" from cache
remote: Restoring data for "heroku/nodejs-engine:dist" from cache
remote: Restoring data for "heroku/nodejs-npm-install:npm_cache" from cache
remote:
remote: [Heroku Node.js Engine Buildpack]
remote:
remote: [Checking Node.js version]
remote: Detected Node.js version range: >=22.0.0 <23.0.0-0
remote: Resolved Node.js version: 22.11.0
remote:
remote: [Installing Node.js distribution]
remote: Reusing Node.js 22.11.0 (linux-arm64)
remote: Installing application metrics scripts
remote: [1;35m
remote: [1;35m# Heroku Node.js npm Install Buildpack
remote:
remote: - Installing node modules
remote: - Using npm version `[0;33m10.9.0`
remote: - Restoring npm cache
remote: - Configuring npm cache directory
remote: - Running `[0;33m[1;36mnpm ci "--production=false"`
remote:
remote: npm warn config production Use `--omit=dev` instead.
remote:
remote: added 173 packages, and audited 174 packages in 2s
remote:
remote: 76 packages are looking for funding
remote: run `npm fund` for details
remote:
remote: found 0 vulnerabilities
remote:
remote: - Done (2.272s)
remote: - Running scripts
remote: - No build scripts found
remote: - Configuring default processes
remote: - Adding default web process for `[0;33mnpm start`
remote: - Done (finished in 2.518s)
remote:
remote: [Discovering process types]
remote: Procfile declares types -> web
remote: Reusing layers from image 'salty-shelf-87055/builds@sha256:e2bf21073c72abde7772d8d296ed27dcc318d49d34ebf1e732f4378ea5eb13db'
remote: Reusing layer 'heroku/nodejs-engine:dist'
remote: Reusing layer 'heroku/nodejs-engine:node_runtime_metrics'
remote: Reusing layer 'heroku/nodejs-engine:web_env'
remote: Reusing layer 'heroku/nodejs-npm-install:npm_runtime_config'
remote: Reusing layer 'buildpacksio/lifecycle:launch.sbom'
remote: Added 1/1 app layer(s)
remote: Reusing layer 'buildpacksio/lifecycle:launcher'
remote: Reusing layer 'buildpacksio/lifecycle:config'
remote: Reusing layer 'buildpacksio/lifecycle:process-types'
remote: Adding label 'io.buildpacks.lifecycle.metadata'
remote: Adding label 'io.buildpacks.build.metadata'
remote: Adding label 'io.buildpacks.project.metadata'
remote: Setting default process type 'web'
remote: Saving salty-shelf-87055/builds...
remote: *** Images (sha256:e6fd3b8b1e6ceacc2660a248c1af77b6fd748773a1a72f283936f55f299c9b19):
remote: salty-shelf-87055/builds:bd3c68bc-e063-474b-b626-b9e63ae5e520
remote: Reusing cache layer 'heroku/nodejs-engine:dist'
remote: Adding cache layer 'heroku/nodejs-engine:dist'
remote: Adding cache layer 'heroku/nodejs-npm-install:npm_cache'
remote: Uploading cache
remote: Launching...
remote: https://salty-shelf-87055-5d3af90ffbb3.herokuapp.com/ deployed to Heroku
remote: Verifying deploy... done.
To https://git.heroku.com/salty-shelf-87055.git
e9c4cd9..ea104fb main -> main
Check that everything works.
$ heroku open cool
If everything is in working order, you see another face.
Start a Console
The heroku run
command to launch an interactive one-off dyno is unavailable for Fir. As
an alternative, use heroku run: inside
to access a running dyno until we
add heroku run
for Fir.
You must add an SSH key to your Heroku account before running this command.
To execute the command you need the name of a currently running process. You can see a list
with heroku ps
:
$ heroku ps
=== web (1X-Classic): npm start (1)
web-5d478d89c8-zrz5f: up 2024/11/27 16:20:52 -0400 (~ 18s ago)
Use that dyno name to run the bash
command by prepending “launcher” to it to open up a
shell on that dyno. You can then execute commands there:
$ heroku run:inside web-5d478d89c8-zrz5f "launcher bash"
Running launcher bash on ⬢ salty-shelf-87055... up, web-5d478d89c8-zrz5f
heroku@web-5d478d89c8-zrz5f:/workspace$
If you receive an error, Error connecting to process
, configure your firewall.
You can use this to view the contents of the dyno’s disk:
~ $ ls
Procfile node_modules test.js
README.md package-lock.json views
app.json package.json
index.js public
~ $ exit
exit
Type exit
to exit the shell and terminate the dyno.
Define Config Vars
With Heroku, you can externalize configuration, storing data such as encryption keys or external resource addresses in config vars.
At runtime, config vars are exposed as environment variables to the application. For example,
lets modify index.js
to introduce a new route, /times
, that repeats an action depending on
the value of the TIMES
environment variable. Copy the following into index.js
:
const express = require('express')
const path = require('path')
const cool = require('cool-ascii-faces')
const PORT = process.env.PORT || 5001
function showTimes() {
const times = process.env.TIMES || 5
let result = ''
for (i = 0; i < times; i++) {
result += i + ' '
}
return result
}
express()
.use(express.static(path.join(__dirname, 'public')))
.set('views', path.join(__dirname, 'views'))
.set('view engine', 'ejs')
.get('/', (req, res) => res.render('pages/index'))
.get('/cool', (req, res) => res.send(cool()))
.get('/times', (req, res) => res.send(showTimes()))
.listen(PORT, () => console.log(`Listening on ${ PORT }`))
heroku local
automatically sets up the environment based on the contents of the .env
file
in your local directory. In the top-level directory of your project, the .env
file already
contains the following:
TIMES=2
If you run the app with heroku local --port 5006
and then open
http://localhost:5001/times, you see two numbers generated every time.
To set the config var on Heroku, execute this command.
$ heroku config:set TIMES=2
Setting TIMES and restarting salty-shelf-87055...
Setting TIMES and restarting salty-shelf-87055... done, v5
TIMES: 2
View the config vars that are set using heroku config
.
$ heroku config
=== salty-shelf-87055 Config Vars
TIMES: 2
Deploy your changed application to Heroku.
$ git add .
$ git commit -m "Add /times route"
[main 91f2d13] Add /times route
1 file changed, 10 insertions(+)
$ git push heroku main
remote: Updated 18 paths from d2169b7
remote: Compressing source files... done.
remote: Building source:
remote: Extracting source
remote: Restoring cache
remote: Restoring data for SBOM from previous image
remote: 3 of 6 buildpacks participating
remote: heroku/nodejs-engine 3.3.3
remote: heroku/nodejs-npm-install 3.3.3
remote: heroku/procfile 3.1.2
remote: Restoring metadata for "heroku/nodejs-engine:web_env" from app image
remote: Restoring metadata for "heroku/nodejs-engine:dist" from app image
remote: Restoring metadata for "heroku/nodejs-engine:node_runtime_metrics" from app image
remote: Restoring metadata for "heroku/nodejs-npm-install:npm_runtime_config" from app image
remote: Restoring metadata for "heroku/nodejs-npm-install:npm_cache" from cache
remote: Restoring data for "heroku/nodejs-engine:dist" from cache
remote: Restoring data for "heroku/nodejs-npm-install:npm_cache" from cache
remote:
remote: [Heroku Node.js Engine Buildpack]
remote:
remote: [Checking Node.js version]
remote: Detected Node.js version range: >=22.0.0 <23.0.0-0
remote: Resolved Node.js version: 22.11.0
remote:
remote: [Installing Node.js distribution]
remote: Reusing Node.js 22.11.0 (linux-arm64)
remote: Installing application metrics scripts
remote: [1;35m
remote: [1;35m# Heroku Node.js npm Install Buildpack
remote:
remote: - Installing node modules
remote: - Using npm version `[0;33m10.9.0`
remote: - Restoring npm cache
remote: - Configuring npm cache directory
remote: - Running `[0;33m[1;36mnpm ci "--production=false"`
remote:
remote: npm warn config production Use `--omit=dev` instead.
remote:
remote: added 173 packages, and audited 174 packages in 2s
remote:
remote: 76 packages are looking for funding
remote: run `npm fund` for details
remote:
remote: found 0 vulnerabilities
remote:
remote: - Done (2.147s)
remote: - Running scripts
remote: - No build scripts found
remote: - Configuring default processes
remote: - Adding default web process for `[0;33mnpm start`
remote: - Done (finished in 2.406s)
remote:
remote: [Discovering process types]
remote: Procfile declares types -> web
remote: Reusing layers from image 'salty-shelf-87055/builds@sha256:e6fd3b8b1e6ceacc2660a248c1af77b6fd748773a1a72f283936f55f299c9b19'
remote: Reusing layer 'heroku/nodejs-engine:dist'
remote: Reusing layer 'heroku/nodejs-engine:node_runtime_metrics'
remote: Reusing layer 'heroku/nodejs-engine:web_env'
remote: Reusing layer 'heroku/nodejs-npm-install:npm_runtime_config'
remote: Reusing layer 'buildpacksio/lifecycle:launch.sbom'
remote: Added 1/1 app layer(s)
remote: Reusing layer 'buildpacksio/lifecycle:launcher'
remote: Reusing layer 'buildpacksio/lifecycle:config'
remote: Reusing layer 'buildpacksio/lifecycle:process-types'
remote: Adding label 'io.buildpacks.lifecycle.metadata'
remote: Adding label 'io.buildpacks.build.metadata'
remote: Adding label 'io.buildpacks.project.metadata'
remote: Setting default process type 'web'
remote: Saving salty-shelf-87055/builds...
remote: *** Images (sha256:34e816a1d1f0fefcda5c608a528d9bc7a706b9b2e91b7c867f6dc88430e3f4df):
remote: salty-shelf-87055/builds:c0e13043-bc5d-4d60-bb1d-d794991e586d
remote: Reusing cache layer 'heroku/nodejs-engine:dist'
remote: Adding cache layer 'heroku/nodejs-engine:dist'
remote: Adding cache layer 'heroku/nodejs-npm-install:npm_cache'
remote: Uploading cache
remote: Launching...
remote: https://salty-shelf-87055-5d3af90ffbb3.herokuapp.com/ deployed to Heroku
remote: Verifying deploy... done.
To https://git.heroku.com/salty-shelf-87055.git
ea104fb..91f2d13 main -> main
Then visit it by running heroku open times
.
Provision a Database
The sample app requires a database. Provision a Heroku Postgres database, an add-on available through the Elements Marketplace. Add-ons are cloud services that provide out-of-the-box additional services for your application, such as logging, monitoring, databases, and more.
An essential-0
Postgres size costs $5 a month, prorated to the minute. At the end of this tutorial, we prompt you to delete your database to minimize costs.
$ heroku addons:create heroku-postgresql:essential-0
Creating heroku-postgresql:essential-0 on salty-shelf-87055...
Creating heroku-postgresql:essential-0 on salty-shelf-87055... ~$0.007/hour (max $5/month)
Database should be available soon
postgresql-dimensional-97702 is being created in the background. The app will restart when complete...
Use heroku addons:info postgresql-dimensional-97702 to check creation progress
Use heroku addons:docs heroku-postgresql to view documentation
You can wait for the database to provision by running this command:
$ heroku pg:wait
Waiting for database postgresql-dimensional-97702... Provisioning
Waiting for database postgresql-dimensional-97702... Available
After that command exits, your Heroku app can access the Postgres database. The DATABASE_URL
environment variable stores your credentials, which your app is configured to connect to. You can see all the add-ons provisioned with the addons
command:
$ heroku addons
Add-on Plan Price Max price State
──────────────────────────────────────────────── ─────────── ──────────── ───────── ───────
heroku-postgresql (postgresql-dimensional-97702) essential-0 ~$0.007/hour $5/month created
└─ as DATABASE
The table above shows add-ons and the attachments to the current app (salty-shelf-87055) or other apps.
Use npm
to add node-postgres to your dependencies.
$ npm install pg
added 13 packages, and audited 187 packages in 2s
76 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
Edit your index.js
file to use this module to connect to the database specified in
your DATABASE_URL
environment variable. On line 4 of index.js
, add:
const { Pool } = require('pg')
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
ssl: {
rejectUnauthorized: false
}
})
Then, to execute a query against the database, add a new /db
route that will return all
rows in the test_table
table. On line 31 of index.js
, add:
.get('/db', async (req, res) => {
try {
const client = await pool.connect();
const result = await client.query('SELECT * FROM test_table');
const results = { 'results': (result) ? result.rows : null};
res.render('pages/db', results );
client.release();
} catch (err) {
console.error(err);
res.send("Error " + err);
}
})
The index.js
file should now look like this:
const express = require('express')
const path = require('path')
const cool = require('cool-ascii-faces')
const { Pool } = require('pg')
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
ssl: {
rejectUnauthorized: false
}
})
const PORT = process.env.PORT || 5001
function showTimes() {
const times = process.env.TIMES || 5
let result = ''
for (i = 0; i < times; i++) {
result += i + ' '
}
return result
}
express()
.use(express.static(path.join(__dirname, 'public')))
.set('views', path.join(__dirname, 'views'))
.set('view engine', 'ejs')
.get('/', (req, res) => res.render('pages/index'))
.get('/cool', (req, res) => res.send(cool()))
.get('/times', (req, res) => res.send(showTimes()))
.get('/db', async (req, res) => {
try {
const client = await pool.connect();
const result = await client.query('SELECT * FROM test_table');
const results = { 'results': (result) ? result.rows : null};
res.render('pages/db', results );
client.release();
} catch (err) {
console.error(err);
res.send("Error " + err);
}
})
.listen(PORT, () => console.log(`Listening on ${ PORT }`))
Deploy your code to Heroku.
$ git add .
$ git commit -m "Add /times route"
[main 189c806] Add /times route
3 files changed, 161 insertions(+), 2 deletions(-)
$ git push heroku main
remote: Updated 18 paths from 510e320
remote: Compressing source files... done.
remote: Building source:
remote: Extracting source
remote: Restoring cache
remote: Restoring data for SBOM from previous image
remote: 3 of 6 buildpacks participating
remote: heroku/nodejs-engine 3.3.3
remote: heroku/nodejs-npm-install 3.3.3
remote: heroku/procfile 3.1.2
remote: Restoring metadata for "heroku/nodejs-engine:web_env" from app image
remote: Restoring metadata for "heroku/nodejs-engine:dist" from app image
remote: Restoring metadata for "heroku/nodejs-engine:node_runtime_metrics" from app image
remote: Restoring metadata for "heroku/nodejs-npm-install:npm_runtime_config" from app image
remote: Restoring metadata for "heroku/nodejs-npm-install:npm_cache" from cache
remote: Restoring data for "heroku/nodejs-engine:dist" from cache
remote: Restoring data for "heroku/nodejs-npm-install:npm_cache" from cache
remote:
remote: [Heroku Node.js Engine Buildpack]
remote:
remote: [Checking Node.js version]
remote: Detected Node.js version range: >=22.0.0 <23.0.0-0
remote: Resolved Node.js version: 22.11.0
remote:
remote: [Installing Node.js distribution]
remote: Reusing Node.js 22.11.0 (linux-arm64)
remote: Installing application metrics scripts
remote: [1;35m
remote: [1;35m# Heroku Node.js npm Install Buildpack
remote:
remote: - Installing node modules
remote: - Using npm version `[0;33m10.9.0`
remote: - Restoring npm cache
remote: - Configuring npm cache directory
remote: - Running `[0;33m[1;36mnpm ci "--production=false"`
remote:
remote: npm warn config production Use `--omit=dev` instead.
remote:
remote: added 186 packages, and audited 187 packages in 2s
remote:
remote: 76 packages are looking for funding
remote: run `npm fund` for details
remote:
remote: found 0 vulnerabilities
remote:
remote: - Done (2.365s)
remote: - Running scripts
remote: - No build scripts found
remote: - Configuring default processes
remote: - Adding default web process for `[0;33mnpm start`
remote: - Done (finished in 2.613s)
remote:
remote: [Discovering process types]
remote: Procfile declares types -> web
remote: Reusing layers from image 'salty-shelf-87055/builds@sha256:34e816a1d1f0fefcda5c608a528d9bc7a706b9b2e91b7c867f6dc88430e3f4df'
remote: Reusing layer 'heroku/nodejs-engine:dist'
remote: Reusing layer 'heroku/nodejs-engine:node_runtime_metrics'
remote: Reusing layer 'heroku/nodejs-engine:web_env'
remote: Reusing layer 'heroku/nodejs-npm-install:npm_runtime_config'
remote: Reusing layer 'buildpacksio/lifecycle:launch.sbom'
remote: Added 1/1 app layer(s)
remote: Reusing layer 'buildpacksio/lifecycle:launcher'
remote: Reusing layer 'buildpacksio/lifecycle:config'
remote: Reusing layer 'buildpacksio/lifecycle:process-types'
remote: Adding label 'io.buildpacks.lifecycle.metadata'
remote: Adding label 'io.buildpacks.build.metadata'
remote: Adding label 'io.buildpacks.project.metadata'
remote: Setting default process type 'web'
remote: Saving salty-shelf-87055/builds...
remote: *** Images (sha256:1d7891f6fb5baf4c27d2e8712b43d5c9feae815c917d4a3b67c9def58aaa7531):
remote: salty-shelf-87055/builds:5709f3b9-b93d-4845-a617-0e63390b3f0e
remote: Reusing cache layer 'heroku/nodejs-engine:dist'
remote: Adding cache layer 'heroku/nodejs-engine:dist'
remote: Adding cache layer 'heroku/nodejs-npm-install:npm_cache'
remote: Uploading cache
remote: Launching...
remote: https://salty-shelf-87055-5d3af90ffbb3.herokuapp.com/ deployed to Heroku
remote: Verifying deploy... done.
To https://git.heroku.com/salty-shelf-87055.git
91f2d13..189c806 main -> main
If you access /db
, you receive an error because there’s no
table in the database. Assuming that you have Postgres installed locally,
use the heroku pg:psql
command to connect to the remote database, create a table, and insert a row.
--> Connecting to postgresql-dimensional-97702
psql (14.13 (Homebrew), server 16.3)
WARNING: psql major version 14, server major version 16.
Some psql features might not work.
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compression: off)
Type "help" for help.
salty-shelf-87055::DATABASE=> create table test_table (id integer, name text);
CREATE TABLE
salty-shelf-87055::DATABASE=> insert into test_table values (1, 'hello database');
INSERT 0 1
salty-shelf-87055::DATABASE=> \q
Now when you access your app’s /db
route with heroku open db
, you see something like:
Read more about Heroku PostgreSQL.
You can use a similar technique to install MongoDB or Redis add-ons.
Delete Your App and Add-on
Remove the app and database from your account. We only charge you for the resources you used.
This action permanently deletes your application
$ heroku apps:destroy
You can confirm that your add-ons and app are gone with these commands:
$ heroku addons --all
$ heroku apps --all
Next Steps
Now you know how to deploy an app, change its configuration, view logs, scale, and attach add-ons. For more information, here’s some recommended reading.
- For a technical overview of the concepts that you encounter while writing, configuring, deploying, and running applications, read How Heroku Works.
- To learn more about developing and deploying Node.js applications, visit the Node.js category.
- To understand how to take an existing Node.js app and deploy it to Heroku, read Deploying Node.js Apps on Heroku.