Skip to main content


bud.js config files are the most straight forward way of interfacing with bud.js.

  • The file name should include bud in the name.
  • The module should be located in the project root or the ./config directory.
  • The module can be written in JavaScript, TypeScript, YML or JSON5.
  • JavaScript and TypeScript configurations can either export a configuration function or import bud and use it directly.

By default bud.js uses esbuild-wasm to transpile the config file when authored with TypeScript.

If you prefer you can install esbuild and it will be preferred.

The esbuild team advises that using esbuild is faster than esbuild-wasm, but the benefit of esbuild-wasm is that it doesn't need to be built during installation.

Example configurations

import type {Bud} from '@roots/bud'

export default async (bud: Bud) => {
bud.entry(`app`, [`app.js`, `app.css`])

Importing bud.js directly

You can import bud.js directly and use it in your configuration.

import {bud} from '@roots/bud'

bud.entry(`app`, [`app.js`, `app.css`])

Using multiple configuration files

It is possible to create more than one bud.js configuration file.

When more than one configuration file is present they are execuetd in the following order:

  1. bud.* - the standard, base configuration.
  2. bud.local.* - local configuration.
  3. bud.{production,development}.* - mode specific configuration. Applied when bud.mode matches.
  4. bud.{production,development}.local.* - mode specific local configuration. Applied when bud.mode matches.

You may want to add bud.local.* to your .gitignore file. This way contributors to your project can make specific overrides using bud.local.* files without affecting the base configuration kept in source control.

Configuring bud.js with JSON and YML

Each key is a reference to a bud.js call. The supplied values are the arguments to that call, expressed as an array.

Calling functions

For example, the following bud.js configuration:

- app
- app.js

is equivalent to:

bud.entry('app', 'app.js')

There is some flexibility here if you are passing a single value and it is NOT an array. So, this is okay:

app: app.js

Since it can easily be interpreted by bud.js as:

- app: app.js

Which is equivalent to a single item in array of arguments, containing an object.

bud.entry({app: 'app.js'})

Conversely, since bud.assets expects an array, the following yml would cause an error:

# This is incorrect
assets: ['src/**/*.html', 'app/**/*.html']

How is bud.js to know whether you intended to pass multiple parameters or a single array? It can't, and so this is the result:

bud.assets('src/**/*.html', 'app/**/*.html') // wrong
// what we wanted: bud.assets(['src/**/*.html', 'app/**/*.html'])

To fix it, we must remember that we are passing an array of the function parameters, and wrap our argument in an array:

- ['src/**/*.html', 'app/**/*.html']

Accessing nested values

You can access nested properties with standard yml indentation:

- '@babel/plugin-transform-runtime'
- {helpers: true}

You can also use dot notation:

- '@babel/plugin-transform-runtime'
- {helpers: true}

Accessing bud values

You can make reference to the bud object with _bud.

splitChunks: _bud.isProduction

You can tap bud with an arrow fn if needed. These functions will be called as they are encountered and supplied with the bud.js instance.

minimize: bud => bud.isProduction

This is the equivalent of:

bud.tap('minimize', bud.isProduction)

Treating a value as a function

If you need to execute some code but don't need the bud object, you can prefix a string with => to indicate that it should be treated as a function. These functions will be called as they are encountered.

This will log 4:

log: => 2 + 2

Handling callbacks

Some functions accept functions as a value. In cases like these wrap the function in an additional => so that the config parser does not call the function itself.

webpackConfig: >
=> config => ({...config, parallelism: 1})

bud.tap and bud.tapAsync can be helpful for dynamic configuration and work like this:

tap: >
=> bud => {
// this is a very flexible
// area to do all sorts of dynamic config stuff

tapAsync: >
=> async bud => {
// same as above but async
bud.log('hi!', '...eventually')

If you're doing a lot of this remember that you can create JS configurations in addition to the yml one.

Configuring bud.js with JSON

You can use JSON5 syntax, similar to what is supported in tsconfig.json.

/** Comments are fine */
entry: ["app", ["app.js"]],
runtime: true,
copyDir: "assets",
babel: {
setPluginOptions: [
{helpers: false, regenerator: false}

If you are doing a lot of dynamic configuration you may find it easier to use YML or JS. Ultimately, it's your choice, but we recommend using yml over json for more complicated configs.