Guides & Tutorials

How Our Build Bots Build Sites

Note: This post was last updated with current information in January 2023.

At Netlify, we believe in the simplicity of the JAMstack, and we are thrilled that you are contributing to the success of the stack along with us. Developing sites can be simple, but once you start thinking outside of the box, you’re probably using more than one framework, more than a few modules in the language that your site generator is written in, and some of your own code to glue them together.

Your carefully crafted development environment, which came together organically during the creation and growth of your site over weeks or months, builds your site just fine. But then you send us your repository to build for you, and all we generate is a build failure…bummer! You’re always welcome to ask us for help in our Forums - this article about debugging your site build in particular may be the advice you need already pre-organized for you. However, we do have some best practices and some debugging suggestions if you’d rather do your own investigation.

How we make the sausage

To give some context for diving into build issues, let’s take a high-level tour of our build system. Note that the build system is only used when you use us with a git repo — sending us your code, rather than your finished site. It works the same for a repository we’re watching, a deploy triggered using an incoming Build Hook, or a build you trigger from our UI. However, for API deploys where you send us a zip file, use our CLI to build locally before deploying, or even drag and drop deploys - those are pre-built by you, and we just publish the content you send us out onto our CDN directly.

At a high level, the build system is actually quite straightforward — we clone your repo and submodules, drop git permissions, launch a docker container (without git permissions, but with access to your just cloned code), download any cache from a prior successful build in the same context, and then run your specified build command(s) in a recent version of ubuntu linux, potentially also running any automatically or manually configured integrations or build plugins on the way.

Want to try to make your own sausage?

To debug a build, as of January 2023 you cannot run our build image directly. However, we provide a CLI which should run your build nearly-identically, if you want to develop locally instead of in our CI. This will be your basic recipe, from within a local copy of your cloned repository:

# install the CLI for current and future use:
npm install netlify-cli -g
# log in to Netlify using it
netlify login
# choose a site to connect this repo with
netlify link
# build your site
netlify build
# optionally, push your successfully built site up to our CDN:
netlify build --deploy

This process should connect your local development environment to the relevant netlify site and run the build command you have configured, potentially using environment variables set in our UI as well as locally, which in turn should show you similar error messages (assuming you have your local development environment configured to match ours, as described in the debugging section of this article).

Since I am a psychic, so I can tell you what probably went wrong with your build. Speaking as Netlify’s Head of Technical Support, I can tell you that the proximate cause of a build failure is likely with your specification of the versions of build tools you want to use. You’ve probably got a package.json if you use a Node.js-based system, and maybe you have a requirements.txt or a Gemfile if you’re using Python or Ruby. That’s all you probably need on your local build system — because you can be sure that the version of Node, Ruby, or Python you’re using is the version that you’re using. But what versions are we using? You can check out all our defaults here: https://docs.netlify.com/configure-builds/available-software-at-build-time/

I know — you don’t use those versions AT ALL, how on earth could we choose such an ancient version of your language, WTF?

A tale of several versions

The truth of the state of technology is that there is no one size fits all project specification (as our ever-growing list of static site generators shows), but don’t worry, we do allow you to specify:

  • a Node.js version — either via .nvmrc or by setting a NODE_VERSION environment variable in the “Build environment” section of our per-site Settings UI. Note that there are some default npm version to Node.js version mappings — Node.js v8 will pull in npm v5, and if you want some different behavior you may have to do some fancy footwork with your package.json (or even explicitly installing an older version). You can use any version that nvm can fetch!

  • a Ruby version — put your version of choice in a /.ruby-version file. You can choose any version that rvm supports. As of early 2023, we pre-install 2.7.2 and 2.6.6

  • a Python version — put your version of choice in a /runtime.txt . We only have a handful of pythons (hehe) in our build environment, so you should either pick one of these or make a compelling argument for us to include another version: we pre-install 3.8 (default), and also 2.7

  • A PHP version. We have version 8.0 as default, but you can select other versions (7.4 or 8.1) via a $PHP_VERSION environment variable.

If our build environment is missing something other than a ruby, node, or python dependency, you might need to add it yourself. Our build environment runs Ubuntu Linux v 20.04 LTS using x86_64 architecture, so you’ll want to bring a binary that can run there. Since you don’t have permissions to apt-get install anything, you’re limited to pre-compiled binaries that fit that architecture. A frequent use pattern is to get a copy of the binary we need to build your site, and add it to your repository so you can run it directly during your build. By default your build starts in the root of your repository, so it could be as easy as using ./my-binary as part of your build command.

What else could go wrong?

There are several other paths to failure within our build environment. One example is builds that are intended to serve content: your build command shouldn’t be node index.js or npm start! You’ll probably see a build timeout in these cases — we’ll run your commands but then after 15 minutes, we stop the build process.

The next biggest source of failures is network access. The Docker container your build runs in does have network access — you can download stuff from the internet — but what we don’t have is any of your GitHub permissions. If you have submodules that are in private repositories, or private node modules, or other Git repositories that you need separate access to — well, our build environment only has access to them in case you can somehow provide the authentication to us. You can see some advice on how you can access private resources in the following articles:

Now that you’ve gotten the versions ironed out and access permissions all dialed in, things should be working, right? Well, just in case builds are still failing, fear not — we’ll be happy to help you debug in our forums, in case things still aren’t working.

Keep reading

Recent posts

How do the best dev and marketing teams work together?