The Vercel build cache is a powerful tool for speeding up deployments, but it’s not just about storing artifacts; it’s about intelligently managing the inputs that determine what needs to be rebuilt.

Let’s see it in action. Imagine you have a Next.js project. A typical vercel build command will process your code, dependencies, and configuration.

# Local build simulation
npx next build

On Vercel, the build cache works by hashing the entire set of inputs to a build step. If those inputs haven’t changed, Vercel can skip the build step and pull the cached output. This includes:

  • Source Code: Any change in your .js, .jsx, .ts, .tsx, .css, .scss files, etc.
  • Dependencies: Changes in package.json or package-lock.json (or yarn.lock, pnpm-lock.yaml).
  • Configuration Files: next.config.js, .env files (though sensitive env vars are handled differently), vercel.json.
  • Build Arguments: Any custom arguments passed to the build command.

The mental model Vercel builds is this: a build is a function, and the cache is its memoization. The inputs are the arguments to the function, and the output is the built artifact. If the arguments are the same, the output must be the same.

Consider a common scenario: adding a new dependency.

package.json before:

{
  "dependencies": {
    "react": "^18.2.0",
    "next": "^13.4.1"
  }
}

package.json after adding lodash:

{
  "dependencies": {
    "react": "^18.2.0",
    "next": "^13.4.1",
    "lodash": "^4.17.21"
  }
}

When Vercel detects a change in package.json (or its lockfile), it invalidates the cache for dependency installation and any subsequent build steps that depend on those installed dependencies. This is why a simple npm install or yarn add can trigger a full rebuild.

The levers you control directly are the files Vercel considers part of the build context. By default, Vercel is quite good at determining this. However, you can explicitly influence it with vercel.json:

// vercel.json
{
  "builds": [
    {
      "src": "next.config.js",
      "use": "@vercel/next",
      "config": {
        "outputDirectory": "build",
        "cacheSettings": {
          "outputCache": true,
          "cacheDir": ".next/cache"
        }
      }
    }
  ],
  "cacheSettings": {
    "outputCache": true,
    "cacheDir": ".vercel/cache"
  }
}

This vercel.json snippet shows how you can configure Vercel to manage caching for specific build steps. The cacheSettings within a build configuration or at the root level tell Vercel where to look for and store build artifacts. outputCache: true is the default and essential for this system to function.

One of the most counterintuitive aspects of the Vercel build cache is how it handles incremental builds, especially with frameworks like Next.js. It’s not just a simple file-level hash. Vercel’s build cache leverages content-addressable storage. This means that instead of hashing file names or timestamps, it hashes the content of each file. If you rename a file but its content remains identical, the cache might still be hit for that specific file’s processing. Furthermore, the cache is granular; if only one small utility function within a large module changes, Vercel might only need to reprocess that specific function and its direct dependents, rather than the entire module or application. This fine-grained invalidation is key to its speed.

The next concept to explore is how to leverage Vercel’s environment variables effectively to influence build cache behavior without invalidating it unnecessarily.

Want structured learning?

Take the full Vercel course →