Last updated by Netlify Support in October 2024
In this guide, we’ll be talking about synchronous functions. We won’t be covering Edge Functions or Background Functions since those are not bound by the same limits as standard synchronous functions or Scheduled Functions are.
Netlify Functions are a core feature of our product. By delegating your server-side logic to them, you leverage serverless functions that are version-controlled, built, and deployed along with the rest of your Netlify site.
However, there are some limitations on function execution, with the 30 second execution limit being one of the most critical factors to have in mind when designing your serverless code.
Function crashing
If your function takes longer than the allowed execution time, you’ll most likely be presented with this message:
That would be the error displayed when you directly visit the function URL. However, if you’re calling the function from your frontend using APIs like fetch
or libraries like axios
, you most likely won’t see this page. In that case, you’d have to check the dev tools in your browser and inspect the Network tab to check for that request. You could then see the above message in the “Response” tab.
Let’s dive into a few scenarios where this happens and how we can take the first steps towards mitigating them…
Everything was running smooth… What happened?
Your site was running fine and everything working great. You’re already thinking about the next cool feature to roll out when you notice that someone DM’s you that screenshot from your production site.
Well this is strange! That isn’t supposed to happen. First thing you do is open your site immediately and try to reproduce the case…
… but it’s working fine now
Why am I not able to replicate this? Why is it only happening sometimes?
Typically reasons for this issue may include, but are not limited to:
- Your code is taking longer to execute due to some condition we (or even you for that matter) cannot predict or control (e.g. slow third-party API response);
- Your code may have been running at its limit before (near the limit of execution time) and all it took was a small delay to cause the failure. Maybe your code is not optimized enough or is too complex for a one function to handle.
- Your code does not reliably exit - perhaps you have a code path that will never complete somewhere in your function?
My function never worked! It’s always timing out! What is wrong?
You’re excited on making your first step towards the future of web development. You’re either starting a new project or thinking about migrating an existing site over to Netlify but are already running into some roadblocks along the way.
No worries, we’re here to help. You’ve set up your Netlify Function properly and followed every instruction “by the book” but your code is still timing out.
Typically reasons for this issue may include, but are not limited to:
- Guess what? Basically the same as above. Maybe slightly different but the root cause is most likely related to the same causes (slow APIs, extensive code, etc.)
My site uses a framework such as Gatsby or Nextjs. What is happening?!
Gatsby related functions
To support Gatsby Functions and SSR/DSG render modes, the Essential Gatsby build plugin automatically generates Netlify Functions called __api
, __ssr
, __dsg
, and __ipx
.
If you are using Gatsby version >=5.12.0
, gatsby-adapter-netlify will be installed automatically, and provide support for Gatsby Functions.
Next.js related functions
When using the Essential Next.js Build Plugin, it creates three Netlify functions that handle requests that haven’t been pre-rendered. These are ___netlify-handler
(for SSR and API routes), ___netlify-odb-handler
(for ISR and fallback routes), and _ipx
(for images).
So… What’s happening?
If the function that is timing out is one of the framework-related ones, it’ll probably boil down to the same reasons. However, these functions have additional logic to sustain their execution that uses part of the allowed execution time.
How to mitigate all scenarios
Take a closer look at your code.
Is it relying on any third-party service? Is that service working properly (might be a good thing to check their statuspage or logs)? Presumably, running the function locally will show the same behavior around the speed of API calls/responses so you can more easily debug.
If you have a framework-related function, is it timing out only for a particular page request? If so, what makes this page different than the others?
Try breaking-down your function into smaller parts. Instead of making 10 requests in the same API call, try splitting it into 2 functions with 5 calls each. Or, consider doing the “synchronous” part of the work in a function (verify credit card here), and the asynchronous part (place order with warehouse here) in a background function, which can run for up to 15 minutes. Note that you can call a background function from a normal function; it will not block the primary function’s execution.
Sometimes, region also makes a difference. Netlify Functions, by default run in us-east-1
(N. Virginia) region. So, if you are making API calls to services who have their servers located in the other end of the world, the responses will take longer. If you have a Pro or higher account, our staff can adjust the region of your functions for you per site or account wide to most AWS regions that are capable of running lambdas.
A few times, you might be missing something simple. You might have made all the necessary optimizations, but missing the final return
statement to actually send the response back to the client. For example:
export async function handler(event, context) {
const data = await doStuff()
return {
body: JSON.stringify(data)
statusCode: 200
}
}
In the above example, if you’re missing the return
statement, the function will execute the doStuff()
function and keep on waiting forever even after successfully retrieving data from that function. Your Function code might not always be this simple, so you might need to make sure that your Function is actually firing the return
statement at the correct time.
Logging execution time
The best way to see how long your Function is taking for a particular task is by logging its execution time. The best way to do that is by using console.time()
. Here’s an example:
export async function handler(event, context) {
console.time('doStuff')
const data = await doStuff()
console.timeEnd('doStuff')
return {
body: JSON.stringify(data)
statusCode: 200
}
}
In your Function console, you’d see something like: doStuff: # seconds
. This will show how long your doStuff()
call took. Again, depending on your Function code - for instance if it is using features like async/await
statements, Promises, etc. you might have to adapt the above to correctly calculate those timings.
Once you know what piece of code is acting as a bottleneck in your Function, you can work on changing that.