How to Deploy an Express.js Application to Vercel
Express.js is a popular framework used with Node.js. In this guide, we will cover each step in-depth to deploy an Express.js application to Vercel using Serverless Functions. First, let’s understand what we are trying to achieve when deploying Express.js apps to Vercel.
Vercel is a cloud platform to deploy frontend applications. It’s designed for the frontend experience; build Hybrid frontends with tools like Next.js, develop lightweight event-driven APIs, and deploy to our Global Edge Network.
Express.js is a minimal and flexible Node.js web framework. It’s a popular choice among developers due to its flexibility, adoption, and trusted ecosystem. Using Express.js implies a server. This server will be running for the lifetime of the application, or until:
- An unhandled exception (error) is thrown.
- The server shuts down either manually or by a scheduled task.
- Software failure outside Node.js or hardware failure.
Traditional APIs are hosted using a running server. As you scale your application, you’ll need to consider: cost, flexibility, security, rapid provisioning, and much more. As you can imagine, this is difficult to implement correctly.
The serverless approach is quite different. Pieces of backend code run in stateless compute environments that are triggered by events (like requests) and may last for one invocation. It’s fully automated and can scale up in milliseconds. Plus, there is no overhead managing and maintaining servers. Developers focus on business logic – functions that return value.
When we deploy a server (Express.js based application) within a Serverless Function, we are executing a full server implementation on each request. This is an anti-pattern, as Serverless Functions should serve one purpose.
We recommend using API Routes with Next.js to create Serverless Functions.
Any file inside the folder pages/api
is mapped to /api/*
and will be treated as an API endpoint instead of a page
. For example, the following API route pages/api/user.js
handles a json
response:
1
export
default
function
handler
(
req
,
res
)
{
2
res
.
statusCode
=
200
;
3
res
.
setHeader
(
'Content-Type'
,
'application/json'
)
;
4
res
.
json
(
{
name
:
'John Doe'
}
)
;
5
}
API routes provide built in middlewares which parse the incoming request (req
). Those middlewares are:
req.cookies
– An object containing the cookies sent by the request. Defaults to{}
req.query
– An object containing the query string. Defaults to{}
req.body
– An object containing the body parsed bycontent-type
, ornull
if no body was sent
There’s also support for additional middlewares.
You can also create a standalone Express.js app with Vercel. First, create a file index.js
and add it to an /api
folder. This is similar to the app.js file in serverful Express.js applications. The /api
directory is where we’ll add our Serverless Functions.
1
const
app
=
require
(
'express'
)
(
)
;
2
const
{
v4
}
=
require
(
'uuid'
)
;
3
4
app
.
get
(
'/api'
,
(
req
,
res
)
=>
{
5
const
path
=
`
/api/item/
${
v4
(
)
}
`
;
6
res
.
setHeader
(
'Content-Type'
,
'text/html'
)
;
7
res
.
setHeader
(
'Cache-Control'
,
's-max-age=1, stale-while-revalidate'
)
;
8
res
.
end
(
`
Hello! Go to item: <a href="
${
path
}
">
${
path
}
</a>
`
)
;
9
}
)
;
10
11
app
.
get
(
'/api/item/:slug'
,
(
req
,
res
)
=>
{
12
const
{
slug
}
=
req
.
params
;
13
res
.
end
(
`
Item:
${
slug
}
`
)
;
14
}
)
;
15
16
module
.
exports
=
app
;
Notice that we added a setHeader
line for our Cache-Control
. This describes the lifetime of our resource, telling the CDN to serve from the cache and update in the background (at most once per second).
Let’s add one rewrite to push all traffic to our index.js
. Add a vercel.json
at the root of your project to specify your app’s behavior. See the CLI documentation to learn how to customize your Vercel projects.
1
{
2
"rewrites"
:
[
{
"source"
:
"/api/(.*)"
,
"destination"
:
"/api"
}
]
3
}
To serve static content, we would normally do app.use(express.static('public'))
in our main file app.js
. Instead, we can add a /public
folder to the root.
Serving static files with Vercel allows us to do static asset hoisting and push to our Global Edge Network. We recommend using this approach instead of express.static
.
If you’re using Next.js, then React is your view layer. Otherwise, you might be tempted to install a view engine like Pug, EJS, or similar. Computing the same response for every request is not only expensive but highly inefficient. Remember that Serverless Functions don’t keep managed state. To prevent computing on demand and ensure cached content can be used in the future, we need to set up the correct headers.
Serverless Functions will create multiple database connections as traffic increases. All connections to the database need to be consumed quickly. To ensure uptime, consider using a serverless friendly database or connection pooling.
Serverless Functions have maximum execution limits and should respond as quickly as possible. They should not subscribe to data events. Instead, we need a client that subscribes to data events and a Serverless Function that publishes new data. Consider using a serverless friendly Realtime provider.
Express.js will swallow errors that can put the main function into an undefined state unless properly handled. They’ll render their own error pages (500), which prevents Vercel from discarding the function and resetting its state.
Let’s explore how to re-think our application to utilize serverless.
Next.js/Vercel prevents the need for installing common dependencies you’d use with Express. For example, Next.js/Vercel give you access to the Request and Response objects from Node.js. These objects are the standard HTTP Request and Response objects from the Node.js runtime. You also have access to Node.js helpers and these are similar to the Express API.
Note: Read our Migration Guide to understand the transition to serverless.
It can be overwhelming migrating to a new provider, especially for new companies. We recommend adopting Next.js/Vercel (and serverless) incrementally. This helps reduce risk while still pushing your product and platform forward.
Serverless Functions can be used for every part of your application, including:
It’s possible to deploy an Express.js application as a single Serverless Function, but it comes with drawbacks and should only be used as a migration path. Instead, use Next.js or embrace multiple Serverless Functions as you incrementally migrate to the Vercel platform.
To deploy your Express.js project with Vercel for Git, make sure it has been pushed to a Git repository.
Import the project into Vercel using your Git provider of choice.
After your project has been imported, all subsequent pushes to branches will generate Preview Deployments, and all changes made to the Production Branch (commonly “main”) will result in a Production Deployment.