Zip your own Netlify functions for better dependency control
Tags: javascript, netlify, lambda
Published: 2020-10-25 22:53:53

When I was working on my side project [Dedolist](https://dedolist.com), which is mostly hosted on [Netlify](https://netlify.com) I started using Netlify functions. They are a really easy way to create small AWS Lambda functions.  

In their simplest form you just created a file in your "functions" folder and they get deployed as a lambda function.  Unfortunately I required a bit more control over the functions than the simplest case.

I needed:
1. To access a file locally that is deployed with the function.
2. Maintain the functions own dependencies that were not part of the main project.

It took a few hours and reading a lot of forum posts and sample projects, but I finally was able to figure it out.  I'm hoping to save you some time by showing you the exact steps you need to take to accomplish this.

Netlify's build tools does try and smartly build your functions, however there are some scenarios where it may fail to find all the dependencies. There is also a limit to the size of the function that AWS lambda accepts (50MB) and this technique gives you more control over what is included in your final functions.

I have all the code for this demo in this [repository](https://github.com/dgavey/netlify-functions-example).  I'll point out some of the specific changes I made to deploy my bundled functions.

First off, in general the way to bundle your functions is you need to compress each function and all of it's dependencies in a single zip file. Just like the simplest form of Netlify functions, you can put each zip file in your functions folder and it will get deployed. 

In order to be able to test your functions locally using `netlify dev` you need to be able to specify a separate folder for your "development" and "production" functions.  It's easy to do that by changing your `netlify.toml` and adding environment specific configurations below.

```
#netlify.toml in root of project

[build]
  functions = "functions"

[dev]
  functions = "functions-dev"
```

As you can see above, new now specify two different folders for function in "build" and "dev". So now when you run `netlify dev` the functions can be modified in the functions-dev folder and you can test them there.

Now lets look at what a function in the "functions-dev" folder looks like.  Take a look at the structure below for a function called "hello-dev".

```
functions-dev
  hello-dev
    node_modules
    package.json
    hello-dev.js
    .gitignore
```

Everything in the folder `hello-dev` will be zipped and become one lambda function. You can have multiple functions and even mix your single file functions with folder based ones.

For this example the package.json has a dependency for [lambda-api](https://github.com/jeremydaly/lambda-api).  No other function will have this dependency only this one.

The magic is in the top level package.json file and the build commands. Let's look at each part of the build system.

``` javascript
"scripts": {
      "build": "NODE_ENV=production npm-run-all build:*",
      "build:static": "eleventy",
      "build:functions-install-dependencies": "cd functions-dev; for i in */; do cd ${i%/}; yarn; cd ..; done;",
      "build:zip-functions": "cd functions-dev; for i in */; do zip -r \"../functions/${i%/}.zip\" \"$i\"; done;",
      "build:copy-single-functions": "cp ./functions-dev/*.js ./functions",
      "dev": "eleventy --serve --quiet"
}
```

So **"build"** simply runs all the build steps and signifies the node production environment. This is the command that Netlify calls when building the production application.

**"build:static"** Is just the normal Eleventy build command, not part of the functions build step.

**"build:functions-install-dependencies"** does what is says.  It enters into each folder and install the dependencies for each function.

**"build:zip-functions"** zips each folder into the production functions folder so Netlify knows to create it.

Finally **"build:copy-single-functions"** copies any single file lambda functions you might have.

You can see a working example from the [repository](https://github.com/dgavey/netlify-functions-example) on [https://dgavey-netlify-functions-demo.netlify.app/](https://dgavey-netlify-functions-demo.netlify.app/).

There was a couple of strange issues I ran into with the Netlify CLI that should be noted.

1. It won't serve functions on a purely static site, so I included an extremely basic eleventy generator.
2. It won't allow access to functions in folders unless there is a build command in dev environment.

Hopefully this can help you get more control over the building of your functions with Netlify.

Cover photo by [Tony Pham](https://unsplash.com/@tonyphamvn?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText)