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:

const { parse } = require('url')

module.exports = (req, res) => {
  const { query } = parse(req.url, true)
  const { name = 'World' } = query
  res.end(`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.

Deploying with Static Content

You can upload static content along side 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, 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, look into @now/node-server, although that is not recommended.

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

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.

With many Node.js-based frameworks like Express also frequently dealing with these HTTP request and response objects, you may be able to use them in your Node.js lambda.

The following lambda example, using Express, accepts a JSON body in the POST request, and returns a stringified version of it:

'use strict'

const express = require('express')
const bodyParser = require('body-parser')
const app = express()

module.exports = app

app.use(bodyParser.json())

app.post('*', (req, res) => {
  if (req.body == null) {
    return res.status(400).send({ error: 'no JSON object in the request' })
  }
  res.set('Content-Type', 'application/json')
  res.status(200).send(JSON.stringify(req.body, null, 4))
})

app.all('*', (req, res) => {
  res.status(405).send({ error: 'only POST requests are accepted' })
})

Example Node.js lambda using express and body-parser

For more information on handling request bodies with Express, see the following examples: Express and Twitter Dreamify with Express.

Handling request bodies in Node.js functions is also possible when not using a framework.

Node.js request bodies arrive in the format of a ReadableStream and must be listened to in order to extract the data.

The code to do this, as taken from the official Node.js documentation, has been put into an example below:

module.exports = async (req, res) => {
  let body = []
  await req
    .on('data', chunk => {
      body.push(chunk)
    })
    .on('end', () => {
      body = Buffer.concat(body).toString()
      const json = JSON.parse(body)
      res.end(`Hello ${json.name}, you just parsed the request body!`)
    })
}

An example asynchronous Node.js function using the ReadableStream object to retrieve the request body contents.

Using this code might seem a little tedious. As a result, we recommend the use of a third-party library such as micro to parse the request body like so:

const { json } = require('micro')

module.exports = async (req, res) => {
  const body = await json(req)
  res.end(`Hello ${body.name}, you just parsed the request body!`)
}

An example asynchronous Node.js function using micro to get the request body contents.

For more information on handling request bodies in Node.js, you can read this short guide to understand how it works in greater detail.

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.

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.end(`
    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 Node.js version used is the v8.10.

Maximum Lambda Bundle Size

To help keep cold boot times low, the maximum output bundle size for a Node.js output lambda is, by default, 5mb. This limit is extendable up to 50mb.

Example maxLambdaSize configuration:
{
  "builds": [
    { "src": "*.js", "use": "@now/node", "config": { "maxLambdaSize": "10mb" } }
  ]
}