If you've been around the web in the last few months, you probably heard about serverless applications, which pretty much run completely off the cloud, without any sort of manual server configuration, which also ends up bringing some great scalability options. Today we're going to set-up Adonis, a Node.js web application framework, to run as an API right off the Now.sh platform.

As all of this is mostly recent stuff, it's highly subject to change, but if you dare to adventure yourself on cool new tech and also learn the steps to port your application, keep scrolling and let's have some fun!

First of all, if you plan on deploying serverless, please consider doing it the right way, as lambdas or separate functions. Only follow this route if you really need all the framework goodness, since your application may have a slower boot time, consume more memory and possibly end up with higher costs down the line. You have been warned.

Setting up Adonis

First, let's get our Adonis set up. Install the CLI utility by running the following commnand:

npm i -g @adonisjs/cli

To keep things simple, we'll be only working with the API blueprint. Up to this point I haven't tested how complex it would be to setup a fullstack Adonis installation, but it shouldn't be that hard anyways. Just run the following command to create our project:

adonis new serverless-adonis --api-only

A very simple and minimal install will be created for you. You can check if everything is running fine by running adonis serve --dev

Customize whatever you want on the API, create your endpoints, etc.

Setting up Now.sh

With Adonis working fine, it's our time to get our Now set up. Install it by following the official documentation here and make sure you are logged in. A simple npm i -g now should do fine, but in any doubt check the official docs.

We will need to create a file to contain all our serverless configuration. On Now.sh this file is called now.json.

For now, let's use the following contents on the file:

{
    "version": 2,
    "name": "serverless-adonis"
}

This is the simplest configuration for Now.sh, just the application name and version. We're gonna expand on that.

Getting the Builds right

For applications that rely directly on Node.js server features, and not on Now ones (for example, Express, Koa, Adonis, etc) we need to specify a different builder type, called node-server. To do this, add the following code to your now.json file:

"builds": [{
  "src": "/server.js",
  "use": "@now/node-server",
  "config": {
    "includeFiles": ["**"],
    "maxLambdaSize": "50mb"
  }
}]

This code will instruct Now to use our server.js file, which the Adonis framework entry point, to be built using node-server and use it's generated server output.

In the configs, there's also an includeFiles configured to include all files from Adonis. This guarantees us that any file dynamically loaded by the framework is loaded as an asset by the builder and is available at runtime. Finally, the maxLambdaSize key defines an upper limit of 50MB for our built file. I don't think it's possible to hit this so easily (the "base" Adonis deployment up to here is around 12-13MB, so there's still lots of room for new code, right?), but if you somehow do, then you will need to break your application into smaller parts, possibly refactoring it to work natively with lambdas.

To test your if everything is working, run now on your CLI. The build process will start and when finished, you will receive a link to your deployment.

Setting up the Routes

If you try to access your deployment, you will notice that you get an "Index of" page from it, instead of your API. To fix this, we need to setup our routes on the now.json file:

"routes": [{
  "src": "/(.*)",
  "dest": "/server.js"
}]

What this is doing is telling Now to map all requests to our server.js build file. This is not the routing used by Adonis itself, so you don't need to map any routes here, since they will already be mapped. Just code them inside Adonis (located at start/routes.js and be happy.

Build the app again by running the now command and access the new deployment. If everything went fine you should have your API responding to requests now.

Getting it to work with Git

If you're using Git to version your work, then you probably will have issues when deploying automatically, since the .env file will not be found. Since this is a file that should only contain variables for the current environment, we're gonna create a separated file exclusively for Now, so it can build successfully. Let's call it now.env.

Make any adjustments you find necessary to it and remember: these are the information being used in production and will be available on your repository, so try not to include any sensitive information. You can include any environment variables alter by running the command now -e MY_COOL_VAR=my_sensitive_value.

It should be looking like this right now:

HOST=127.0.0.1
PORT=3333
NODE_ENV=production
APP_NAME=AdonisJs
APP_URL=http://${HOST}:${PORT}
CACHE_VIEWS=false
now.env

Finally, we need to tell Adonis to use our new now.env file instead of .env, to do this, we go back into the now.json and add the following lines:

"env": {
  "ENV_PATH": "now.env"
}

This will set an environment variable on Now telling Adonis to use our new file instead of it's default file.

Finally, copy the APP_KEY from the .env file or the run adonis key:generate to generate a new one and set it on Now by running now -e APP_KEY=your-key-here. Repeat this for any other sensitive information, token or configuration. You can also use environment secrets to keep sensitive information while not needing to touch the now.json file so often.

If you run the now command or push it to Git, things should now be working fine.

Installing via Blueprints

You can download the configured Adonis blueprint on GitHub or install it with the following command adonis new --blueprint=MatheusMK3/serverless-adonis, which leaves you with most steps of this guide done (except for the Now installation and configuration). You can finish installing it by simply running adonis deployment:prepare to generate all the required stuff for Now.sh, including setting up environment variables/secrets and other stuff.

I hope you have enjoyed this guide, it's my first English post here in the blog and part of a new english section I'm working on (if you're an early bird you might notice lots of things are still in portuguese 😛). Feel free to leave and doubts, questions or feedback in the comments, they will be very welcome!