We recently introduced support for Dockerfile to specify the build step of your static deployments, in addition to our existing Docker support for serverless APIs.
This enables you to to deploy with one now command or one git push, preserving the security, reproducibility, and reliability of Docker containers — without any of the hassle.
Today we are glad to announce support for build-time environment variables. This enables you to expose any secrets or constants (like NODE_ENV=production) to your build process.
Build env works exactly like run-time env, but inside the build namespace. Here's an example now.json file:
{
  "build": {
    "env": {
      "NPM_TOKEN": "@npm-token",
      "NODE_ENV": "production"
    }
  }
}
In this case I'm exposing two env variables:
  • NPM_TOKEN which references the contents of a secret npm-token
  • NODE_ENV as a constant string for configuration
That's all it takes! Your Dockerfile can then use the ARG keyword and embed the supplied env variables.
We have upgraded now-cli to add support for the --build-env parameter:
now \
  --build-env NODE_ENV=production \
  --build-env NPM_TOKEN=@npm-token
This option works exactly like how -e / --env work for run-time environment.
In the example above, we used NPM_TOKEN for a good reason: many teams around the world make use of private npm modules, which require a custom token.
How does it work? First, we need to populate the npm-token secret in your account or team context. We recommend you generate a readonly npm token specifically for this purpose:
npm token create --read-only
Once you have the value, create a npm-token secret from it (which we referenced by using the @ special character in our config):
now secret add npm-token MY_TOKEN_HERE
At this point, you can freely use it inside Dockerfile:
FROM mhart/alpine-node:10 as base
ARG NPM_TOKEN
RUN echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" > ~/.npmrc
WORKDIR /usr/src
COPY package.json yarn.lock /usr/src/
RUN yarn
COPY . .
RUN yarn run build && yarn --production

FROM mhart/alpine-node:base-10
WORKDIR /usr/src
ENV NODE_ENV="production"
COPY --from=base /usr/src .
EXPOSE 3000
CMD ["node", "start.js"]
This Dockerfile:
  • Makes use of Node.js 10 as a base image
  • Makes use of multi-stage builds to make the resulting image as lean as possible (by excluding yarn and npm from the run-time image, and therefore tightening security)
  • Is able to install packages from private npm
  • Is optimized for only re-installing dependencies if package.json or yarn.lock change
  • Uses yarn, but npm would also work.
If so desired, one could substitute yarn.lock for package-lock.json, and then execute npm install in place of yarn. Another option is to use the newly introduced npm ci.
This power and flexibility at build-time is why we think Dockerfile is the perfect solution for your cloud builds.
We packaged the example above as a starter repository for a static deployment and one for a microservice. To make use of them, just follow the instructions on the README.
The techniques described above are applicable for any programming language or stack. You can expose any number of build env variables you require.
All the special Now env variables are automatically exposed to the build step, such as NOW_URL and NOW_DC.
Some other ideas for how you can use build env include:
  • Generating configuration files automatically
  • Exposing information about what deployment is running in HTML comments of static deployments for debugging
  • Dynamically generating content at build-time that gets pre-rendered statically
Customizing the build environment is an essential feature for sophisticated build processes, especially those that require special access and permissions to download dependencies or data.
We are very happy about how standardizing around Dockerfile brings a broad range of benefits in terms of security and performance, but in particular we are excited about it opening up our platform to an even broader community of developers.