Using Netlify Functions with Gatsby

An instant backend for your Gatsby site


One of the coolest features that Next.js offers is API Routes.

An API route is similar to a typical route, except instead of serving a statically-built HTML page, it invokes a Node.js function. You can use this for all kinds of stuff:

  • Managing user authentication
  • Getting and setting application data from a database
  • Proxying requests to 3rd-party APIs, while keeping secrets secret
  • Anything you'd normally use Node.js for!

Even mostly-static sites like this blog can benefit from being able to mix in a splash of Node. For example, this blog has a hit counter at the bottom of every article. The data for the # of hits needs to be stored in a database.

Gatsby doesn't have first-class support for API routes, but fear not! With a helping hand from Netlify, we can build something which is just as awesome.

This tutorial will show you how to add to your existing Gatsby site. No experience with serverless / backend code is expected. To follow along, you'll need a site currently being deployed on Netlify.

Watch the video NEW

Prefer your lessons in video format? Watch for free on egghead:

Link to this heading
What are Netlify Functions?

Netlify Functions are essentially AWS Lambda functions, wrapped and integrated into Netlify's platform.

If you've heard the term “serverless”, it's usually a reference to AWS Lambda. Essentially it's a cloud platform that lets you run backend code without thinking about servers. Your code exists simultaneously on many different computers, and it scales up and down automatically as needed. Instead of paying a monthly fee for renting a server, you only pay when your code is executed.

AWS products are notoriously difficult to work with, and AWS Lambda has its share of sharp edges. Netlify Functions sands down some of these edges, by doing stuff like:

  • Bundling and deploying your code when you publish changes to your site
  • Managing routing
  • Offering a local dev environment

In exchange for this convenience, Netlify charges a slight premium. Your first 125,000 requests are free, but anything above that adds a $25/month/site package (and the price scales up more once you exceed 2 million requests per month per site). Learn more on their pricing page.

Let's look at a straightforward example of a Netlify Function. Create a new root-level directory called functions, and add a file, hello-world.js:


Breaking this down, our file has a single function, which is exported using CommonJS syntax as handler. This function can be given parameters, and we'll see them a little later on. For now, we don't need them.

We are expected to return a response object from this function, which should include:

  • statusCode, an HTTP status code
  • body, the contents of the response. Must be a string (you can use JSON.stringify for objects)

In order to use this function, you'll need to save this file in a top-level functions directory. The name of the file will become the path you can use to make the request. For example: /functions/hello-world.js will be available at https://your-site-com/.netlify/functions/hello-world.

Link to this heading
Configuring Netlify

I'll warn you now: this part of the tutorial is boring. Fortunately, it's a one-time setup deal. Think of it as the annoying insurance forms you need to fill out before they'll let you go ziplining.

We need to do two things:

  1. Enable functions for our Netlify project
  2. Link our local development environment to our Netlify site

Link to this heading
Enabling functions

Log into your Netlify dashboard, and select your site. These pictures show the sequence needed to enable functions for your site:

The Netlify “site details” page, with the “Site settings” button circled.Click the “Site settings” buttonThe site settings page. In the left side-bar, the navigation link for “functions” is circledClick “Functions” in the sidebarThe “Deploy Settings” for your functions. The functions directory is not set, and there's a circled button to “Edit settings”Click to edit settingsThe “Deploy Settings” for your functions, with the edit form toggled on. The word “functions” has been entered in the text field, and the “Save” button is circledEnter “functions” and click Save

Link to this heading
Linking our local development environment

Next, we need to install the Netlify command-line tools. Open a new terminal and run:


cd into your Gatsby project, so we can link it to our Netlify project:


You'll be prompted to select the correct project. In many cases, it can infer the project from the Git remote. After this has been completed, you should see a happy little message like this:

A confirmation message, saying that the project has been linked

Link to this heading
Running locally

In order to execute the function we wrote, we need to make a request to this URL:

The URL is derived from our local path to the function (/functions/hello-world.js), but without the .js suffix, and with a .netlify prefix.

Of course, if we start our Gatsby dev environment and try and access localhost:8000/.netlify/functions/hello-world, we'll get a 404 error; our Gatsby development server doesn't know anything about this!

Instead, we'll need to run Netlify Dev, a service for running the Netlify platform on your development machine. At the time of writing, it was still in Beta, but it works great for running local serverless functions.

From within your Gatsby project, run:


You should get a whole lot of output:

Terminal output of Netlify Dev

Let's go through this step by step:

  1. We run netlify dev in our project
  2. It correctly identifies that this is a Gatsby project
  3. It sets up an AWS Lambda server on port 34567
  4. It starts a Gatsby dev server with npm run develop
  5. It launches a wrapper server on port 8888
  6. It echoes the typical Gatsby output, which shows a Gatsby dev server on port 8000 (the default for Gatsby apps).

That's a lot of servers! In addition to the typical Gatsby dev server at port 8000, it also runs a Lambda server at 34567, and a "wrapper" server at 8888.

The idea with the wrapper server is that it intercepts any requests to /.netlify. The Gatsby app doesn't have a route for that path, but Netlify does! This allows us to access our function by visiting localhost:8888/.netlify/functions:

Chrome window showing that going to localhost:8000/.netlify/hello-world shows the text “Hello World!”

Link to this heading
Using Functions

Our Netlify Functions work like an API endpoint: we can hit it with fetch whenever we want to execute them. The returned value will be the response.

We're free to use whichever HTTP action we want (GET, POST, etc). Here's an example of how we might retrieve the "hello World!" copy:


Link to this heading
The “event” Parameter

The function we've seen so far responds identically to all requests. This isn't exactly realistic; our function may depend on query or body params, cookies, the HTTP method, and so on. Fortunately, our function takes an event parameter, which tells us all about this request.

Here's a quick look:


Link to this heading
CDNs for the backend

Many people pick Gatsby because they like the idea of a site that can be compiled to plain HTML + CSS + JS, deployed around the world on a simple CDN instead of a monolithic server.

This is really cool, because it means you get a blazing fast site with perfect uptime; since your site is copied across thousands of individual static servers across the world, there's no problem at all if a bunch of them spontaneously explode.

Up until very recently, if we needed a dynamic runtime backend, we'd need to introduce a single point of failure; we'd need to rent a VPS and install a Node/Express app, and hope it doesn't crash if a meteor hits the data center, or our site gets featured on Product Hunt.

Serverless functions are CDNs for the backend. When you deploy a function to AWS Lambda through Netlify Functions, it's dispersed across the cloud, and it automatically scales up or down depending on traffic. We don't lose any resiliency by introducing backend functions!

This tutorial is ending, but your journey with functions is just beginning. Now that you have this tool in your toolbox, a lot of new doors are open to you!

In the near future, I'll be writing about how I use serverless functions and FaunaDB to set up things like a hit counter + a “like” button. Be sure to subscribe and I'll let you know when it's published!

Last Updated

June 10th, 2020


A front-end web development newsletter that sparks joy

My goal with this blog is to create helpful content for front-end web devs, and my newsletter is no different! I'll let you know when I publish new content, and I'll even share exclusive newsletter-only content now and then.

No spam, unsubscribe at any time.

If you're a human, please ignore this field.