Did you know that we’ve rebuilt Netlify Functions from the ground up, with a reimagined experience and packed to the brim with new features? If you’re still using the legacy version, you’re missing out! This guide will help you migrate in a few simple steps.
#Some quick history
It’s been a while since we first launched Netlify Functions. For the first time, developers could augment their frontend applications with backend functionality without leaving the comfort and convenience of the Netlify experience they knew and loved.
Back then, AWS Lambda was the state-of-the-art solution in the serverless computing space, so Netlify Functions launched with a fully compatible API surface, making it easy for developers to port over any existing workflows.
Functions quickly became an incredibly popular feature of our platform, used by millions of developers on a wildly diverse set of use cases.
Late last year, we took everything we learned over the course of five years and released a major update to the product, with a redesigned API based on web standards and a set of features that unlock an entire new category of use cases.
We kept the legacy version around so that developers could migrate at their own pace, but we haven’t updated it with any new features and we’re going to start deprecating it 2025.
#What’s new
Before I ask you to change any code, let me try to convince you that it’s worth your trouble. Here’s what you’ll get out of the box when you start using the modern Netlify Functions.
- Built on web standards: The new Netlify Functions API has a really simple design built around web platform standards: a function receives a
Request
and returns aResponse
. So rather than having to learn a proprietary API, your team can just learn the web platform. - Configurable URL: Gone are the days when setting the URL of your function involved creating a rewrite rule to the default
/.netlify/functions/<name>
endpoint. You can now configure the URL right from the function code. - Advanced routing: To give you better control over when your function should or should not run, you can set it to respond only to certain HTTP methods and provide a list of exclusion paths. You can also build complex routing logic by defining path parameters using the
URLPattern
standard. - Zero-config streaming: If you want to use response streaming to start getting data in front of your users as quickly as possible, your function can simply return a stream. There’s no need to annotate your code or configure anything.
- Zero-config Blobs: Use Netlify Blobs within your function with no setup required. To interact with a data store, import the
@netlify/blobs
module and call the methods to read and write data as you please. - Static file shadowing: When building an application that leverages a combination of static and dynamic data, you can configure your endpoint to serve a static file if one exists at that path and only invoke the function if not.
- Rate limiting: You can define custom rate-limiting rules for your endpoints right from your function code.
- Simple cookies: Manipulate cookies with ease by using type-safe, convenient utility methods based on the
CookieStore
standard. - Geolocation data: Unlock personalisation use cases with detailed information about your visitors, like their IP address, country, city, timezone and even postal code.
- Netlify metadata: Get easy access to metadata about your Netlify property, including information about your account, site and deploy.
- Global
Netlify
object: Access any of the features listed above (and more) from anywhere in your function, even in deeply-nested files or modules that don’t have access to the handler scope.
#Code changes
«Okay, but I have a lot of functions using the old syntax and I don’t want to risk breaking my site with complex migrations». I hear you!
First of all, Netlify gives you different tools that make this type of migration safe:
- You can use the Netlify CLI to run your functions locally before deploying
- You can use deploy previews to validate your changes before publishing to production
- The
@netlify/function
package exposes types for all the APIs, giving TypeScript users full type-safety
You do need to make some changes to your code, but they’re limited to a small set of areas. Let’s get started.
#Move to ES Modules
One of the key pillars of the modern Netlify Functions is the idea of embracing the web platform and building with standard APIs whenever possible. This includes the format in which function files are defined.
The modern Netlify Functions work exclusively with the standard ECMAScript modules format (also known as ES Modules or ESM). The CommonJS format is not supported, since it comes with a set of drawbacks and it was never standardised beyond its Node.js implementation.
To move to ESM, start by changing the way you import and export data:
- Imports with
require()
must be changed toimport
declarations - Imports of local files must always include the file extension
- Exports with
module.exports
must be changed toexport
declarations
If you use VS Code, you can get it to handle this transformation for you: hover next to the require
keyword, click on “Quick fix” and select “Convert to ES Module”.
Finally, you must instruct Node.js to treat your function as an ESM file by doing at least one of the following:
- Rename the function’s entry file to use the
.mjs
extension (or.mts
if you want to use TypeScript) - Have a
package.json
file at the root of your project with thetype
property set tomodule
There are a few other changes that may affect you, depending on how your function is structured:
#Change the handler signature
In the modern Netlify Functions, the function handler is declared using a default export and not the named handler
export.
Another notable change is in the signature of the handler. Instead of receiving a Lambda event, your function will receive a Request
and a context object. Equally, rather than returning a Lambda response object, your function must return a Response
.
This has implications on how you perform operations like accessing the request URL, reading and setting headers or defining the response status code.
If you use scheduled functions, you must declare the cron expression in a schedule
configuration property instead of using a wrapper function. Also, the handler no longer needs to return anything, since there’s no client waiting for a response.
When you start using the new API, you’ll notice that you’re working mostly with web standards and I think you’ll love how intuitive and predictable that feels — as much as I like the Netlify documentation, nothing beats being able to just refer to the documentation of the web platform.
#Supercharge your functions
Now that your function is using the updated syntax, let’s look at how you can leverage some of the powerful features it gets you out of the box. In the example below, we’ll configure the function URL with a path parameter and set it to run only on GET requests.
And that’s it! Your function has gained superpowers with just a few changes.
#Bonus: two for one
Now that you’ve familiarised yourself with the modern Netlify Functions, you might like to know that you also learned how to use another serverless compute primitive in the process: Netlify Edge Functions.
Even though they run on different JavaScript runtimes, they have identical APIs and configuration options. In fact, you can try moving your function file to the netlify/edge-functions
directory and it should just work.