---
last_review_date: "2026-04-05"
---

# Formula Cookbook

A *formula* is a package definition written in Ruby. It can be created with `brew create <URL>` where `<URL>` is a zip or tarball, installed with `brew install <formula>`, and debugged with `brew install --debug --verbose <formula>`. Formulae use the [`Formula` class API](/rubydoc/Formula.html) which provides various Homebrew-specific helpers.

* Table of Contents
{:toc}

## Homebrew terminology

| term                 | description                                                               | example |
| -------------------- | ------------------------------------------------------------------------- | ------- |
| **formula**          | Homebrew package definition that builds from upstream sources             | `/opt/homebrew/Library/Taps/homebrew/homebrew-core/Formula/f/foo.rb` |
| **cask**             | Homebrew package definition that installs pre-compiled binaries built and signed by upstream | `/opt/homebrew/Library/Taps/homebrew/homebrew-cask/Casks/b/bar.rb` |
| **prefix**           | path in which Homebrew is installed                                       | `/opt/homebrew` |
| **keg**              | installation destination directory of a given **formula** version         | `/opt/homebrew/Cellar/foo/0.1` |
| **rack**             | directory containing one or more versioned **kegs**                       | `/opt/homebrew/Cellar/foo` |
| **keg-only**         | a **formula** is *keg-only* if it is not symlinked into Homebrew's prefix | the [`openjdk`](https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/o/openjdk.rb) formula |
| **opt prefix**       | a symlink to the active version of a **keg**                              | `/opt/homebrew/opt/foo` |
| **Cellar**           | directory containing one or more named **racks**                          | `/opt/homebrew/Cellar` |
| **Caskroom**         | directory containing one or more named **casks**                          | `/opt/homebrew/Caskroom` |
| **tap**              | directory (and usually Git repository) of **formulae**, **casks** and/or **external commands**       | `/opt/homebrew/Library/Taps/homebrew/homebrew-core` |
| **bottle**           | pre-built **keg** poured into a **rack** of the **Cellar** instead of building from upstream sources | `qt--6.5.1.ventura.bottle.tar.gz` |
| **tab**              | information about a **keg**, e.g. whether it was poured from a **bottle** or built from source       | `/opt/homebrew/Cellar/foo/0.1/INSTALL_RECEIPT.json` |
| **Brew Bundle**      | a declarative interface to Homebrew                                                                  | `brew 'myservice', restart_service: true` |
| **Brew Services**    | the Homebrew command to manage background services                                                   | `brew services start myservice` |

## An introduction

Homebrew uses Git for storing formulae and contributing to the project.

As of [Homebrew 4.0.0](https://brew.sh/2023/02/16/homebrew-4.0.0/), formulae are downloaded as JSON from <https://formulae.brew.sh> which is automatically regenerated by a scheduled [Homebrew/formulae.brew.sh](https://github.com/Homebrew/formulae.brew.sh) job from the default branch of the Homebrew/homebrew-core repository.

Homebrew installs formulae to the Cellar at `$(brew --cellar)` and then symlinks some of the installation into the prefix at `$(brew --prefix)` (e.g. `/opt/homebrew`) so that other programs can see what's going on. We suggest running `brew ls` on a few of the kegs in your Cellar to see how it is all arranged.

Packages are installed according to their formulae. Read over a simple one, e.g. `brew edit etl` (or [etl.rb](https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/e/etl.rb)) or a more advanced one, e.g. `brew edit git` (or [git.rb](https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/g/git.rb)).

## Basic instructions

Make sure you run `brew update` before you start. This ensures your Homebrew installation is a Git repository.

To create or edit formulae locally, you'll need to first [tap `homebrew/core`](FAQ.md#can-i-edit-formulae-myself) if you haven't previously. This clones the Homebrew/homebrew-core Git repository to `$(brew --repository homebrew/core)`. As you're developing, you'll also need to set `HOMEBREW_NO_INSTALL_FROM_API=1` in your shell environment or before any `install`, `reinstall` or `upgrade` commands to force `brew` to use the local repository instead of the API.

Before submitting a new formula make sure your package:

* meets all our [Acceptable Formulae](Acceptable-Formulae.md) requirements
* isn't already in Homebrew (check `brew search <formula>`)
* isn't already waiting to be merged (check the [issue tracker](https://github.com/Homebrew/homebrew-core/pulls))
* is still supported by upstream (i.e. doesn't require extensive patching)
* has a stable, tagged version (i.e. isn't just a GitHub repository with no versions)
* passes all `brew audit --new --formula <formula>` tests

Before submitting a new formula make sure you read over our [contribution guidelines](https://github.com/Homebrew/brew/blob/HEAD/CONTRIBUTING.md#contributing-to-homebrew).

### Grab the URL

Run `brew create` with a URL to the source tarball:

```sh
brew create https://example.com/foo-0.1.tar.gz
```

This creates `$(brew --repository)/Library/Taps/homebrew/homebrew-core/Formula/f/foo.rb` and opens it in your `EDITOR`.

`brew create --help` lists templates for supported languages and build systems.
Pass the appropriate option to populate useful defaults for the project.

If `brew` said `Warning: Version cannot be determined from URL` when doing the `create` step, you’ll need to explicitly add the correct [`version`](/rubydoc/Formula.html#version-class_method) to the formula and then save the formula.

Homebrew will try to guess the formula’s name from its URL. If it fails to do so you can override this with `brew create <URL> --set-name <name>`.

### Fill in the `homepage`

**We don’t accept formulae without a [`homepage`](/rubydoc/Formula.html#homepage-class_method)!**

An SSL/TLS (https) [`homepage`](/rubydoc/Formula.html#homepage-class_method) is preferred, if one is available.

If a homepage blocks automated requests but works in a browser, record the date it was last checked by a human:

```ruby
homepage "https://www.example.com", browsed: "2026-07-26"
```

This skips automated homepage availability audits for one year. Do not use a future date.

Try to summarise from the [`homepage`](/rubydoc/Formula.html#homepage-class_method) what the formula does in the [`desc`](/rubydoc/Formula.html#desc-class_method)ription. Note that the [`desc`](/rubydoc/Formula.html#desc-class_method)ription is automatically prepended with the formula name when printed.

### Fill in the `license`

**We don’t accept new formulae into Homebrew/homebrew-core without a [`license`](/rubydoc/Formula.html#license-class_method)!**

We only accept formulae that use a licence compatible with the [Debian Free Software Guidelines](https://wiki.debian.org/DFSGLicenses) or are released into the public domain following [DFSG Guidelines on Public Domain software](https://wiki.debian.org/DFSGLicenses#Public_Domain).

Use the licence identifier from the [SPDX License List](https://spdx.org/licenses/) e.g. `license "BSD-2-Clause"`, or use `license :public_domain` for public domain software.

Use `:any_of`, `:all_of` or `:with` to describe complex licence expressions.

* `:any_of` should be used when the user can choose which licence to use.
* `:all_of` should be used when the user must use all licences.
* `:with` should be used to specify a valid SPDX exception.

Add `+` to an identifier to indicate that the formulae can be licensed under later versions of the same licence.

Check out the [Licence Guidelines](Licence-Guidelines.md) for examples of complex licence expressions in Homebrew formulae.

### Check the build system

```sh
HOMEBREW_NO_INSTALL_FROM_API=1 brew install --build-from-source --interactive foo
```

You’re now at a new prompt with the tarball extracted to a temporary sandbox.

Check the package’s `README`. Does the package install with `./configure`, `cmake`, or something else? Delete the commented out `cmake` lines if the package uses `./configure`.

### Check for dependencies

The `README` probably tells you about dependencies and Homebrew or macOS probably already has them. You can check for Homebrew dependencies with `brew search`. Some common dependencies that macOS comes with:

* `libexpat`
* `libGL`
* `libiconv`
* `libpcap`
* `libxml2`
* `python`
* `ruby`

There are plenty of others; check `/usr/lib` for them.

We generally try not to duplicate system libraries and complicated tools in core Homebrew but we do duplicate some commonly used tools.

Special exceptions are OpenSSL and LibreSSL. Things that use either *should* be built using Homebrew’s shipped equivalent and our BrewTestBot's post-install `audit` will warn if it detects you haven't done this.

For `homebrew/core`, keep dependencies minimal and context-dependent.
Prefer dependencies needed to build, test or satisfy current core dependents and avoid optional upstream features that bring in large recursive dependency trees.
When a formula needs both a light default build and a maximal build, Homebrew may accept a separate `*-full` formula.
See the [`homebrew/core` dependency policy](Acceptable-Formulae.md#dependencies-and-full-variants).

**Important:** `$(brew --prefix)/bin` is NOT in the `PATH` during formula installation. If you have dependencies at build time, you must specify them and `brew` will add them to the `PATH` or create a [`Requirement`](/rubydoc/Requirement.html).

### Specifying other formulae as dependencies

```ruby
class Foo < Formula
  # ...

  depends_on "httpd" => [:build, :test]
  depends_on xcode: ["9.3", :build]
  depends_on arch: :x86_64
  depends_on "jpeg"
  depends_on macos: :sonoma
  depends_on "pkgconf"
  depends_on "readline" => :recommended
  depends_on "gtk+" => :optional

  # ...
end
```

A `String` (e.g. `"jpeg"`) specifies a formula dependency.

A `Symbol` (e.g. `:xcode`) specifies a [`Requirement`](/rubydoc/Requirement.html) to restrict installation to systems meeting certain criteria, which can be fulfilled by one or more formulae, casks or other system-wide installed software (e.g. Xcode). Some [`Requirement`](/rubydoc/Requirement.html)s can also take a string or symbol specifying their minimum version that the formula depends on.

* Top-level `depends_on :macos` marks a formula as macOS-only.
* Top-level `depends_on macos: :sonoma` marks a formula as macOS-only and declares the minimum compatible macOS release.
* Top-level `depends_on maximum_macos: :ventura` marks a formula as macOS-only and declares the newest compatible macOS release.
* Top-level `depends_on :linux` marks a formula as Linux-only.

For a formula that supports both macOS and Linux but needs a specific macOS version, put the macOS version requirement inside `on_macos`.

A `Hash` (e.g. `=>`) adds information to a dependency. Given a string or symbol, the value can be one or more of the following values:

* `:build` means this is a build-time only dependency so it can be skipped when installing from a bottle or when listing missing dependencies using `brew missing`.
* `:test` means this is only required when running `brew test`.
* `:optional` (not allowed in `Homebrew/homebrew-core`) generates an implicit `with-foo` option for the formula. This means that, given `depends_on "foo" => :optional`, the user must pass `--with-foo` to use the dependency.
* `:recommended` (not allowed in `Homebrew/homebrew-core`) generates an implicit `without-foo` option, meaning that the dependency is enabled by default and the user must pass `--without-foo` to disable this dependency. The default description can be overridden using the [`option`](/rubydoc/Formula.html#option-class_method) syntax (in this case, the [`option` declaration](#adding-optional-steps) must precede the dependency):

```ruby
option "with-foo", "Compile with foo bindings" # This overrides the generated description if you want to
depends_on "foo" => :optional # Generated description would otherwise be "Build with foo support"
```

* `"<option-name>"` (not allowed in `Homebrew/homebrew-core`) requires a dependency to have been built with the specified option.

### Specifying conflicts with other formulae

Sometimes there’s a hard conflict between formulae that can’t be avoided or circumvented with [`keg_only`](/rubydoc/Formula.html#keg_only-class_method).

A good example for minor conflict is the [`mbedtls`](https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/m/mbedtls.rb) formula, which ships and compiles a "Hello World" executable. This is obviously non-essential to `mbedtls`’s functionality, and as conflict with the popular GNU [`hello`](https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/h/hello.rb) formula would be overkill, we just [remove it](https://github.com/Homebrew/homebrew-core/blob/442f9cc511ce6dfe75b96b2c83749d90dde914d2/Formula/m/mbedtls.rb#L52-L53) during the installation process.

[`pdftohtml`](https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/p/pdftohtml.rb) provides an example of a serious conflict, where each listed formula ships an identically named binary that is essential to functionality, so a [`conflicts_with`](/rubydoc/Formula.html#conflicts_with-class_method) is preferable.

As a general rule, [`conflicts_with`](/rubydoc/Formula.html#conflicts_with-class_method) should be a last-resort option. It’s a fairly blunt instrument.

The syntax for a conflict that can’t be worked around is:

```ruby
conflicts_with "blueduck", because: "yellowduck also ships a duck binary"
```

### Formulae revisions

In Homebrew we sometimes accept formulae updates that don’t include a version bump. These include resource updates, new patches or fixing a security issue with a formula.

Occasionally, these updates require a forced-recompile of the formula itself or its dependents to either ensure formulae continue to function as expected or to close a security issue. This forced-recompile is known as a [`revision`](/rubydoc/Formula.html#revision-class_method) and is inserted underneath the [`homepage`](/rubydoc/Formula.html#homepage-class_method)/[`url`](/rubydoc/Formula.html#url-class_method)/[`sha256`](/rubydoc/Formula.html#sha256-class_method)/[`license`](/rubydoc/Formula.html#license-class_method) block.

When a dependent of a formula fails to build against a new version of that dependency it must receive a [`revision`](/rubydoc/Formula.html#revision-class_method). An example of such failure is in [this issue report](https://github.com/Homebrew/legacy-homebrew/issues/31195) and [its fix](https://github.com/Homebrew/legacy-homebrew/pull/31207).

[`revision`](/rubydoc/Formula.html#revision-class_method)s are also used for formulae that move from the system OpenSSL to the Homebrew-shipped OpenSSL without any other changes to that formula. This ensures users aren’t left exposed to the potential security issues of the outdated OpenSSL. An example of this can be seen in [this commit](https://github.com/Homebrew/homebrew-core/commit/0d4453a91923e6118983961e18d0609e9828a1a4).

#### `compatibility_version`

Use [`compatibility_version`](/rubydoc/Formula.html#compatibility_version-class_method) to record whether a formula update remains compatible with already-built dependents. Homebrew records this in installed tabs so later installs and upgrades can avoid rebuilding dependents unnecessarily when the installed dependency is still known to be compatible. This exists both to reduce the number of dependency upgrades users need and to avoid unnecessary dependent [`revision`](/rubydoc/Formula.html#revision-class_method) bumps.

Bump `compatibility_version` by `1` when a formula update requires any recursive dependent formula to receive a [`revision`](/rubydoc/Formula.html#revision-class_method) bump in the same pull request. If only some dependents need rebuilding, still bump `compatibility_version`; only the dependents that actually need rebuilding should receive a `revision` bump.

Do not change `compatibility_version` for updates that do not require dependent `revision` bumps. It should never decrease and should only increment by `1` at a time.

Use [`brew bump-compatibility-version`](Manpage.md#bump-compatibility-version-options-formula-) to increment `compatibility_version` mechanically.

[`brew audit`](Manpage.md) checks this relationship in both directions. If a formula's `compatibility_version` increases, at least one recursive dependent in the same pull request must also increase `revision` by `1`. If a formula's `revision` increases because a changed recursive dependency also changed versions, that dependency must increase `compatibility_version` by `1`.

These checks are based on dependent `revision` bumps in the pull request, not on general ABI analysis. Homebrew cannot automatically detect every compatibility break that is not covered by linkage or formula tests, so maintainers may still need to bump `compatibility_version` and dependent `revision`s manually when they know a rebuild is required.

### Version scheme changes

Sometimes formulae have version schemes that change such that a direct comparison between two versions no longer produces the correct result. For example, a project might be version `13` and then decide to become `1.0.0`. As `13` is translated to `13.0.0` by our versioning system by default this requires intervention.

When a version scheme of a formula fails to recognise a new version as newer it must receive a [`version_scheme`](/rubydoc/Formula.html#version_scheme-class_method). An example of this can be seen in [this pull request](https://github.com/Homebrew/homebrew-core/pull/4006).

### Double-check for dependencies

When you already have a lot of formulae installed, it's easy to miss a common dependency. You can double-check which libraries a binary links to with the `otool` command (perhaps you need to use `xcrun otool`):

```console
$ otool -L /opt/homebrew/bin/ldapvi
/opt/homebrew/bin/ldapvi:
    /opt/homebrew/opt/openssl/lib/libssl.1.0.0.dylib (compatibility version 1.0.0, current version 1.0.0)
    /opt/homebrew/opt/openssl/lib/libcrypto.1.0.0.dylib (compatibility version 1.0.0, current version 1.0.0)
    /opt/homebrew/lib/libglib-2.0.0.dylib (compatibility version 4201.0.0, current version 4201.0.0)
    /opt/homebrew/opt/gettext/lib/libintl.8.dylib (compatibility version 10.0.0, current version 10.2.0)
    /opt/homebrew/opt/readline/lib/libreadline.6.dylib (compatibility version 6.0.0, current version 6.3.0)
    /opt/homebrew/lib/libpopt.0.dylib (compatibility version 1.0.0, current version 1.0.0)
    /usr/lib/libncurses.5.4.dylib (compatibility version 5.4.0, current version 5.4.0)
    /System/Library/Frameworks/LDAP.framework/Versions/A/LDAP (compatibility version 1.0.0, current version 2.4.0)
    /usr/lib/libresolv.9.dylib (compatibility version 1.0.0, current version 1.0.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1213.0.0)
```

### Changing a dynamic library ID

Use [`change_dylib_id`](/rubydoc/Formula.html#change_dylib_id-instance_method)
inside `install` or `post_install` when one Mach-O dynamic library needs a
non-standard ID. Both the source and its complete new ID are explicit. Set
`resolve_source: true` when the source is a symlink and its target should be
edited. For example:

```ruby
change_dylib_id lib/"libfoo.dylib", opt_lib/"libfoo.dylib"
change_dylib_id lib/"libfoo.dylib", "@rpath/libfoo.1.dylib", resolve_source: true
```

The helper preserves the file's permissions and codesigns the modified library
on Apple Silicon.

### Specifying macOS components as dependencies

If a formula dependency is required on all platforms but can be handled by a component that ships with macOS, specify it with [`uses_from_macos`](/rubydoc/Formula.html#uses_from_macos-class_method). On Linux it acts like [`depends_on`](/rubydoc/Formula.html#depends_on-class_method), while on macOS it's ignored unless the host system is older than the optional `since:` parameter.

For example, to require the `bzip2` formula on Linux while relying on built-in `bzip2` on macOS:

```ruby
uses_from_macos "bzip2"
```

To require the `perl` formula only when building or testing on Linux:

```ruby
uses_from_macos "perl" => [:build, :test]
```

To require the `curl` formula on Linux and pre-macOS 12:

```ruby
uses_from_macos "curl", since: :monterey
```

### Language-specific dependencies

Use [Language-Specific Formulae](Language-Specific-Formulae.md) for Python, Node.js, Java and Ruby dependency and installation patterns.
Use [`resource`](/rubydoc/Formula.html#resource-class_method) blocks when dependencies need separate immutable URLs and SHA-256 checksums.
Do not rely on packages installed in the contributor's global language environment.

### Install the formula

```sh
HOMEBREW_NO_INSTALL_FROM_API=1 brew install --build-from-source --verbose --debug foo
```

`--debug` will ask you to open an interactive shell if the build fails so you can try to figure out what went wrong.

Check the top of the e.g. `./configure` output. Some configure scripts do not recognise e.g. `--disable-debug`. If you see a warning about it, remove the option from the formula.

### Add a test to the formula

Add a valid test to the [`test do`](/rubydoc/Formula.html#test-class_method) block of the formula. This will be run by `brew test foo` and [BrewTestBot](BrewTestBot.md).

The [`test do`](/rubydoc/Formula.html#test-class_method) block automatically creates and changes to a temporary directory which is deleted after run. You can access this [`Pathname`](/rubydoc/Pathname.html) with the [`testpath`](/rubydoc/Formula.html#testpath-instance_method) function. The environment variable `HOME` is set to [`testpath`](/rubydoc/Formula.html#testpath-instance_method) within the [`test do`](/rubydoc/Formula.html#test-class_method) block.

We want tests that don't require any user input and test the basic functionality of the application. For example `foo build-foo input.foo` is a good test and (despite their widespread use) `foo --version` and `foo --help` are bad tests. However, a bad test is better than no test at all.

See the [`cmake`](https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/c/cmake.rb) formula for an example of a good test. It writes a basic `CMakeLists.txt` file into the test directory then calls CMake to generate Makefiles. This test checks that CMake doesn't e.g. segfault during basic operation.

You can check that the output is as expected with `assert_equal` or `assert_match` on the output of the formula's [assertions](/rubydoc/Homebrew/Assertions.html) such as in this example from the [`envv`](https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/e/envv.rb) formula:

```ruby
assert_equal "mylist=A:C; export mylist", shell_output("#{bin}/envv del mylist B").strip
```

You can also check that an output file was created:

```ruby
assert_path_exists testpath/"output.txt"
```

Some advice for specific cases:

* If the formula is a library, compile and run some simple code that links against it. It could be taken from upstream's documentation / source examples. A good example is [`tinyxml2`](https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/t/tinyxml2.rb)'s test, which writes a small C++ source file into the test directory, compiles and links it against the tinyxml2 library and finally checks that the resulting program runs successfully.
* If the formula is for a GUI program, try to find some function that runs as command-line only, like a format conversion, reading or displaying a config file, etc.
* If the software cannot function without credentials or requires a virtual machine, docker instance, etc. to run, a test could be to try to connect with invalid credentials (or without credentials) and confirm that it fails as expected. This is preferred over mocking a dependency.
* Homebrew comes with a number of [standard test fixtures](https://github.com/Homebrew/brew/tree/HEAD/Library/Homebrew/test/support/fixtures), including numerous sample images, sounds, and documents in various formats. You can get the file path to a test fixture with e.g. `test_fixtures("test.svg")`.
* If your test requires a test file that isn't a standard test fixture, you can install it from a source repository during the `test` phase with a [`resource`](/rubydoc/Formula.html#resource-class_method) block, like this:

```ruby
test do
  resource "testdata" do
    url "https://example.com/input.foo"
    sha256 "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
  end

  resource("testdata").stage do
    assert_match "OK", shell_output("#{bin}/foo build-foo input.foo")
  end
end
```

* If the binary only writes to `stderr`, you can redirect `stderr` to `stdout` for assertions with `shell_output`. For example:

```ruby
test do
  assert_match "Output on stderr", shell_output("#{bin}/formula-program 2>&1", 2)
end
```

### Manuals

Homebrew expects to find manual pages in `#{prefix}/share/man/...`, and not in `#{prefix}/man/...`.

Some software installs to `man` instead of `share/man`, so check the output and add a `"--mandir=#{man}"` to the `./configure` line if needed.

### Caveats

In case there are specific issues with the Homebrew packaging (compared to how the software is installed from other sources) a `caveats` block can be added to the formula to warn users. This can indicate non-standard install paths, like this example from the [`ruby`](https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/r/ruby.rb) formula:

    ==> Caveats
    By default, binaries installed by gem will be placed into:
      /opt/homebrew/lib/ruby/gems/3.4.0/bin

    You may want to add this to your PATH.

### A quick word on naming

Name the formula like the project markets the product. So it’s `pkgconf`, not `pkgconfig`; `sdl_mixer`, not `sdl-mixer` or `sdlmixer`.

The only exception is software such as “Apache Ant”. Apache puts “Apache” in front of everything, but we use the formula name `ant`. We only include the prefix in cases such as `gnuplot`, where it is part of the name, and `gnu-go`, because everyone calls it “GNU Go” and not just “Go”. The word “Go” is too common and there are too many implementations of it.

If you’re not sure about the name, check its homepage, Wikipedia page and [what Debian calls it](https://www.debian.org/distrib/packages).

When Homebrew already has a formula called `foo` we typically do not accept requests to replace that formula with something else also named `foo`. This is to avoid both confusing and surprising users’ expectations.

When two formulae share an upstream name, e.g. [AESCrypt](https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/a/aescrypt.rb) and [AES Crypt](https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/a/aescrypt-packetizer.rb) the newer formula must typically adapt its name to avoid conflict with the current formula.

If you’re *still* not sure, just commit. We’ll apply some arbitrary rule and make a decision 😉.

When importing classes, Homebrew will require the formula and then create an instance of the class. It does this by assuming the formula name can be directly converted to the class name using a `regexp`. The rules are simple:

* `foo-bar.rb` => `FooBar`
* `foobar.rb` => `Foobar`

Thus, if you change the name of the class, you must also rename the file. Filenames should be all lowercase, and class names should be the strict CamelCase equivalent, e.g. formulae `gnu-go` and `sdl_mixer` become classes `GnuGo` and `SdlMixer`, even if part of their name is an acronym.

Add aliases by creating symlinks in an `Aliases` directory in the tap root.

### Audit the formula

You can run `brew audit --strict --online` to test formulae for adherence to Homebrew house style, which is loosely based on the [Ruby Style Guide](https://github.com/rubocop-hq/ruby-style-guide#the-ruby-style-guide). The `audit` command includes warnings for trailing whitespace, preferred URLs for certain source hosts, and many other style issues. Fixing these warnings before committing will make the process a lot quicker for everyone.

New formulae being submitted to Homebrew should run `brew audit --new --formula foo`. This command is performed by BrewTestBot on new submissions as part of the automated build and test process, and highlights more potential issues than the standard audit.

Use `brew info` and check if the version guessed by Homebrew from the URL is correct. Add an explicit [`version`](/rubydoc/Formula.html#version-class_method) if not.

### Commit

Everything is built on Git, so contribution is easy:

```sh
brew update # required in more ways than you think (initialises the Homebrew/brew Git repository if you don't already have it)
cd "$(brew --repository homebrew/core)"
# Create a new git branch for your formula so your pull request is easy to
# modify if any changes come up during review.
git checkout -b <some-descriptive-name> origin/HEAD
git add Formula/f/foo.rb
git commit
```

The established standard for Git commit messages is:

* the first line is a commit summary of *50 characters or less*
* two (2) newlines, then
* explain the commit thoroughly.

At Homebrew, we require the name of the formula up front like so: `foobar 7.3 (new formula)`.

This may seem crazy short, but you’ll find that forcing yourself to summarise the commit encourages you to be atomic and concise. If you can’t summarise it in 50 to 80 characters, you’re probably trying to commit two commits as one. For a more thorough explanation, please read Tim Pope’s excellent blog post, [A Note About Git Commit Messages](https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html).

The required commit message format for simple version updates is `foobar 7.3` and for fixes is `foobar: fix flibble matrix.`. Please squash your commits into one with this message format, otherwise your PR will be replaced by our autosquash workflow.

Ensure you reference any relevant GitHub issue, e.g. `Closes #12345` in the commit message. Homebrew’s history is the first thing future contributors will look to when trying to understand the current state of formulae they’re interested in.

### Push

Now you just need to push your commit to GitHub.

If you haven’t forked Homebrew yet, [go to the Homebrew/homebrew-core repository and hit the Fork button](https://github.com/Homebrew/homebrew-core).

If you have already forked Homebrew on GitHub, then you can manually push (just make sure you have been pulling from the `Homebrew/homebrew-core` default branch):

```sh
git push https://github.com/myname/homebrew-core/ <what-you-named-your-branch>
```

Now, [open a pull request](How-To-Open-a-Homebrew-Pull-Request.md) for your changes.

* One formula per commit; one commit per formula.
* Keep merge commits out of the pull request.

## Convenience tools

### Messaging

Three commands are provided for displaying informational messages to the user:

* `ohai` for general info
* `opoo` for warning messages
* `odie` for error messages and immediately exiting

Use `odie` when you need to exit a formula gracefully for any reason. For example:

```ruby
if build.head?
  lib_jar = Dir["cfr-*-SNAPSHOT.jar"]
  doc_jar = Dir["cfr-*-SNAPSHOT-javadoc.jar"]
  odie "Unexpected number of artifacts!" if (lib_jar.length != 1) || (doc_jar.length != 1)
end
```

### Standard arguments

For any formula using certain well-known build systems, there will be arguments that should be passed during compilation so that the build conforms to Homebrew standards. These have been collected into a set of `std_*_args` methods. Detailed information about each of those methods can be found in the [`Formula` class API](/rubydoc/Formula.html) documentation.

Most of these methods accept parameters to customise their output. For example, to set the install prefix to [**`libexec`**](#variables-for-directory-locations) for `configure` or `cmake`:

```ruby
system "./configure", *std_configure_args(prefix: libexec)
system "cmake", "-S", ".", "-B", "build", *std_cmake_args(install_prefix: libexec)
```

Homebrew provides helpers for Cabal, Cargo, CMake, Autoconf, Go, Meson, npm, pip and Zig builds.
Pass the helper directly to the build command rather than copying its expanded argument list, because defaults change with Homebrew's build and security policy.
Use the [`Formula` class API](/rubydoc/Formula.html) for each helper's current signature, supported overrides and generated arguments.

Use `std_npm_args` for npm installations as described in [Language-Specific Formulae](Language-Specific-Formulae.md#standard-npm-installation).
Use `std_pip_args` for direct pip installations as described in [Language-Specific Formulae](Language-Specific-Formulae.md#installing-python-bindings).
`std_go_args` also provides supported ways to set `-ldflags`, `-gcflags` and `-tags`; see the [`babelfish`](https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/b/babelfish.rb) and [`wazero`](https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/w/wazero.rb) formulae for current examples.

### `bin.install "foo"`

You’ll see stuff like this in some formulae. This moves the file `foo` into the formula’s `bin` directory (`/opt/homebrew/Cellar/pkg/0.1/bin`) and makes it executable (`chmod 0555 foo`). Variables for the most common [directory locations](#variables-for-directory-locations) are available.

You can also rename the file during the installation process. This can be useful for adding a prefix to binaries that would otherwise cause conflicts with another formula, or for removing a file extension. For example, to install `foo.py` into the formula's `bin` directory (`/opt/homebrew/Cellar/pkg/0.1/bin`) as just `foo` instead of `foo.py`:

```ruby
bin.install "foo.py" => "foo"
```

### `inreplace`

[`inreplace`](/rubydoc/Utils/Inreplace.html) is a convenience function that can edit files in-place. For example:

```ruby
inreplace "path", before, after
```

`before` and `after` can be strings or regular expressions. You should use the block form if you need to make multiple replacements in a file:

```ruby
inreplace "path" do |s|
  s.gsub!(/foo/, "bar")
  s.gsub! "123", "456"
end
```

Make sure you modify `s`! This block ignores the returned value.

[`inreplace`](/rubydoc/Utils/Inreplace.html) should be used instead of patches when patching something that will never be accepted upstream, e.g. making the software’s build system respect Homebrew’s installation hierarchy. If it's something that affects both Homebrew and MacPorts (i.e. macOS specific) it should be turned into an upstream submitted patch instead.

If you need to modify variables in a `Makefile`, rather than using [`change_make_var!`](/rubydoc/StringInreplaceExtension.html#change_make_var!-instance_method) within an [`inreplace`](/rubydoc/Utils/Inreplace.html), try passing them as arguments to `make`:

```ruby
system "make", "target", "VAR2=value1", "VAR2=value2", "VAR3=values can have spaces"
```

```ruby
system "make", "CC=#{ENV.cc}", "PREFIX=#{prefix}"
```

Note that values *can* contain unescaped spaces if you use the multiple-argument form of `system`.

## Patches

While [`patch`](/rubydoc/Formula.html#patch-class_method)es should generally be avoided, sometimes they are temporarily necessary.

When [`patch`](/rubydoc/Formula.html#patch-class_method)ing (i.e. fixing header file inclusion, fixing compiler warnings, etc.) the first thing to do is check whether the upstream project is aware of the issue. If not, file a bug report and/or submit your patch for inclusion. We may sometimes still accept your patch before it was submitted upstream but by getting the ball rolling on fixing the upstream issue you reduce the length of time we have to carry the patch around.

*Always justify a [`patch`](/rubydoc/Formula.html#patch-class_method) with a code comment!* Otherwise, nobody will know when it is safe to remove the patch, or safe to leave it in when updating the formula. The comment should include a link to the relevant upstream issue(s).

External [`patch`](/rubydoc/Formula.html#patch-class_method)es can be declared using resource-style blocks:

```ruby
patch do
  url "https://example.com/example_patch.diff"
  sha256 "85cc828a96735bdafcf29eb6291ca91bac846579bcef7308536e0c875d6c81d7"
end
```

A strip level of `-p1` is assumed. It can be overridden using a symbol argument:

```ruby
patch :p0 do
  url "https://example.com/example_patch.diff"
  sha256 "85cc828a96735bdafcf29eb6291ca91bac846579bcef7308536e0c875d6c81d7"
end
```

[`patch`](/rubydoc/Formula.html#patch-class_method)es can be declared in [`stable`](/rubydoc/Formula.html#stable-class_method) and [`head`](/rubydoc/Formula.html#head-class_method) blocks. Always use a block instead of a conditional, i.e. `stable do ... end` instead of `if build.stable? then ... end`.

```ruby
stable do
  # ...

  patch do
    url "https://example.com/example_patch.diff"
    sha256 "85cc828a96735bdafcf29eb6291ca91bac846579bcef7308536e0c875d6c81d7"
  end
end
```

Embedded (**END**) patches can be declared like so:

```ruby
patch :DATA
patch :p0, :DATA
```

with the patch data included at the end of the file:

    __END__
    diff --git a/foo/showfigfonts b/foo/showfigfonts
    index 643c60b..543379c 100644
    --- a/foo/showfigfonts
    +++ b/foo/showfigfonts
    @@ -14,6 +14,7 @@
    …

Patches can also be embedded by passing a string. This makes it possible to provide multiple embedded patches while making only some of them conditional.

```ruby
patch :p0, "..."
```

In embedded and external patches, the string "@@HOMEBREW\_PREFIX@@" is replaced with the value of the constant `HOMEBREW_PREFIX` before the patch is applied.

### Annotating patches

External and `file` patches can optionally declare a `type` and what they `resolve`. These annotations are exposed in `brew info --json` and the formula API for downstream tools such as SBOM generators and vulnerability scanners; they have no effect on how the patch is applied.

`type` describes where the patch came from, using the `pedigree.patches` terminology from the [CycloneDX specification](https://cyclonedx.org/docs/1.6/json/).

`:backport` takes code from a newer version of the same software and applies it to the older version Homebrew ships. Most upstream-commit patches fall here. For example, `innoextract` applies an upstream commit that fixes the build with CMake 4 ahead of the next release:

```ruby
patch do
  url "https://github.com/dscharrer/innoextract/commit/83d0bf4365b09ddd17dddb400ba5d262ddf16fb8.patch?full_index=1"
  sha256 "fe5299d1fdea5c66287aef2f70fee41d86aedc460c5b165da621d699353db07d"
  type :backport
end
```

`:cherry_pick` selectively applies an upstream commit that is *not* from a strictly newer release line, such as a fix that only exists on a maintenance or release branch. `gecode` pulls Qt 6 support from the upstream `release/6.3.0` branch rather than `master`:

```ruby
patch do
  url "https://github.com/Gecode/gecode/commit/c0ca0e5f4406099be22f87236ea8547c2f31ded3.patch?full_index=1"
  sha256 "233b266a943c0619b027b4cb19912e2a8c9d1f8e4323a3627765cb32b47c59fe"
  type :cherry_pick
end
```

When in doubt between `:backport` and `:cherry_pick`, prefer `:backport` for anything taken from the upstream development tip.

`:unofficial` is a patch not authored by the upstream maintainers, such as a Homebrew- or distribution-specific build fix. As with all Homebrew patches, an `:unofficial` patch should have been [reported and/or submitted upstream](#patches) where practical. `unzip` carries a Debian-maintained patch set because upstream Info-ZIP no longer makes releases:

```ruby
patch do
  url "https://archive.ubuntu.com/ubuntu/pool/main/u/unzip/unzip_6.0-28ubuntu4.1.debian.tar.xz"
  sha256 "d123c8e6972dbdd17ba1a4920fb57ed2ede9237dbae149dcbf55df829c77baf3"
  type :unofficial
  apply "patches/04-handle-pkware-verification-bit.patch",
        "patches/05-fix-uid-gid-handling.patch",
        "patches/13-remove-build-date.patch"
end
```

`resolves` records what the patch fixes: one or more CVE identifiers (`CVE-YYYY-NNNN`), GHSA identifiers (`GHSA-xxxx-xxxx-xxxx`), OSV identifiers (`OSV-YYYY-NNNN`) or issue/PR URLs. CVE identifiers are also inferred automatically from the patch `url`, `apply` paths and `file` path, so a Debian-style `CVE-2016-2399.patch` is picked up without an explicit `resolves`.

```ruby
patch do
  url "https://deb.debian.org/debian/pool/main/libq/libquicktime/libquicktime_1.2.4-12.debian.tar.xz"
  sha256 "e5b5fa3ec8391b92554d04528568d04ea9eb5145835e0c246eac7961c891a91a"
  type :backport
  resolves "CVE-2016-2399", "CVE-2017-9122"
  apply "patches/CVE-2016-2399.patch", "patches/CVE-2017-9122_et_al.patch"
end
```

For non-security build fixes, pass the upstream issue or PR URL instead:

```ruby
patch do
  url "https://github.com/dscharrer/innoextract/commit/264c2fe6b84f90f6290c670e5f676660ec7b2387.patch?full_index=1"
  sha256 "f968a9c0521083dd4076ce5eed56127099a9c9888113fc50f476b914396045cc"
  type :backport
  resolves "https://github.com/dscharrer/innoextract/pull/169"
end
```

### Creating the diff

```sh
HOMEBREW_NO_INSTALL_FROM_API=1 brew install --interactive --git foo
# (make some edits)
git diff | pbcopy
brew edit foo
```

Now just paste into the formula after `__END__`.

Instead of `git diff | pbcopy`, for some editors `git diff >> path/to/your/formula/foo.rb` might help you ensure that the patch is not altered, e.g. whitespace removal, indentation changes, etc.

## Advanced formula tricks

See the [`Formula` class API](/rubydoc/Formula.html) documentation for the full list of methods available within a formula. If anything isn’t clear, you can usually figure it out by `grep`ping the `$(brew --repository homebrew/core)` directory for examples. Please submit a pull request to amend this document if you think it will help!

### Handling different system configurations

Often, formulae need different dependencies, resources, patches, conflicts, deprecations or `keg_only` statuses on different OSes and architectures. In these cases, the components can be nested inside `on_macos`, `on_linux`, `on_arm` or `on_intel` blocks. For example, here's how to add `gcc` as a Linux-only dependency:

```ruby
on_linux do
  depends_on "gcc"
end
```

Components can also be declared for specific macOS versions or version ranges. For example, to declare a dependency only on Sequoia, nest the `depends_on` call inside an `on_sequoia` block. Add an `:or_older` or `:or_newer` parameter to the `on_sequoia` method to add the dependency to all macOS versions that meet the condition. For example, to add `gettext` as a build dependency on Sequoia and all later macOS versions, use:

```ruby
on_sequoia :or_newer do
  depends_on "gettext" => :build
end
```

Sometimes, a dependency is needed on certain macOS versions *and* on Linux. In these cases, a special `on_system` method can be used:

```ruby
on_system :linux, macos: :sonoma_or_older do
  depends_on "gettext" => :build
end
```

To check multiple conditions, nest the corresponding blocks. For example, the following code adds a `gettext` build dependency when on ARM *and* macOS:

```ruby
on_macos do
  on_arm do
    depends_on "gettext" => :build
  end
end
```

#### Inside `def install` and `test do`

Inside `def install` and `test do`, don't use these `on_*` methods. Instead, use `if` statements and the following conditionals:

* `OS.mac?` and `OS.linux?` return `true` or `false` based on the OS
* `Hardware::CPU.arm?` and `Hardware::CPU.intel?` return `true` or `false` based on the arch
* `MacOS.version` returns the current macOS version. Use `==`, `<=` or `>=` to compare to symbols corresponding to macOS versions (e.g. `if MacOS.version >= :tahoe`)

See the [`icoutils`](https://github.com/Homebrew/homebrew-core/blob/442f9cc511ce6dfe75b96b2c83749d90dde914d2/Formula/i/icoutils.rb#L36) formula for an example.

### `livecheck` blocks

When `brew livecheck` is unable to identify versions for a formula, we can control its behaviour using a `livecheck` block. Here is a simple example to check a page for links containing a filename like `example-1.2.tar.gz`:

```ruby
livecheck do
  url "https://www.example.com/downloads/"
  regex(/href=.*?example[._-]v?(\d+(?:\.\d+)+)\.t/i)
end
```

For `url`/`regex` guidelines and additional `livecheck` block examples, refer to the [`brew livecheck`](Brew-Livecheck.md) documentation. For more technical information on the methods used in a `livecheck` block, please refer to the [`Livecheck` class](/rubydoc/Livecheck.html) documentation.

### Excluding formulae from autobumping

By default, all new formulae in the `Homebrew/homebrew-core` repository are autobumped. This means that future updates are handled automatically by Homebrew CI jobs, and contributors do not have to submit pull requests.

Sometimes, we want to exclude a formula from this list, for one reason or another. This can be done by adding the `no_autobump!` method in the formula definition; a reason must be provided with the `because:` parameter. It accepts a string or a symbol that corresponds to a preset reason, for example:

```ruby
no_autobump! because: :bumped_by_upstream
```

A complete list of allowed symbols can be found in [`NO_AUTOBUMP_REASONS_LIST`](/rubydoc/top-level-namespace.html#NO_AUTOBUMP_REASONS_LIST-constant).

See our [Autobump](Autobump.md) documentation for more information about the autobump process.

### URL download strategies

When parsing a download URL, Homebrew auto-detects the resource type it points to, whether archive (e.g. tarball, zip) or version control repository (e.g. Git, Subversion, Mercurial) and chooses an appropriate download strategy. Some strategies can be passed additional options to alter what's downloaded. For example, to fetch a formula's source code and infer its version number from a specific tag in a Git repository (useful for packages that rely on Git submodules), specify [`url`](/rubydoc/Formula.html#url-class_method) with the `:tag` and `:revision` options, like so:

```ruby
class Foo < Formula
  # ...
  url "https://github.com/some/package.git",
      tag:      "v1.6.2",
      revision: "344cd2ee3463abab4c16ac0f9529a846314932a2"
end
```

If fetching from a Subversion or Mercurial repository, specify `revision` and `version` separately:

```ruby
class Bar < Formula
  # ...
  url "https://svn.code.sf.net/p/package/code/stable", revision: "4687"
  version "12.1.8"
end
```

To fetch specific revisions of Subversion externals, specify `revisions`:

```ruby
class Baz < Formula
  # ...
  url "svn://source.something.org/package/trunk/",
      revisions: { trunk: "22916", "libsomething" => "31045" }
  version "7.2.11"
end
```

If not inferable, specify which of Homebrew's built-in download strategies to use with the `using:` option. For example:

```ruby
class Nginx < Formula
  desc "HTTP(S) server and reverse proxy, and IMAP/POP3 proxy server"
  homepage "https://nginx.org/"
  url "https://nginx.org/download/nginx-1.23.2.tar.gz", using: :homebrew_curl
  sha256 "a80cc272d3d72aaee70aa8b517b4862a635c0256790434dbfc4d618a999b0b46"
  head "https://hg.nginx.org/nginx/", using: :hg
end
```

Homebrew offers these anonymous download strategies.

| `using:` value   | download strategy                | requirements |
| ---------------- | -------------------------------- | ------------ |
| `:bzr`           | fetch from Bazaar repository     | `breezy` installed |
| `:curl`          | download using `curl` (default)  | |
| `:cvs`           | fetch from CVS repository        | `cvs` installed |
| `:fossil`        | fetch from Fossil repository     | `fossil` installed |
| `:git`           | fetch from Git repository        | `git` installed |
| `:hg`            | fetch from Mercurial repository  | `hg` installed |
| `:homebrew_curl` | download using brewed `curl`     | `curl` installed |
| `:nounzip`       | download without decompressing   | |
| `:post`          | download using `curl` via POST   | `data:` [hash of parameters](Cask-Cookbook.md#additional-url-parameters) |
| `:svn`           | fetch from Subversion repository | `svn` installed |

If you need more control over the way files are downloaded and staged, you can create a custom download strategy and specify it with the `:using` option:

```ruby
class MyDownloadStrategy < SomeHomebrewDownloadStrategy
  def fetch(timeout: nil, **options)
    opoo "Unhandled options in #{self.class}#fetch: #{options.keys.join(", ")}" unless options.empty?

    # downloads output to `temporary_path`
  end
end

class Foo < Formula
  url "something", using: MyDownloadStrategy
end
```

### Unstable versions (`head`)

Formulae can specify an alternate download for the upstream project's development/cutting-edge source (e.g. `master`/`main`/`trunk`) using [`head`](/rubydoc/Formula.html#head-class_method), which can be activated by passing `--HEAD` when installing. Specifying it is done in the same manner as [`url`](/rubydoc/Formula.html#url-class_method), with added conventions for fetching from version control repositories:

* Git repositories **must always** specify `branch:`. If the repository is very large, specify `only_path` to [limit the checkout to one path](Cask-Cookbook.md#git-urls).

```ruby
head "https://github.com/some/package.git", branch: "main"
```

* Mercurial repositories need `branch:` specified to fetch a branch other than "default".

* Subversion repositories can specify `trust_cert: true` to [skip interactive certificate prompts](Cask-Cookbook.md#subversion-urls).

* CVS repositories can specify `module:` to check out a specific module.

You can also bundle the URL and any `head`-specific dependencies and resources in a `head do` block.

```ruby
class Foo < Formula
  # ...

  head do
    url "https://hg.sr.ht/~user/foo", using: :hg, branch: "develop"

    depends_on "pkgconf" => :build

    resource "package" do
      url "https://github.com/other/package.git", branch: "main"
    end
  end
end
```

You can test whether the [`head`](/rubydoc/Formula.html#head-class_method) is being built with `build.head?` in the `install` method.

### Compiler selection

Sometimes a package fails to build when using a certain compiler. Since the [supported Xcode and Command Line Tools versions](Installation.md#macos-requirements) no longer include a GCC compiler we cannot simply force the use of GCC. Instead, the correct way to declare this is with the [`fails_with`](/rubydoc/Formula.html#fails_with-class_method) DSL method. A properly constructed [`fails_with`](/rubydoc/Formula.html#fails_with-class_method) block documents the latest compiler build version known to cause compilation to fail, and the cause of the failure. For example:

```ruby
fails_with :clang do
  build 211
  cause "Miscompilation resulting in segfault on queries"
end

fails_with :gcc do
  version "5" # fails with GCC 5.x and earlier
  cause "Requires C++17 support"
end

fails_with gcc: "7" do
  version "7.1" # fails with GCC 7.0 and 7.1 but not 7.2, or any other major GCC version
  cause <<-EOS
    warning: dereferencing type-punned pointer will break strict-aliasing rules
    Fixed in GCC 7.2, see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=42136
  EOS
end
```

For `:clang`, `build` takes an integer (you can find this number in your `brew --config` output), while `:gcc` uses either just `version` which takes a string to indicate the last problematic GCC version, or a major version argument combined with `version` to single out a range of specific GCC releases. `cause` takes a string, and the use of heredocs is encouraged to improve readability and allow for more comprehensive documentation.

[`fails_with`](/rubydoc/Formula.html#fails_with-class_method) declarations can be used with any of `:gcc`, `:llvm`, and `:clang`. Homebrew will use this information to select a working compiler (if one is available).

### Just moving some files

When your code in the install function is run, the current working directory is set to the extracted tarball. This makes it easy to just move some files:

```ruby
prefix.install "file1", "file2"
```

Or everything:

```ruby
prefix.install Dir["output/*"]
```

Or just the tarball's top-level files like README, LICENSE etc.:

```ruby
prefix.install_metafiles
```

Generally we'd rather you were specific about which files or directories need to be installed rather than installing everything.

#### Variables for directory locations

| name                  | default path                                   | example |
| --------------------- | ---------------------------------------------- | ------- |
| **`HOMEBREW_PREFIX`** | same as output of `$(brew --prefix)`           | `/opt/homebrew` |
| **`etc`**             | `#{HOMEBREW_PREFIX}/etc`                       | `/opt/homebrew/etc` |
| **`pkgetc`**          | `#{HOMEBREW_PREFIX}/etc/#{name}`               | `/opt/homebrew/etc/foo` |
| **`var`**             | `#{HOMEBREW_PREFIX}/var`                       | `/opt/homebrew/var` |
| **`prefix`**          | `#{HOMEBREW_PREFIX}/Cellar/#{name}/#{version}` | `/opt/homebrew/Cellar/foo/0.1` |
| **`opt_prefix`**      | `#{HOMEBREW_PREFIX}/opt/#{name}`               | `/opt/homebrew/opt/foo` |
| **`bin`**             | `#{prefix}/bin`                                | `/opt/homebrew/Cellar/foo/0.1/bin` |
| **`opt_bin`**         | `#{opt_prefix}/bin`                            | `/opt/homebrew/opt/foo/bin` |
| **`doc`**             | `#{prefix}/share/doc/#{name}`                  | `/opt/homebrew/Cellar/foo/0.1/share/doc/foo` |
| **`include`**         | `#{prefix}/include`                            | `/opt/homebrew/Cellar/foo/0.1/include` |
| **`opt_include`**     | `#{opt_prefix}/include`                        | `/opt/homebrew/opt/foo/include` |
| **`info`**            | `#{prefix}/share/info`                         | `/opt/homebrew/Cellar/foo/0.1/share/info` |
| **`lib`**             | `#{prefix}/lib`                                | `/opt/homebrew/Cellar/foo/0.1/lib` |
| **`opt_lib`**         | `#{opt_prefix}/lib`                            | `/opt/homebrew/opt/foo/lib` |
| **`libexec`**         | `#{prefix}/libexec`                            | `/opt/homebrew/Cellar/foo/0.1/libexec` |
| **`opt_libexec`**     | `#{opt_prefix}/libexec`                        | `/opt/homebrew/opt/foo/libexec` |
| **`man`**             | `#{prefix}/share/man`                          | `/opt/homebrew/Cellar/foo/0.1/share/man` |
| **`man[1-8]`**        | `#{prefix}/share/man/man[1-8]`                 | `/opt/homebrew/Cellar/foo/0.1/share/man/man[1-8]` |
| **`sbin`**            | `#{prefix}/sbin`                               | `/opt/homebrew/Cellar/foo/0.1/sbin` |
| **`opt_sbin`**        | `#{opt_prefix}/sbin`                           | `/opt/homebrew/opt/foo/sbin` |
| **`share`**           | `#{prefix}/share`                              | `/opt/homebrew/Cellar/foo/0.1/share` |
| **`opt_share`**       | `#{opt_prefix}/share`                          | `/opt/homebrew/opt/foo/share` |
| **`pkgshare`**        | `#{prefix}/share/#{name}`                      | `/opt/homebrew/Cellar/foo/0.1/share/foo` |
| **`opt_pkgshare`**    | `#{opt_prefix}/share/#{name}`                  | `/opt/homebrew/opt/foo/share/foo` |
| **`elisp`**           | `#{prefix}/share/emacs/site-lisp/#{name}`      | `/opt/homebrew/Cellar/foo/0.1/share/emacs/site-lisp/foo` |
| **`opt_elisp`**       | `#{opt_prefix}/share/emacs/site-lisp/#{name}`  | `/opt/homebrew/opt/foo/share/emacs/site-lisp/foo` |
| **`frameworks`**      | `#{prefix}/Frameworks`                         | `/opt/homebrew/Cellar/foo/0.1/Frameworks` |
| **`opt_frameworks`**  | `#{opt_prefix}/Frameworks`                     | `/opt/homebrew/opt/foo/Frameworks` |
| **`kext_prefix`**     | `#{prefix}/Library/Extensions`                 | `/opt/homebrew/Cellar/foo/0.1/Library/Extensions` |
| **`bash_completion`** | `#{prefix}/etc/bash_completion.d`              | `/opt/homebrew/Cellar/foo/0.1/etc/bash_completion.d` |
| **`fish_completion`** | `#{prefix}/share/fish/vendor_completions.d`    | `/opt/homebrew/Cellar/foo/0.1/share/fish/vendor_completions.d` |
| **`fish_function`**   | `#{prefix}/share/fish/vendor_functions.d`      | `/opt/homebrew/Cellar/foo/0.1/share/fish/vendor_functions.d` |
| **`zsh_completion`**  | `#{prefix}/share/zsh/site-functions`           | `/opt/homebrew/Cellar/foo/0.1/share/zsh/site-functions` |
| **`zsh_function`**    | `#{prefix}/share/zsh/site-functions`           | `/opt/homebrew/Cellar/foo/0.1/share/zsh/site-functions` |
| **`pwsh_completion`** | `#{prefix}/share/pwsh/completions`             | `/opt/homebrew/Cellar/foo/0.1/share/pwsh/completions` |
| **`buildpath`**       | temporary working directory during builds      | `/private/tmp/foo-20250205-69197-po5981/foo-0.1` |
| **`testpath`**        | temporary working directory during tests       | `/private/tmp/foo-test-20250205-84567-4hfs9m` |

These can be used, for instance, in code such as:

```ruby
bin.install Dir["output/*"]
```

to move binaries into their correct location within the Cellar, and:

```ruby
man.mkpath
```

to create the directory structure for the manual page location.

To install man pages into specific locations, use `man1.install "foo.1", "bar.1"`, `man2.install "foo.2"`, etc.

The `opt_` variants generate paths that are stable between updates, which can be useful for e.g. replacing versioned paths in files:

```ruby
inreplace lib/"pkgconfig/zlib.pc", prefix, opt_prefix
```

Note that in the context of Homebrew, [`libexec`](/rubydoc/Formula.html#libexec-instance_method) is reserved for private use by the formula and therefore is not symlinked into `HOMEBREW_PREFIX`.

### File-level operations

You can use the file utilities provided by Ruby's [`FileUtils`](https://ruby-doc.org/current/stdlibs/fileutils/FileUtils.html). These are included in the [`Formula` class](/rubydoc/Formula.html), so you do not need the `FileUtils.` prefix to use them.

When creating symlinks, take special care to ensure they are *relative* symlinks. This makes it easier to create a relocatable bottle. For example, to create a symlink in `bin` to an executable in `libexec`, use:

```ruby
bin.install_symlink libexec/"name"
```

instead of:

```ruby
ln_s libexec/"name", bin
```

The symlinks created by [`install_symlink`](/rubydoc/Pathname.html#install_symlink-instance_method) are guaranteed to be relative. `ln_s` will only produce a relative symlink when given a relative path.

Several other utilities for Ruby's [`Pathname`](/rubydoc/Pathname.html) can simplify some common operations.

* To perform several operations within a directory, enclose them within a  [`cd <path> do`](/rubydoc/Pathname.html#cd-instance_method) block:

```ruby
cd "src" do
  system "./configure", "--disable-debug", "--prefix=#{prefix}"
  system "make", "install"
end
```

* To surface one or more binaries buried in `libexec` or a macOS `.app` package, use [`write_exec_script`](/rubydoc/Pathname.html#write_exec_script-instance_method) or [`write_jar_script`](/rubydoc/Pathname.html#write_jar_script-instance_method):

```ruby
bin.write_exec_script Dir[libexec/"bin/*"]
bin.write_exec_script prefix/"Package.app/Contents/MacOS/package"
bin.write_jar_script libexec/jar_file, "jarfile", java_version: "11"
```

* For binaries that require setting one or more environment variables to function properly, use [`write_env_script`](/rubydoc/Pathname.html#write_env_script-instance_method) or [`env_script_all_files`](/rubydoc/Pathname.html#env_script_all_files-instance_method):

```ruby
(bin/"binary").write_env_script libexec/"bin/binary", PACKAGE_ROOT: libexec
bin.env_script_all_files(libexec/"bin", PERL5LIB: ENV.fetch("PERL5LIB", nil))
```

### Rewriting a script shebang

Some formulae install executable scripts written in an interpreted language such as Python or Perl. Homebrew provides a `rewrite_shebang` method to rewrite the shebang of a script. This replaces a script's original interpreter path with the one the formula depends on. This guarantees that the correct interpreter is used at execution time. This isn't required if the build system already handles it (e.g. often with `pip` or Perl `ExtUtils::MakeMaker`).

For example, the [`icdiff`](https://github.com/Homebrew/homebrew-core/blob/bc311e91f3a77889e568dec8d3063c3a6cb2965a/Formula/i/icdiff.rb#L18) formula uses this utility. Note that it is necessary to include the utility in the formula; for example with Python one must use `include Language::Python::Shebang`.

### Adding optional steps

**Note:** [`option`](/rubydoc/Formula.html#option-class_method)s are not allowed in Homebrew/homebrew-core as they are not tested by CI.

If you want to add an [`option`](/rubydoc/Formula.html#option-class_method):

```ruby
class Yourformula < Formula
  # ...
  url "https://example.com/yourformula-1.0.tar.gz"
  sha256 "abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc1"
  # ...
  option "with-ham", "Description of the option"
  option "without-spam", "Another description"

  depends_on "bar" => :recommended
  depends_on "foo" => :optional # automatically adds a with-foo option # automatically adds a without-bar option
  # ...
end
```

And then to define the effects the [`option`](/rubydoc/Formula.html#option-class_method)s have:

```ruby
if build.with? "ham"
  # note, no "with" in the option name (it is added by the build.with? method)
end

if build.without? "ham"
  # works as you'd expect. True if `--without-ham` was given.
end
```

[`option`](/rubydoc/Formula.html#option-class_method) names should be prefixed with the words `with` or `without`. For example, an option to run a test suite should be named `--with-test` or `--with-check` rather than `--test`, and an option to enable a shared library `--with-shared` rather than `--shared` or `--enable-shared`. See the [alternative `ffmpeg`](https://github.com/homebrew-ffmpeg/homebrew-ffmpeg/blob/HEAD/Formula/ffmpeg.rb) formula for examples.

[`option`](/rubydoc/Formula.html#option-class_method)s that aren’t `build.with?` or `build.without?` should be deprecated with [`deprecated_option`](/rubydoc/Formula.html#deprecated_option-class_method). See the [`wget`](https://github.com/Homebrew/homebrew-core/blob/3f762b63c6fbbd49191ffdf58574d7e18937d93f/Formula/wget.rb#L27-L31) formula for a historical example.

### Running commands after installation

Formulae in official Homebrew taps must represent post-install work with [`post_install_steps`](/rubydoc/Formula.html#post_install_steps-class_method); new `post_install` methods are rejected. These steps can be re-run separately with `brew postinstall <formula>`, are stored in the JSON API and do not require downloading source formula Ruby. A `post_install_steps` block may only contain the supported step calls with literal arguments. It cannot call the wider formula DSL or arbitrary Ruby code. Homebrew executes the steps with the same post-install sandbox policy.

The legacy `post_install` method remains available temporarily for third-party tap compatibility, but is not an authoring interface for official formulae. A formula cannot define both `post_install` and `post_install_steps`.

```ruby
class Foo < Formula
  # ...
  url "https://example.com/foo-1.0.tar.gz"

  post_install_steps do
    mkdir_p "log/foo", base: :var
    touch "foo/state", base: :var
    move "default.conf", "foo/default.conf"
    symlink "cert.pem", "foo/cert.pem", source_base: :relative
  end
  # ...
end
```

#### File preparation steps

Specify `base:` for paths such as `var`, `etc` or `pkgetc`. File steps with separate source and target paths default those paths to `prefix`; use `source_base:` or `target_base:` to select another formula path and `source_base: :relative` for relative symlink sources.

* `mkdir_p`: create a directory and any missing parents; example: `mkdir_p "log/foo", base: :var`.
* `touch`: create or update a file timestamp; example: `touch "foo/state", base: :var`.
* `move`: move one file or directory; example: `move "default.conf", "foo/default.conf"`.
* `move_contents`: move the contents of one directory into another; example: `move_contents "defaults", "foo/defaults"`.
* `copy`: copy a file or, with `recursive: true`, a directory; example: `copy "default.conf", "foo/default.conf"`.
* `remove`: remove one or more paths; example: `remove ["old.conf", "foo/*.bak"], base: :var`. Use `recursive: true` for directories.
* `inreplace`: replace a string or regular expression in a file; example: `inreplace "foo.conf", "@PREFIX@", "{{HOMEBREW_PREFIX}}", base: :etc`. Its `audit_result:` and `global:` options match the formula `inreplace` helper.
* `symlink`: create a symlink; example: `symlink "cert.pem", "foo/cert.pem", source_base: :relative`.
* `symlink_tree`: recursively symlink a directory's contents while preserving real target directories.
* `symlink_children`: symlink each direct child of a directory, optionally adding a `prefix:` or `suffix:`.
* `set_permissions`: change existing path permissions; example: `set_permissions "foo", "0755", base: :var`.
* `change_dylib_id`: change one Mach-O dynamic library ID; pass the complete source and new ID, use `resolve_source: true` for a source symlink and wrap the step in `on_macos`.

`move` and `copy` replace an existing target by default, matching the corresponding file helpers; pass `overwrite: false` to reject replacement. `symlink` preserves an existing target by default, so pass `overwrite: true` when replacement is intentional. `move` and `copy` accept `source_glob: true` when the glob must resolve to exactly one source; `symlink` accepts one or more matching sources. Path collections used by `remove` and `set_permissions` expand globs automatically. `remove` ignores missing paths and may additionally be restricted with `symlink_target_contains:` or `content_contains:`. It accepts `sudo: true` or `sudo: :if_needed` for paths requiring elevated permissions.

Use `if_path_exists`, `unless_path_exists`, `on_macos` and `on_linux` blocks to guard one or more steps. Specify the guard path's `base:` explicitly. A condition is evaluated once when its scope begins, so related steps make the same decision:

```ruby
unless_path_exists "foo/default.conf", base: :var do
  mkdir_p "foo", base: :var
  copy "default.conf", "foo/default.conf"
end
```

#### Default config and template steps

`write_file` atomically writes its literal content, replacing an existing file by default. Specify its `base:`, such as `base: :etc`. Pass `append_newline: true` to ensure the content ends in a newline, `overwrite: false` to preserve an existing file or use `unless_path_exists` to guard a group of default-file steps:

```ruby
unless_path_exists "foo.conf", base: :etc do
  write_file "foo.conf", "key = value\n", base: :etc
end
```

{% raw %}

#### Interpolation in steps blocks

Ruby `#{...}` interpolation is normally evaluated before structured steps are serialised. The Ruby expression does not pass through the JSON API; only the string it produced does. A concrete result is safe only when it is identical for every installation represented by the JSON. RuboCop cannot generally establish that from arbitrary Ruby, so use interpolation in ordinary formula methods such as `install`, where Ruby code is evaluated locally.

`{{...}}` is not Ruby interpolation. It remains literal in the JSON API and the install-step runner expands supported tokens at install time. Use this form for install-time values in `post_install_steps`, especially values that depend on the current Homebrew installation. When a path argument supports `base:`, `source_base:` or `target_base:`, prefer those options to embedding a path token.

The runtime steps DSL retains compatibility helpers for `formula_name`, `name`, `version`, `version.major` and `version.major_minor`. Interpolating these helpers is safe and permitted by RuboCop because they return the corresponding `{{...}}` token text rather than a concrete value. Other Ruby interpolation is rejected. Prefer explicit `{{...}}` tokens in new steps so it is clear that expansion is deferred until installation.

Content, replacements, command arguments and command environments may use a fixed set of `{{...}}` tokens: `{{HOMEBREW_BREW_FILE}}`, `{{HOMEBREW_CELLAR}}`, `{{HOMEBREW_PREFIX}}`, `{{formula_name}}`, `{{name}}`, `{{user}}`, `{{prefix}}`, `{{opt_prefix}}`, `{{bin}}`, `{{sbin}}`, `{{lib}}`, `{{libexec}}`, `{{share}}`, `{{pkgshare}}`, `{{rack}}`, `{{var}}`, `{{etc}}`, `{{pkgetc}}`, `{{version}}`, `{{version.major}}` and `{{version.major_minor}}`. `{{name}}` is retained for compatibility; prefer `{{formula_name}}`. Completion directory tokens are also available. Any other `{{...}}` is left verbatim, so literal braces are never rewritten. For example: `write_file "foo.conf", "prefix = {{HOMEBREW_PREFIX}}\n", base: :etc`.
{% endraw %}

#### Command and lifecycle steps

`run` executes one command with a literal argument array; it does not evaluate a shell command string. Select the executable with `base:`, such as `:bin`, `:libexec` or `:homebrew_prefix`, or pass an absolute system executable. The step also supports a literal `env:`, `stdin_path:`, `stdout_path:`, `chdir:` and `sudo:`. Standard output is hidden by default and standard error is printed, matching `SystemCommand`; use `print_stdout: true` or `print_stderr: false` to change that behaviour. Failure aborts the post-install; pass `must_succeed: false` when a non-zero exit status is expected and should be ignored. Nothing is written to `stdout_path:` when an ignored command fails. Like all formula post-install steps, the command runs inside the formula post-install sandbox.

```ruby
run "foo-helper", args: ["--prefix", "{{HOMEBREW_PREFIX}}"], base: :libexec
terminate_process "foo", match: :full, attempts: 3
if_path_exists "foo.conf", base: :etc do
  warn "Remove the old foo.conf before continuing"
end
```

`terminate_process` terminates a process by name or, with `match: :full`, by its full command line. `attempts:` is the total number of attempts and defaults to one. Failure is ignored by default; pass `must_succeed: true` when it should abort. The step also supports `notices:` shown before the first attempt and a `failure_message:` warning.
`warn` emits a literal warning. Wrap it in `if_path_exists` when the warning only applies while a path exists.

#### Repeated formula actions

Use the named actions below for formula families that share post-install algorithms. Unique complex logic should be installed as a packaged helper and invoked with `run` instead of adding a formula-specific action. Any static formula inputs needed by a named action must be installed into the bottle rather than fetched from formula resources after pouring.

* `configure_gcc_runtime`: generate the Linux GCC runtime links and specs.
* `install_gzipped_executable`: unpack and install a gzipped executable.
* `configure_glibc_runtime`: generate requested glibc locales and timezone links.
* `configure_clang_system`: generate macOS Clang system configuration files.
* `configure_php`: configure shared PEAR and PECL state.
* `bootstrap_cpython`: bootstrap CPython packaging state.
* `bootstrap_pypy`: bootstrap PyPy packaging state with the required `abi_version:` argument.

#### Service data directory steps

`init_data_dir` creates a database service data directory and runs a supported
bootstrap command unless the directory already contains the default marker
file. Specify its `base:`, normally `base: :var`. It skips the bootstrap command
in Homebrew's GitHub Actions jobs and does not change permissions or ownership.

* `init_data_dir` with `using: :postgresql`: initialise PostgreSQL with
  `initdb`; example: `init_data_dir "postgresql@16", using: :postgresql, base: :var`.
  PostgreSQL defaults to `locale: "en_US.UTF-8"` and can set another locale,
  for example `init_data_dir "postgresql@12", using: :postgresql, locale: "C", base: :var`.
* `init_data_dir` with `using: :mysql`: initialise MySQL with
  `mysqld --initialize-insecure`; example:
  `init_data_dir "mysql", using: :mysql, base: :var`.
* `init_data_dir` with `using: :mariadb`: initialise MariaDB with
  `mysql_install_db`; example: `init_data_dir "mysql", using: :mariadb, base: :var`.

`symlink_tree` recursively links a source directory's contents into a target
directory, preserving existing real directories and skipping `.DS_Store` files.
`symlink_children` links each direct child of a source directory into a target
directory, defaulting the target to the same path as the source, and can add a
`prefix` or `suffix` to each linked name. For example:

```ruby
symlink_tree "share/postgresql", "share/{{formula_name}}"
symlink_children "bin", suffix: "-{{version.major}}"
```

#### Desktop and cache rebuild steps

These steps rebuild shared desktop and cache state using Homebrew-owned tools.

* `compile_gsettings_schemas`: compile GSettings schemas in `share/glib-2.0/schemas`.
* `update_gio_modules_cache`: update the GIO module cache in `lib/gio/modules`.
* `update_gdk_pixbuf_loaders_cache`: update the GDK Pixbuf loader cache.
* `update_gtk_icon_cache`: refresh the `hicolor` GTK icon cache.
* `update_mime_database`: rebuild the shared MIME database in `share/mime`.
* `update_desktop_database`: rebuild the desktop entry database in `share/applications`.

```ruby
class Foo < Formula
  # ...
  url "https://example.com/foo-1.0.tar.gz"

  post_install_steps do
    symlink "cert.pem", "cert.pem",
            source_formula: "ca-certificates",
            source_base:    :formula_pkgetc,
            target_base:    :pkgetc,
            overwrite:      true
  end
  # ...
end
```

In the above example, the [`libressl`](https://github.com/Homebrew/homebrew-core/blob/442f9cc511ce6dfe75b96b2c83749d90dde914d2/Formula/lib/libressl.rb#L53-L56) formula replaces its stock list of certificates with a symlink to that of the `ca-certificates` formula.

### Handling files that should persist over formula upgrades

For example, Ruby 1.9’s gems should be installed to `var/lib/ruby/` so that gems don’t need to be reinstalled when upgrading Ruby. You can usually do this with symlink trickery, or (ideally) a configure option.

Another example would be configuration files that should not be overwritten on package upgrades. If after installation you find that to-be-persisted configuration files are not copied but instead *symlinked* into `$(brew --prefix)/etc/` from the Cellar, this can often be rectified by passing an appropriate argument to the package’s configure script. That argument will vary depending on a given package’s configure script and/or Makefile, but one example might be: `--sysconfdir=#{etc}`

### Service files

There are two ways to add `launchd` plists and `systemd` services to a formula, so that `brew services` can pick them up:

#### Package-provided service file

If the package already provides a service file, it can be installed into the `prefix` directory and referenced by name:

```ruby
service do
  name macos: "custom.launchd.name",
       linux: "custom.systemd.name"
end
```

To find the file we append `.plist` to the `launchd` service name and `.service` to the `systemd` service name internally.

#### Formula-defined service file

If the formula does not provide a service file you can generate one using the following stanza:

```ruby
# 1. An individual command
service do
  run opt_bin/"script"
end

# 2. A command with arguments
service do
  run [opt_bin/"script", "--config", etc/"dir/config.yml"]
end

# 3. OS specific commands (If you omit one, the service file won't get generated for that OS.)
service do
  run macos: [opt_bin/"macos_script", "standalone"],
      linux: var/"special_linux_script"
end
```

#### Service block methods

This table lists the options you can set within a `service` block. The `run` or `name` field must be defined inside the service block. If `name` is defined without `run`, then Homebrew makes no attempt to change the package-provided service file according these fields. The `run` field indicates what command to run, instructs Homebrew to create a service description file using options set in the block, and therefore is required before using fields other than `name` and `require_root`.

| method                  | default      | macOS | Linux | description |
| ----------------------- | ------------ | :---: | :---: | ----------- |
| `run`                   | -            |  yes  |  yes  | command to execute: an array with arguments or a path |
| `run_type`              | `:immediate` |  yes  |  yes  | type of service: `:immediate`, `:interval` or `:cron` |
| `interval`              | -            |  yes  |  yes  | controls the start interval, required for the `:interval` type |
| `cron`                  | -            |  yes  |  yes  | controls the trigger times, required for the `:cron` type |
| `keep_alive`            | `false`      |  yes  |  yes  | [sets contexts](#keep_alive-options) in which the service will keep the process running |
| `launch_only_once`      | `false`      |  yes  |  yes  | whether the command should only run once |
| `run_at_load`           | `true`       |  yes  | no-op | whether the command should run when the service is loaded |
| `require_root`          | `false`      |  yes  |  yes  | whether the service requires root access. If true, Homebrew hints at using `sudo` on various occasions, but does not enforce it |
| `environment_variables` | -            |  yes  |  yes  | hash of variables to set |
| `working_dir`           | -            |  yes  |  yes  | directory to operate from |
| `root_dir`              | -            |  yes  |  yes  | directory to use as a chroot for the process |
| `input_path`            | -            |  yes  |  yes  | path to use as input for the process |
| `log_path`              | -            |  yes  |  yes  | path to write `stdout` to |
| `error_log_path`        | -            |  yes  |  yes  | path to write `stderr` to |
| `restart_delay`         | -            |  yes  |  yes  | number of seconds to delay before restarting a process |
| `stop_timeout`          | -            |  yes  |  yes  | number of seconds to wait before forcibly stopping a process |
| `throttle_interval`     | -            |  yes  | no-op | minimum seconds to wait before invocations (macOS default is `10`) |
| `process_type`          | -            |  yes  | no-op | type of process to manage: `:background`, `:standard`, `:interactive` or `:adaptive` |
| `macos_legacy_timers`   | -            |  yes  | no-op | timers created by `launchd` jobs are coalesced unless this is set |
| `sockets`               | -            |  yes  | no-op | socket that is created as an access point to the service |
| `nice`                  | -            |  yes  |  yes  | default scheduling priority (nice level), from `-20` highest to `19` lowest. **Note:** Negative nice values (higher priority) require `require_root: true` to be set. |
| `name`                  | -            |  yes  |  yes  | a hash with the `launchd` service name on macOS and/or the `systemd` service name on Linux. Homebrew generates a default name for the service file if this is not present |

For services that are kept alive after starting you can use the default `run_type`:

```ruby
service do
  run [opt_bin/"beanstalkd", "test"]
  keep_alive true
  run_type :immediate # This should be omitted since it's the default
end
```

If a service needs to run on an interval, use `run_type :interval` and specify an interval:

```ruby
service do
  run [opt_bin/"beanstalkd", "test"]
  run_type :interval
  interval 500
end
```

If a service needs to run at certain times, use `run_type :cron` and specify a time with the crontab syntax:

```ruby
service do
  run [opt_bin/"beanstalkd", "test"]
  run_type :cron
  cron "5 * * * *"
end
```

Environment variables can be set with a hash. For the `PATH` there is the helper method `std_service_path_env` which returns `#{HOMEBREW_PREFIX}/bin:#{HOMEBREW_PREFIX}/sbin:/usr/bin:/bin:/usr/sbin:/sbin` so the service can find other `brew`-installed commands.

```ruby
service do
  run opt_bin/"beanstalkd"
  environment_variables PATH: std_service_path_env
end
```

#### `keep_alive` options

The standard options keep the service alive regardless of any status or circumstances:

```ruby
service do
  run [opt_bin/"beanstalkd", "test"]
  keep_alive true # or false
end
```

Same as above in hash form:

```ruby
service do
  run [opt_bin/"beanstalkd", "test"]
  keep_alive always: true
end
```

Keep alive until the service exits with a non-zero return code:

```ruby
service do
  run [opt_bin/"beanstalkd", "test"]
  keep_alive successful_exit: true
end
```

Keep alive only if the job crashed:

```ruby
service do
  run [opt_bin/"beanstalkd", "test"]
  keep_alive crashed: true
end
```

Keep alive as long as a file exists:

```ruby
service do
  run [opt_bin/"beanstalkd", "test"]
  keep_alive path: "/some/path"
end
```

#### `sockets` format

The `sockets` method accepts a formatted socket definition as `<type>://<host>:<port>`.

* `type`: `udp` or `tcp`
* `host`: host to run the socket on, e.g. `0.0.0.0`
* `port`: port number the socket should listen on

Please note that sockets will be accessible on IPv4 and IPv6 addresses by default.

If you only need one socket and you don't care about the name (the default is `listeners`):

```rb
service do
  run [opt_bin/"beanstalkd", "test"]
  sockets "tcp://127.0.0.1:80"
end
```

If you need multiple sockets and/or you want to specify the name:

```rb
service do
  run [opt_bin/"beanstalkd", "test"]
  sockets http: "tcp://0.0.0.0:80", https: "tcp://0.0.0.0:443"
end
```

### Using environment variables

Homebrew has multiple levels of environment variable filtering which affects which variables are available to formulae.

Firstly, the overall [environment in which Homebrew runs is filtered](https://github.com/Homebrew/brew/issues/932) to avoid environment contamination breaking from-source builds. In particular, this process filters all but a select list of variables, plus allowing any prefixed with `HOMEBREW_`. The specific implementation is found in [`bin/brew`](https://github.com/Homebrew/brew/blob/HEAD/bin/brew).

The second level of filtering [removes sensitive environment variables](https://github.com/Homebrew/brew/pull/2524) (such as credentials like keys, passwords or tokens) to prevent malicious subprocesses from obtaining them. This has the effect of preventing any such variables from reaching a formula's Ruby code since they are filtered before it is called. The specific implementation is found in the [`ENV.clear_sensitive_environment!` method](https://github.com/Homebrew/brew/blob/HEAD/Library/Homebrew/extend/ENV/sensitive.rb).

In summary, any environment variables intended for use by a formula need to conform to these filtering rules in order to be available.

#### Setting environment variables during installation

You can set environment variables in a formula's `install` or `test` blocks using `ENV["VARIABLE_NAME"] = "VALUE"`. An example can be seen in the [`csound`](https://github.com/Homebrew/homebrew-core/blob/442f9cc511ce6dfe75b96b2c83749d90dde914d2/Formula/c/csound.rb#L96) formula.

Environment variables can also be set temporarily using the `with_env` method; any variables defined in the call to that method will be restored to their original values at the end of the block. An example can be seen in the [`gh`](https://github.com/Homebrew/homebrew-core/blob/1fd795861004bdf8bc5f6687c58b76c674794d40/Formula/g/gh.rb#L28-L33) formula.

There are also `ENV` helper methods available for many common environment variable setting and retrieval operations, such as:

* `ENV.cxx11` - compile with C++11 features enabled
* `ENV.deparallelize` - compile with only one job at a time; pass a block to have it only influence specific install steps
* `ENV.O0`, `ENV.O1`, `ENV.O3` - set a specific compiler optimisation level (*default:* Clang: `-Os`, GCC: `-O2`)
* `ENV.runtime_cpu_detection` - account for formulae that detect CPU features at runtime
* `ENV.append_to_cflags` - add a value to `CFLAGS` `CXXFLAGS` `OBJCFLAGS` `OBJCXXFLAGS` all at once
* `ENV.prepend_create_path` - create and prepend a path to an existing list of paths
* `ENV.remove` - remove a string from an environment variable value
* `ENV.delete` - unset an environment variable

The full list can be found in the [`SharedEnvExtension` module](/rubydoc/SharedEnvExtension.html) and [`Superenv` module](/rubydoc/Superenv.html) documentation.

### Deprecating and disabling a formula

See our [Deprecating, Disabling and Removing](Deprecating-Disabling-and-Removing.md) documentation for more information about how and when to deprecate or disable a formula, cask or Homebrew code.

## Updating formulae

When a new version of the software is released, use `brew bump-formula-pr` to automatically update the [`url`](/rubydoc/Formula.html#url-class_method) and [`sha256`](/rubydoc/Formula.html#sha256-class_method), remove any [`revision`](/rubydoc/Formula.html#revision-class_method) lines, and submit a pull request. See our [How to Open a Homebrew Pull Request](How-To-Open-a-Homebrew-Pull-Request.md) documentation for more information.

## Troubleshooting for new formulae

### Version detection failures

Homebrew tries to automatically determine the [`version`](/rubydoc/Formula.html#version-class_method) from the [`url`](/rubydoc/Formula.html#url-class_method) to avoid duplication. If the tarball has an unusual name you may need to manually assign the [`version`](/rubydoc/Formula.html#version-class_method).

### Bad makefiles

If a project's makefile will not run in parallel, try to deparallelize by adding these lines to the formula's `install` method:

```ruby
ENV.deparallelize
system "make" # separate compilation and installation steps
system "make", "install"
```

If that fixes it, please open an issue with the upstream project so that we can fix it for everyone.

### Still won’t work?

Check out what MacPorts and Fink do:

```sh
brew search --macports foo
brew search --fink foo
```

### Superenv notes

`superenv` is our "super environment" that isolates builds by removing `/usr/local/bin` and all user `PATH`s that are not essential for the build. It does this because user `PATH`s are often full of stuff that breaks builds. `superenv` also removes bad flags from the commands passed to `clang`/`gcc` and injects others (for example all [`keg_only`](/rubydoc/Formula.html#keg_only-class_method) dependencies are added to the `-I` and `-L` flags).

If in your local Homebrew build of your new formula, you see `Operation not permitted` errors, this will be because your new formula tried to write to the disk outside of your sandbox area. This is enforced on macOS by `sandbox-exec`.

### Fortran

Some software requires a Fortran compiler. This can be declared by adding `depends_on "gcc"` to a formula.

### MPI

Packages requiring MPI should use [OpenMPI](https://www.open-mpi.org/) by adding `depends_on "open-mpi"` to the formula, rather than [MPICH](https://www.mpich.org/). These packages have conflicts and provide the same standardised interfaces. Choosing a default implementation and requiring its adoption allows software to link against multiple libraries that rely on MPI without creating unanticipated incompatibilities due to differing MPI runtimes.

### Linear algebra libraries

Packages requiring BLAS/LAPACK linear algebra interfaces should link to [OpenBLAS](https://www.openblas.net/) by adding `depends_on "openblas"` and (if built with CMake) passing `-DBLA_VENDOR=OpenBLAS` to CMake, rather than Apple's Accelerate framework or the default reference `lapack` implementation. Apple's implementation of BLAS/LAPACK is outdated and may introduce hard-to-debug problems. The reference `lapack` formula is fine, although it is not actively maintained or tuned.

## How to start over (reset to upstream)

Have you created a real mess in Git which stops you from creating a commit you want to submit to us? You might want to consider starting again from scratch. Your changes to the Homebrew `main` branch can be reset by running:

```sh
git checkout -f main
git reset --hard origin/HEAD
```
