Skip to content

Getting Started with Node Express

A live example is available at https://express.nullstone.dev.

This quickstart launches a Node Express web application to AWS via Nullstone. It also configures a local development environment using Docker that works identical to production, but with debugging enabled.

This quickstart contains a walkthrough for creating an Express app. A working example is available to fork at nullstone-io/node-express-quickstart.

TIP

This quickstart is based off the official Express Hello World example.

Create Express app

Initialize app

We need a package.json file to keep track of our Express app and its dependencies. Run this command to start (answering prompts that appear).

shell
yarn init
yarn init

Add express

This quickstart requires the express node module to run. Let's add this using yarn add.

shell
yarn add express
yarn add express

Add Hello World

We are using the default app.js file to start our app. Let's build this file now with an express server to handle basic requests to the root.

js
const express = require('express')
const app = express()
const port = process.env.PORT || 9000

app.get('/', (req, res) => {
    res.send('Hello World!')
})

app.listen(port, () => {
    console.log(`Example app listening on port ${port}`)
})
const express = require('express')
const app = express()
const port = process.env.PORT || 9000

app.get('/', (req, res) => {
    res.send('Hello World!')
})

app.listen(port, () => {
    console.log(`Example app listening on port ${port}`)
})

Prepare for Local

Configure docker locally

TIP

Nullstone provides a docker image nullstone/node:local that is configured for local development. The source for the docker image is on GitHub at nullstone-io/docker-node.

Create a docker-compose.yml to run locally using Docker.

yaml
version: '3.8'

services:
   app:
      image: nullstone/node:local
      ports:
         - "9000:9000"
      volumes:
         - .:/app
         - node_modules:/app/node_modules
      environment:
         - NODE_ENV=development

volumes:
   node_modules: {}
version: '3.8'

services:
   app:
      image: nullstone/node:local
      ports:
         - "9000:9000"
      volumes:
         - .:/app
         - node_modules:/app/node_modules
      environment:
         - NODE_ENV=development

volumes:
   node_modules: {}

Add a .dockerignore with the following:

docker
node_modules/
node_modules/

Let's start our app locally.

shell
docker compose up
docker compose up

Visit http://localhost:9000.

Update dependencies

As you add dependencies to your application, ensure that there is an entry for the dependency in package.json. Then, restart your docker container with docker compose up or docker compose restart. The local docker image will install dependencies on boot.

Prepare for Production

Before deploying an Express app to production, we need to dockerize the app. In this section, we will create a Dockerfile from a base docker image that is optimized for production.

Create Dockerfile

In your project root, create Dockerfile using the nullstone/node base image.

docker
FROM nullstone/node

COPY package.json .
RUN yarn install
COPY . .
FROM nullstone/node

COPY package.json .
RUN yarn install
COPY . .

Launch to Nullstone

Create app

When launching to Nullstone, we're going to create an app in the Nullstone UI and attach capabilities that automatically configure our app. Follow these steps in the Nullstone UI.

  1. Create an application.
    • Name: In this example, we're naming our app express-quickstart
    • Framework: node
    • App Type: Container
  2. From the Domains tab for the application, add a subdomain. (This will automatically attach a load balancer capability)

Provision

Our application is ready to launch. Click "Launch" through the UI or issue up through the CLI.

shell
nullstone up --wait --app=express-quickstart --env=dev
nullstone up --wait --app=express-quickstart --env=dev

Build

Once your application is provisioned, you may build and deploy your app.

You can name your image whatever you want, just remember this image name for the deploy step. In this example, we are using an image name of express-app.

shell
docker build -t express-app .
docker build -t express-app .

Deploy

Now, issue launch to push your docker image and deploy the service with a new version.

shell
nullstone launch --source=express-app --app=express-quickstart --env=dev
nullstone launch --source=express-app --app=express-quickstart --env=dev

Troubleshooting

Auto-versioning

When pushing your image, Nullstone performs auto-versioning if you are in a git-tracked directory. Nullstone selects the short commit SHA (a unique 8-character token) from the git repository to tag the docker image.

To use a manual version, issue launch with --version (this example uses 1.0.0).

shell
nullstone launch --source=express-app --app=express-quickstart --env=dev --version=1.0.0
nullstone launch --source=express-app --app=express-quickstart --env=dev --version=1.0.0

Version conflicts

Nullstone enforces version/image tag immutability for security reasons.

If you repeatedly push a new docker image without committing anything to git, you will receive an error message like this:

shell
error pushing artifact: error pushing image: tag invalid: The image tag 'c3c7cd83' already exists in the 'periwinkle-louse-fkslv' repository and cannot be overwritten because the repository is immutable.
error pushing artifact: error pushing image: tag invalid: The image tag 'c3c7cd83' already exists in the 'periwinkle-louse-fkslv' repository and cannot be overwritten because the repository is immutable.

The easiest way to resolve this is to launch with an indexed version. The following uses the same commit sha, but with a -2 suffix to distinguish the image tag.

shell
nullstone launch --source=express-app --app=express-quickstart --env=dev --version=c3c7cd83-2
nullstone launch --source=express-app --app=express-quickstart --env=dev --version=c3c7cd83-2