# Ormolu: a Haskell formatter with one style and no options

> Ormolu is a BSD-3-Clause Haskell formatter that uses GHC's own parser and offers a single formatting style with no configuration, guaranteeing idempotence and minimal diffs. The judgement is that the decision to have no options is what makes it usable in CI, and that its main cost is the same one every strict formatter carries, which is that it can only produce the layout it has been taught.

**tweag/ormolu** — A formatter for Haskell source code

- Repository: https://github.com/tweag/ormolu
- Website: https://ormolu-live.tweag.io
- Stars: 1,078 · Forks: 90
- Language: Haskell
- License: NOASSERTION
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/tweag-ormolu

## Seven goals, and the third one is the whole product

Ormolu is a formatter for Haskell source code, and the README states the goals the project was created with. They are worth reading in full because the third one explains the rest.

Use GHC's own parser to avoid the parsing problems caused by `haskell-src-exts`. Make some whitespace programmable, so the layout of the input influences the layout choices in the output, and the choice between single-line and multi-line layouts is made by the user rather than by an algorithm. Implement one true formatting style that admits no configuration. Produce minimal diffs. Choose a style compatible with modern dialects of Haskell, adjusting as new extensions enter broad use. Guarantee idempotence, so formatting already formatted code does not change it. And stay well tested and dependable, so the formatter can be used in large projects.

The second and third goals are in tension and the resolution is what makes Ormolu interesting. The layout of your input influences the output, so a blank line you left where a list should break is preserved. That is the user making the layout decision. But the style itself is fixed and admits no configuration, which is why there is no `.ormolu` style file to argue about.

The result is a formatter where the only question is which style to standardise on, and once you have chosen it, there is nothing left to configure. For a team that wants a shared style and a CI check, that is a much smaller decision surface than a formatter with a hundred options.

The attribution note at the top of the README is worth reading too. Ormolu gratefully acknowledges the support and contributions of Mark Karpov during the period 2019 to 2026, who was the author and main maintainer of the package during his employment at tweag.

## Installing it, and the Nix cache flag that trips people up

The install options are several, and one of them has a gotcha the documentation spells out in detail.

The release page has binaries for Linux, macOS and Windows. You can also install with cabal or stack:

```console
$ cabal install ormolu
$ stack install ormolu
```

And Ormolu is included in several package repositories, for example on Arch Linux you can use the package on AUR:

```console
$ yay -S ormolu
```

Building from source is easiest with Nix, and the instruction is `nix build`. But there is a catch the documentation treats as a first-class concern. Make sure to accept the offered Nix binary caches, otherwise building may take a very long time. The flake declares the relevant caches, the IOG cache and the project's own `ormolu.cachix.org`, which is populated by CI, via its `nixConfig`, but Nix uses them only if you allow it to. The simplest way is to pass `--accept-flake-config`:

```console
$ nix build --accept-flake-config
```

To avoid repeating the flag you can add the substituters and trusted keys to your Nix configuration, in `/etc/nix/nix.conf`, or as `nix.settings` on NixOS.

Stack works too, with `stack build` to build and `stack install` to install. And there is a flake snippet for using Ormolu directly from GitHub:

```nix
{
  inputs.ormolu.url = "github:tweag/ormolu";
  outputs = { ormolu, ... }: {
    # use ormolu.packages.${system}.default here
  };
}
```

The reason to care about the cache flag is that Ormolu is a Haskell program, and building Haskell from source is slow enough that a cold build without substituters is an unpleasant first experience. The cachix cache is populated by CI, so a matching binary is usually available.

## The three modes, and check is the one you put in CI

The usage section is three commands and a set of modes, and the modes are the API.

Printing the formatted output to standard output:

```console
$ ormolu Module.hs
```

Replacing the contents of the input file with the formatted output is the `--mode inplace` flag:

```console
$ ormolu --mode inplace Module.hs
```

And the third mode is the one for continuous integration:

```console
$ ormolu --mode check $(find . -name '*.hs')
```

The documentation notes that checking whether files are already formatted is useful on CI, and the recommended tool for keeping a project formatted is the `run-ormolu` GitHub Action, referenced from the README.

For running over a whole tree, the documentation gives two forms. `find` works, and so does `git ls-files`:

```console
$ ormolu --mode inplace $(find . -name '*.hs')
$ ormolu --mode inplace $(git ls-files '*.hs')
```

The `git ls-files` form is the better one for a project, and the reason is not performance but scope. `find .` walks everything including build output directories, and a formatted copy of a generated file is a diff you did not ask for.

There is a Windows-specific trap in the documentation that is worth knowing about, because it produces a failure that looks like a formatting difference and is not. Ormolu's output always uses LF line endings. In particular, `ormolu --mode check` will fail if its input is correctly formatted except that it has CRLF line endings. This situation can happen on Windows when checking out a git repository without having set `core.autocrlf` to `false`.

That is the single most common way people conclude that Ormolu is broken on Windows, and the fix is a git configuration setting rather than anything in Ormolu.

## Fixity overrides live in an .ormolu file

The part of Ormolu that surprises people is that it reads your Cabal file to work out how to format your code, and that it can be told to override some of that.

Ormolu automatically locates the Cabal file that corresponds to a given source file. Cabal files are used to extract both default extensions and dependencies. Default extensions directly affect the behavior of the GHC parser, while dependencies are used to determine the fixities of operators that appear in the source code.

So the fixity of an operator in your code is not a guess by Ormolu. It comes from the dependency that provides that operator, looked up through your Cabal file. That is a much better answer than a hardcoded table, and it means an operator from a package you depend on gets the precedence that package documents.

When the automatic answer is wrong, you can override it. Fixities can also be overridden via an `.ormolu` file, which should be located higher in the file system hierarchy than the source file being formatted. When the input comes from stdin, you can pass `--stdin-input-file` to tell Ormolu which location to use as the starting point when searching for `.cabal` and `.ormolu` files.

The example `.ormolu` file in the documentation is a list of `infix` declarations:

```haskell
infixr 9  .
infixr 5  ++
infixl 4  <$
infixl 1  >>, >>=
infixr 1  =<<
infixr 0  $, $!
infixl 4 <*>, <*, *>, <**>

infixr 3 >~<
infixr 3.3 |~|
infixr 3.7 <~>
```

The stdin flag deserves attention because it is the escape hatch for editor integrations. An editor that formats a buffer it has not written to disk has no file path for Ormolu to search from, so it has to pass one explicitly.

The repository reflects how much machinery sits behind this. There is a `fixity-tests/` directory, `region-tests/`, `expected-failures/`, a `weeder.toml` for detecting dead code, a `DESIGN.md`, and a `tests/` directory.

## Editor integration, live demo and the maintenance question

The integration story covers the three usual places, and the documentation is specific about what exists rather than what might.

For editors, the known integrations are Emacs, VS Code, and for Vim the `neoformat` and `vim-ormolu` plugins. Haskell Language Server has built-in support for using Ormolu as a formatter, which is the least friction path if you already run the language server. And for GitHub Actions, `run-ormolu` is the recommended way to ensure that a project stays formatted with Ormolu.

There is also a browser version, Ormolu Live, deployed on every new commit to `master` at `ormolu-live.markkarpov.com`, and older versions are available at `COMMITHASH--ormolu.netlify.app` for the commit you want. The project page is `ormolu-live.tweag.io`.

The maintenance picture is the one part of this that needs a closer look. The listed releases are 0.8.1.1 from 2026-06-15, 0.9.0.0 from 2026-10-01, and 0.8.2.0 from 2026-10-12. So the newest tag by date is a patch on the 0.8 line, published after the 0.9.0.0 release. The last push was on 2026-10-12 and the repository is not archived, so the work is ongoing, but the version numbering does not read in a straight line and the 0.x series carries no compatibility guarantee.

What that means practically is that Ormolu's output can change between versions. A project that pins Ormolu in CI and in the editor can end up with the two disagreeing after a dependency bump, which is the most common operational annoyance with a strict formatter in a fast-moving language. The `--mode check` job in CI is where that surfaces, and it surfaces as a failing build rather than as a wrong file.

The licence is BSD-3-Clause, which the README badge states, though the repository's licence is reported as a custom one that GitHub cannot classify, so the `LICENSE.md` file is the text to rely on. That is a permissive grant with no copyleft obligation, which is a licensing observation rather than legal advice.

## Conclusion

Ormolu fits a Haskell team that wants one agreed house style enforced in CI without maintaining a configuration file, and that values the guarantee that formatting already formatted code changes nothing. It does not fit a team whose style preferences Ormolu does not implement, because there is no option to change it, and it does not fit a project on Windows with CRLF checkouts unless `core.autocrlf` is set to `false`, since Ormolu's output always uses LF. Verify first that the Haskell extensions your project uses are among those Ormolu supports, since the tool is tied to GHC's parser and to the Cabal file it locates, that your CI runs `ormolu --mode check` over the same file set your editor formats, because a mismatch between the two is what produces spurious failures, and that the `.ormolu` file you add for fixity overrides sits at a level the tool will actually find relative to the source file.

## FAQ

### How do I install Ormolu?

The release page has binaries for Linux, macOS and Windows, or you can use `cabal install ormolu` or `stack install ormolu`. On Arch Linux the AUR package works with `yay -S ormolu`. Building from source with Nix needs `nix build --accept-flake-config` to use the binary caches the flake declares.

### How do I check whether Haskell files are already formatted in CI?

Use `ormolu --mode check` over the file set, for example `ormolu --mode check $(find . -name '*.hs')` or `ormolu --mode check $(git ls-files '*.hs')`. The README also points at the `run-ormolu` GitHub Action as the recommended way to keep a project formatted.

### Why does ormolu --mode check fail on Windows when the code looks formatted?

Ormolu's output always uses LF line endings, so the check fails when the input is correctly formatted except for having CRLF endings. The documentation says this happens on Windows when checking out a git repository without setting `core.autocrlf` to `false`.

### How do I override the fixity of an operator in Ormolu?

Ormolu reads fixities from your Cabal file via the dependencies you declare. To override them, add an `.ormolu` file containing `infix` declarations, placed higher in the file system hierarchy than the source file. When formatting from stdin, pass `--stdin-input-file` to tell Ormolu where to start searching for `.cabal` and `.ormolu` files.

### Does Ormolu have any configuration options?

No. The project's stated goal is to implement one true formatting style that admits no configuration. What you can influence is the layout of the input, since the layout of the input influences the layout choices in the output, so a blank line left in a list is preserved as a multi-line layout.

## Sources

- [Issues](https://github.com/tweag/ormolu/issues)
- [Project website](https://ormolu-live.tweag.io)
- [README](https://github.com/tweag/ormolu/blob/master/README.md)
- [Releases](https://github.com/tweag/ormolu/releases)
- [tweag/ormolu on GitHub](https://github.com/tweag/ormolu)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/tweag-ormolu
