Skip to content
Home » Blogs » How I Deployed Node.js/Express App to Vercel (Painfully)

How I Deployed Node.js/Express App to Vercel (Painfully)

Stressed man sitting on couch, feeling overwhelmed and frustrated, expressing mental strain.

Below is how much tries I had to perform until I finally deployed Recite, my Node.js/Express app on Vercel successfully.

Let’s see what all steps I performed. 

You can deploy mostly, any Node.js/Express app on Vercel with this method.

Pre-requisites

Node.js/Express app, a GitHub repository, and a Vercel account.

Initial State of the App

This is the initial project file structure of my Express app.

And the index.js file:

const express = require("express");
const dotenv = require("dotenv");
const quoteRoute = require("./routes/QuoteRoute");
const cors = require("cors");
const connectDb = require("./utils/connectDb");
const errorHandler = require("./middlewares/errorHandler");
const notFound = require("./middlewares/notFound");
const apiRequestLimiter = require("./middlewares/rateLimit");

const app = express();
dotenv.config();

connectDb();

app.use(express.json());

app.use(cors({ origin: "*" }));

app.use(apiRequestLimiter);
app.use("/api/v1", quoteRoute);

app.use(notFound);
app.use(errorHandler);

const port = process.env.PORT;

app.listen(port, () => {
console.log(`listening on http://localhost:${port} `);
});

Every route of my app is through “/api/v1”.

Steps to Deploy to Vercel 

1. Export “index.js” app as a handler

On Vercel, we can’t “listen” like in a normal express server.

app.listen(port, () => {
console.log(`listening on http://localhost:${port} `);
});

We need to export the app as a handler.

module.exports = app;

Final index.js code looks like this:

const express = require("express");
const dotenv = require("dotenv");
const quoteRoute = require("../routes/QuoteRoute");
const cors = require("cors");
const connectDb = require("../utils/connectDb");
const errorHandler = require("../middlewares/errorHandler");
const notFound = require("../middlewares/notFound");
const apiRequestLimiter = require("../middlewares/rateLimit");

const app = express();
dotenv.config();

connectDb();

app.use(express.json());

app.use(cors({ origin: "*" }));

app.use(apiRequestLimiter);
app.use("/api/v1", quoteRoute);

app.use(notFound);
app.use(errorHandler);

const port = process.env.PORT;

module.exports = app;

2. Create “Vercel.json” file in the root directory

And copy paste the code below:

{
"version": 2,
"builds": [
{
"src": "index.js",
"use": "@vercel/node"
}
],
"routes": [
{
"src": "/(.*)",
"dest": "index.js"
}
]
}

This vercel.json file tells us if we want to use a custom build for our app.

Breakdown

1. Specifying the version of our app:

"version": 2

2. Telling Vercel to build index.js as a Node.js serverless function using Vercel’s Node runtime.

"builds": [
{
"src": "index.js",
"use": "@vercel/node"
}
]

3. The below code tells Vercel that any request that comes to “/” endpoint, should be handled by the Express app at index.js.

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

But right now, there’s a mistake in our project.

If we don’t create an “api” folder on the root directory, and don’t paste the index.js file there, Vercel wouldn’t treat it as a serverless function and none of the routes in our app will work.

So we need to make 2 changes:

1. Locate index.js inside the “api” folder in root directory:

2. Update vercel.json to reflect the new “api” folder change:

{
"version": 2,
"builds": [
{
"src": "api/index.js",
"use": "@vercel/node"
}
],
"routes": [
{
"src": "/(.*)",
"dest": "api/index.js"
}
]
}

3. Deploy the app to Vercel

You must have a GitHub repo for this.

Login to vercel.com and import the GitHub repo, then simply deploy it. You will see the below status.

And if we go to the URL, we will see the below page.

Why 404?

Because of notFound handler that we have in our code on index.js file.

app.use(notFound);

Because if you see the index.js file, we don’t have any route for the home endpoint (“/”), so the Express app points us to the notFound handler, which has this code:

const notFound = (req, res, next) => {
const error = new Error("Resource not found");
error.status = 404;
return next(error);
};

module.exports = notFound;

Fix

On index.js file, I can simply create a new route for the home endpoint.

app.get("/", (req, res) => {
res.json({ success: true, message: "Recite - Quotes API is running..." });
});

Now if you hit this URL: https://recite-flax.vercel.app/api/v1/random

You will see that the app is working!

The above endpoint sends a random quote as a response

You can use this Recite REST API in your application to get any random quote!

Errors:

1. Misconfiguration in your ‘vercel.json’ file

Sometimes, you may get this error on your Vercel log:

Because most likely, vercel.json would have some incorrect configuration.

{
"version": 2,
"builds": [
{
"src": "index.js",
"use": "vercel/node"
}
],
"routes": [
{
"src": "/(.*)",
"dest": "index.js"
}
]
}

We need to include “@” on the use property’s value:

{
"version": 2,
"builds": [
{
"src": "index.js",
"use": "@vercel/node"
}
],
"routes": [
{
"src": "/(.*)",
"dest": "index.js"
}
]
}

Verdict

Hope you learnt how to deploy a Node.js/Express app to Vercel using the above steps.

Thankfully, Vercel’s serverless concept is quite faster than Render’s free tier.

According to ChatGPT

Hence, I moved my REST API to Vercel. 

I am also using this API on Vocabsaga, a vocabulary learning platform where you can learn new words through passages and sentences, not random single words.


Contact me on X (Twitter) or LinkedIn for any queries.

Tags:

Leave a Reply

Your email address will not be published. Required fields are marked *