> ## Content Index
> Fetch the complete content index at: https://madewithlove.com/blog/llms.txt
> Use this file to discover other available public pages before exploring further.

# Serverless functions with Vercel
- URL: https://madewithlove.com/blog/serverless-functions-with-vercel/
- Published: 2020-09-02T13:47:22.000Z
- Updated: 2026-05-29T11:57:40.000Z
- Author: Geoffrey Dhuyvetters
- Tags: Engineering, Tutorials, JavaScript, Frontend

As you (might) know, our current website is built on [Gatsby](https://www.gatsbyjs.org/). I love the fact we’re generating a super cacheable, fully static site with every build, but this adds a couple of limitations.

One of the limitations of this setup is having no backend (I know that sounds funny). At times, mostly when communicating with 3rd party services ([newsletters](https://mailchimp.com/developer/), [emails](https://frontapp.com/api), [captcha flows](https://www.google.com/recaptcha/intro/v3.html), etc.), we need a backend to handle authentication.

I felt that the natural way to approach this was using serverless functions (“’other people’s servers”’ wasn’t that catchy).

Serverless functions are built using these steps:

1. create a function (which can access secrets and 3rd party APIs)
2. deploy it to a platform
3. call it as an API from JavaScript (just using something as simple as fetch)

I looked into several services (hardcore [AWS](https://aws.amazon.com/lambda/), [Cloudflare Workers](https://workers.cloudflare.com/), [Serverless](https://www.serverless.com/), and more) but using the [Vercel](https://vercel.com/) platform ([formerly known as Zeit](https://vercel.com/blog/zeit-is-now-vercel)) turned out to be the simplest solution.

What I like about Vercel’s approach is that it’s very easy to run things locally and you don’t have to do crazy stuff ([looking at you AWS](https://docs.aws.amazon.com/lambda/latest/dg/configuration-layers.html)) to add external dependencies (aka NPM modules).

You can write these functions in Go, Python, Node, or Ruby. I’ll be focusing on Node since this is my go-to server language. Deployment is done through [their CLI](https://github.com/vercel/vercel). I’ll also be using [Next.js](https://nextjs.org/) (I’ll dedicate a blog post to this framework later) to make the setup a bit easier.

This might look a bit complicated, but bear with me — it’s not that bad :).

The first step is to [create an account on Vercel](https://vercel.com/signup) and authenticate with the CLI.

```bash
npm i -g vercel@latest
```

```bash
vercel login
```

Now also provides us with the option to start from a boilerplate by using **now init.**

```bash
vercel init nextjs
```

Make sure you rename the folder and the **name** property in **package.json** as your Next step (see what I did there).

Navigate into the folder, install the dependencies and run the project in development mode.

```bash
cd serverlessfunctions101
yarn
yarn dev
```

When navigating to [http://localhost:3000](http://localhost:3000/), you should see a nice and clean introduction page. 

Now (I did it again), empty the **/pages** folder. We want to focus on functions only.

Add an **/api** folder inside of **/pages** and create **hello-world.js** there.

Your structure should look like this.

```
/pages
  /api
    /hello-world.js
```

Each file in **/api** will map to a route. Our function will be available on <http://localhost:3000/api/hello-world>

Creating a function is easy; each function receives a request and should return a response (if not, it will time out).

The simplest way to return data is by using **response.send**. This method accepts text, an object, or a buffer. 

It’s not a real tutorial if we’re not starting with a ‘hello world’ right?

```javascript
export default (request, response) => 
  response.send('hello world');
```

```javascript
export default (request, response) =>
  response.send({
    data: 'hello world',
  });
```

By default, the response status code is **200** **(OK)**. You can modify the status code by using **response.status**. [http-status-codes](https://www.npmjs.com/package/http-status-codes) is a handy package to make this a bit more readable.

```bash
yarn add http-status-codes
```

```javascript
import Status from 'http-status-codes';

// GET -> http://localhost:3000/api/hello-world

export default (request, response) =>
  response.status(Status.FORBIDDEN).json({ error: 'Unauthorized' });
```

We have access to the HTTP request method by using **request.method.**

```javascript
import Status from 'http-status-codes';

// GET -> http://localhost:3000/api/hello-world

export default (request, response) => {
  if (request.method !== 'GET') {
    return response.status(Status.BAD_REQUEST).send('');
  }
  return response.json({
    data: 'hello world',
  });
};
```

**request.query** allows you to access query string data.

```javascript
import Status from 'http-status-codes';

// GET -> http://localhost:3000/api/hello-world?name=Geoffrey

export default (request, response) => {
  if (request.method !== 'GET') {
    return response.status(Status.BAD_REQUEST).send('');
  }
  const name = request?.query?.name ?? 'world';
  return response.json({
    data: `hello ${name}`,
  });
};
```

**request.body** contains all data passed with the request

```javascript
import Status from 'http-status-codes';

// POST -> `http://localhost:3000/api/hello-world`
// with JSON payload {"name": "Geoffrey"}

export default (request, response) => {
  if (request.method !== 'POST') {
    return response.status(Status.BAD_REQUEST).send('');
  }
  const name = request?.body?.name ?? 'world';
  return response.json({
    data: `hello ${name}`,
  });
};
```

**async/await** is supported **by default**, so you can easily call external APIs too.

```javascript
export default async (request, response) => {
  const response = await fetch(apiURL);
  const data = await response.json();
  return response.send(data);
};
```

When it’s time to deploy your functions, it’s just a single command. Vercel guides you through the process and deploys to the correct target.

– **vercel** deploys to a unique staging environment

– **vercel –prod** deploys to production

Run the first command. Your function(s) should now be deployed to a **\*.vercel.app** address, you can configure domains etc via [your dashboard](https://vercel.com/dashboard).

Sometimes you need to store secrets, you can configure those in the project’s settings. Locally, you can store your secrets in a **.env.local** file, like this.

```
API_KEY=my-secret-key
```

I would advise you to try out some things yourself. I promise you’ll really enjoy the experience of creating and deploying serverless functions with Vercel. This is just the tip of the iceberg when it comes to serverless, including [CORS and ](https://github.com/possibilities/micro-cors)[middleware](https://nextjs.org/docs/api-routes/api-middlewares#connectexpress-middleware-support).

More information and documentation can be found on the [Vercel website](https://vercel.com/docs/v2/serverless-functions/introduction).

## Stay in the loop

Weekly updates for SaaS founders, developers and investors. 

Subscribe 

Email sent! Check your inbox to complete your signup. 

No spam. Unsubscribe anytime.