Does your Netlify function appear to be working locally but you're having trouble successfully deploying the function due to it being greater than 50 MB? This article walks through how to use the Netlify CLI to determine the size of the bundled Netlify function locally in order to more quickly optimize the size.
Under the hood Netlify functions are an abstraction build on top of AWS Lambda functions. Therefore, Netlify functions are subject to the same limits as AWS Lambda functions and currently AWS restricts zipped Lambda files to 50 MB. During the build process Netlify bundles any Netlify functions, by default with the zip-it-and-ship it bundler and attempts to upload the zipped version. If a Netlify function is greater than 50 MB after the bundling process then during the build process when uploading the zipped function you will receive an error similar to the below:
You can often get feedback more quickly on the size of your Lambda functions by testing locally whether or not the zipped artifacts for your Netlify functions are less than 50MB without having to do a full remote build.
I was recently working on a Netlify function to programmatically generate meta images and required the following dependencies dotenv, node-fetch, chrome-aws-lambda and puppeteer. It was working as expected locally and remotely but once I added an additional dependency of Cloudinary I began to encounter issues with the function size being too large and needed to experiment with potential optimizations like, will using puppeteer directly from chrome-aws-lambda meaningfully reduce the overall size of the function? Or, will switching the bundler reduce the size of the function below 50MB? The ability to test the impact of my changes of the overall bundle size locally without having to commit them and wait for remote CI/CD was helpful for reducing the amount of time it took to get feedback on my changes and allowed me to land on a working solution more quickly.
1) In order to most effectively work with Netlify functions in a development environment you should use the Netlify CLI as it allows you to run a local development server and interact with Netlify in a similar context to your hosted build configuration. The Netlify CLI can be installed globally with:
1npm install -g netlify-cli
In order to interact with your hosted Netlify site you will need to authenticate by logging into Netlify and link the local project to a site hosted in your Netlify account:
1# Login to Netlify2netlify login34# Link current directory to a remote Netlify site5netlify link
Once everything is configured for the Netlify CLI you should be able to run a build locally that mirrors what happens when Netlify generates a deploy preview remotely which is a similar context to where the error related to file function size occurs.
1netlify build --context deploy-preview
This will run a full build of your site and show in the logs each build step as it occurs and whether or not there are any errors. If everything succeeded then you should be able to view the functions generated by the build in a hidden
.netlify directory within your site which contains your functions folder and both the zipped and unzipped versions of the functions. Since we're concerned about the size of the generated zipped version of the function that is the file that we need to examine closer.
We can quickly inspect the file path of the zipped function that was generated during the build with
du which is a unix command to get information on disk usage and use the -h flag to render the output in a "human-readable" format. Note since this format is human-readable it's an approximation of the actual number.
1# du -h .netlify/functions/getMetaImg.zip2du -h path/to/your/generated/netlify/function.zip
For the above
du command the example output for a 50MB file would be:
1# 50M .netlify/functions/getMetaImg.zip250m path/to/your/generated/netlify/function.zip
You can also navigate to the file via your computer's GUI file navigator such as MacOS's Finder or Windows' File Explorer and view more information for the file to view the file size. I found that looking at the file in the MacOS Finder and then right-clicking "more info" provided me with more significant digits for the same file than the number returned by
du. File Explorer can also be configured to display file sizes.
In order to be able to successfully upload and deploy your function you will need to figure out a way to reduce the size to be no greater than 50 MB by removing unused dependencies, swapping out
dependencies with lighter-weight alternatives or updating how your functions are being bundled for production. One of the fastest ways to reduce the overall size of Netlify functions is by using the esbuild bundler instead of the currently default for Netlify functions zip it and ship it (a.k.a zisi). In April 2021, Netlify announced beta support for esbuild as a more modern and faster, alternative to zisi.
You can enable esbuild for your Netlify functions by updating the
netlify.toml in the root of your project to include the following:
1[functions]2 node_bundler = "esbuild"
I updated my
netlify.toml and then was able to determine that the same function bundled with
zisi was ~2MB smaller in the
esbuild version by doing a local deploy-preview build of my site with the Netlify CLI and then running
du to view the file size. However, if the file is still too large you will need to do a closer evaluation of the dependencies your function relies onto function to determine if there are opportunities to reduce or replace larger dependencies.
Initially, I encountered some issues using esbuild out of the box which caused a
Error: spawn ETXTBSY error when running the deployed function as the zipped version excluded one of my dependencies
chrome-aws-lambda. I was able to determine this by checking the Netlify logs which output the following tip during the Functions bundling step:
1────────────────────────────────────────────────────────────────2 4. Functions bundling3 ────────────────────────────────────────────────────────────────4 5 Packaging Functions from netlify/functions directory:6 - getMetaImg.js7 - gatsby/gatsby.js8 9❯ The following Node.js modules use dynamic expressions to include files:10 - chrome-aws-lambda1112 Because files included with dynamic expressions aren't bundled with your serverless functions by default,13 this may result in an error when invoking a function. To resolve this error, you can mark these Node.js modules as external in the [functions] section of your `netlify.toml` configuration file:1415 [functions]16 external_node_modules = ["chrome-aws-lambda"]1718 Visit https://ntl.fyi/dynamic-imports for more information.
My issues with the deployed function were resolved after I updated my esbuild configuration to include that dynamic dependency of "chrome-aws-lambda" by adding the following to the netlify.toml
1#replace functionName with the name of your function or use [functions] to apply to all of the Netlify # functions configured by that netlify.toml2[functions.functionName]3 external_node_modules = ["chrome-aws-lambda"]
If you are noticing differences in behavior between the esbuild and zisi version of your function you should double-check the logs to help determine if dynamic imports that you need were not removed during the esbuild process and if so, update the functions configuration as needed.
Using the Netlify CLI can be a helpful resource for developing and testing Netlify functions locally. By creating a local deploy-preview build of your site with the Netlify CLI you can gain meaningful insight into issues that arise during remote deployments and shorten the feedback loop to debug issues that do not appear during normal local development. If you're using the default, zisi, bundler for Netlify functions you may want to consider switching over to esbuild.
This article was published on January 02, 2022.