Status: Stable

The @now/node Builder takes an entrypoint of a Node.js function, builds its dependencies (if any) and bundles them into a Lambda.

When to Use It

This Builder is the recommended way to introduce any Node.js-based dynamic request handling into your codebases.

It can be used directly (as a single file, like my-function.js), or you can define an index.js file inside a directory.

How to Use It

For this example, we will create a hello endpoint that we want to access as my-deployment.url/api/hello.

Let's create our project structure:

mkdir -p my-node-project/api/hellocd my-node-project/api/hello

Inside my-node-project > api > hello we will create an index.js file.

The index.js file exports a Node.js function that takes in the standard Node.js request and response objects:

module.exports = (req, res) => {
  const { name = 'World' } = req.query
  res.send(`Hello ${name}!`)
}

An example serverless Node.js function.

Note: The @now/node Builder also supports asynchronous functions, an example of which can be found in the Request and Response Objects section.

The only step left is to define a build that will take this directory's entrypoint (index.js), build it and turn it into a lambda:

{
  "version": 2,
  "builds": [{ "src": "api/hello/index.js", "use": "@now/node" }]
}

An example now.json configuration using the @now/node builder.

Our resulting deployment is here: https://my-node-project-5gkn6kqfy.now.sh/

The example deployment above is open-source and you can view the code for it here: https://my-node-project-5gkn6kqfy.now.sh/_src

You can pass query parameters to make the name change:

The lambda using the name query parameter to change the text using Node.js.

How to Use TypeScript

For this example, we will create a hello endpoint that we want to access as my-deployment.url/api/hello.

Let's create a new project directory:

mkdir my-ts-project && cd my-ts-project

Install the development dependencies:

yarn add --dev typescript @types/node @now/node

OR

npm install --save-dev typescript @types/node @now/node

Inside my-ts-project > api > hello create an index.ts file.

The index.ts file exports a default Node.js function that takes in the standard Node.js request and response objects:

import { NowRequest, NowResponse } from '@now/node'

export default function(req: NowRequest, res: NowResponse) {
  const { name = 'World' } = req.query
  res.send(`Hello ${name}!`)
}

An example serverless Node.js function written in TypeScript.

Let's configure the compiler by creating a tsconfig.json file in the root:

{
  "compilerOptions": {
    "module": "commonjs",
    "target": "esnext",
    "sourceMap": true,
    "strict": true
  }
}

An example tsconfig.json configuration using the recommended defaults for Node.js.

Define a build that will take this file (index.ts), build it, and turn it into a lambda:

{
  "version": 2,
  "builds": [{ "src": "api/hello/index.ts", "use": "@now/node" }]
}

An example now.json configuration using the @now/node builder.

Our resulting deployment is here: https://my-ts-project-gdgfrt3u2.now.sh/

The example deployment above is open-source and you can view the code for it here: https://my-ts-project-gdgfrt3u2.now.sh/_src

You can pass query parameters to make the name change:

The lambda using the name query parameter to change the text using Node.js.

TypeScript Compiler Options

Most compiler options are supported by defining a tsconfig.json in the same directory as package.json.

The following options are not supported:

Request and Response Objects

For each invocation of a Node.js lambda, two objects, request and response, are passed to the function. These objects are the standard HTTP request and response objects given and used by Node.js.

Helpers

In addition to the standard Node.js request and response methods, we provide a set of helper properties and methods to make it even easier for you to build a new lambda function:

method
description
object
req.query
An object containing the request's query string, or {} if the request does not have a query string.
request
req.cookies
An object containing the cookies sent by the request, or {} if the request contains no cookies.
request
req.body
An object containing the body sent by the request, or null if no body is sent.
request
res.status(code)
A function to set the status code sent with the response where code must be a valid HTTP status code. Returns res for chaining.
response
res.send(body)
A function to set the content of the response where body can be a string, an object or a Buffer.
response
res.json(obj)
A function to send a JSON response where obj is the JSON object to send.
response

The following lambda example showcases the use of req.query, req.cookies and req.body helpers:

module.exports = (req, res) => {
  let who = 'anonymous'

  if (req.body && req.body.who) {
    who = req.body.who
  } else if (req.query.who) {
    who = req.query.who
  } else if (req.cookies.who) {
    who = req.cookies.who
  }

  res.status(200).send(`hi ${who}, what's up?`)
}

Example Node.js lambda using the req.query, req.cookies and req.body helpers. It returns greetings for the user specified using req.send().

Note: You can opt-out of this behavior by setting helpers to false in the configuration of the builder. If you opt-out, request objects will be replaced by the standard HTTP request and response.
{
  "builds": [
    { "src": "my-file.js", "use": "@now/node", "config": { "helpers": "false" } }
  ]
}

You can opt-out of helpers by setting helpers to false in the configuration.

req.body

We populate the req.body property on the request object with a parsed version of the content sent with the request when it is possible.

We follow a set of rules on the Content-type header sent by the request to do so:

Content-Type header
Value of req.body
No header
undefined
application/json
An object representing the parsed JSON sent by the request.
application/x-www-form-urlencoded
An object representing the parsed data sent by with the request.
text/plain
A string containing the text sent by the request.
application/octet-stream
A Buffer containing the data sent by the request.

With the req.body helper, you can build applications without extra dependencies or having to parse the content of the request manually. The following example inspects req.body, if it is 'ping', it will return 'pong'.

module.exports = (req, res) => {
  if (typeof req.body !== 'string') {
    return res.status(400).text('Invalid request')
  }

  if (req.body !== 'ping') {
    return res.status(400).text('The value expected is `ping`')
  }

  res.status(200).send('pong')
}

An example Node.js lambda using the req.body helper that returns pong when you send ping.

Helpers Type Definitions

We provide types for the request and response objects.

To install these types, use the following command:

yarn add @now/node --dev

Or, if you're using npm:

npm install @now/node --save-dev

Once the types have been installed, import NowRequest and NowResponse from @now/node, to type the request and response objects:

import { NowRequest, NowResponse } from '@now/node'

export default function(req: NowRequest, res: NowResponse) {
  const { name = 'World' } = req.query
  res.send(`Hello ${name}!`)
}

An example "Hello World" Typescript lambda using the req.query helper.

Async support

We support asynchronous functions out-of-the-box.

In this example, we use the package asciify-image to create ascii art from a person's avatar on github. First, we need to install the package:

yarn add asciify-image

In our code, we export an asynchronous function and we take advantage of the helpers.

const asciify = require('asciify-image')

module.exports = async (req, res) => {
  if (!req.query.username) {
    return res.status(400).send('username is missing from query parameters')
  }

  const avatarUrl = `https://github.com/${req.query.username}.png`

  const opts = { fit: 'box', width: 40, height: 40 }
  const asciified = await asciify(avatarUrl, opts)

  return res.status(200).send(asciified)
}

An example showcasing the use of an asynchronous function.

Deploying with Static Content

You can upload static content alongside your Node.js application by using the @now/static Builder.

For example, if you have a /static directory and an index.js like the one from the example above, you can serve that directory statically by extending your now.json configuration:

{
  "version": 2,
  "builds": [
    { "src": "api/hello/index.js", "use": "@now/node" },
    { "src": "static/**", "use": "@now/static" }
  ]
}

Deploying a serverless Node.js function along with static files.

For more information on including static files in your project, read the documentation for @now/static:

Technical Details

Entrypoint

The entrypoint of this Builder is always a JavaScript file that exposes a function. If you want to expose a server, you should read the documentation for the @now/node-server Builder, although this is not recommended.

Note: @now/node will automatically detect a `package.json` file to install dependencies at the entrypoint level or higher.

Dependencies Installation

The installation algorithm of dependencies works as follows:

  • If a package-lock.json is present, npm install is used
  • Otherwise, yarn is used.

Private npm modules

To install private npm modules, define NPM_TOKEN as a build environment variable in now.json.

Alternatively, define NPM_RC as a build environment variable with the contents of ~/.npmrc.

Build Step

You can run build tasks by creating a now-build script within a package.json file at the entrypoint's level or higher.

An example package.json with a now-build script:
{
  "scripts": {
    "now-build": "node ./build.js"
  }
}
An example build script, named build.js:
const fs = require('fs');
  fs.writeFile(
  'built-time.js',
  `module.exports = "${new Date()}"`,
  (err) => {
    if (err) throw err
    console.log('Build time file created successfully!')
  }
)
An example entrypoint file for the built lambda, index.js:
const BuiltTime = require('./built-time')

module.exports = (req, res) => {
  res.setHeader('content-type', 'text/plain');
  res.send(`
    This Lambda was built at ${new Date(BuiltTime)}.
    The current time is ${new Date()}
  `)
}
To tie it all together, a now.json file:
{
  "version": 2,
  "builds": [
    { "src": "index.js", "use": "@now/node" }
  ]
}

The resulting lambda contains both the build and current time: https://build-time-pq6g1255e.now.sh/

Node.js Version

The default Node.js version used is 8.10.x.

The version can be changed to 10.x by defining engines in package.json:

{
  "name": "my-app",
  "engines": {
    "node": "10.x"
  }
}