Ultracite: a zero-config preset that standardises ESLint, Biome and Oxlint across a repo
A highly opinionated, zero-configuration linter and formatter.
At a glance
- What is it?
- Ultracite is an MIT-licensed TypeScript CLI that installs and wires up an opinionated linting and formatting preset for Biome, ESLint or Oxlint, and also emits rule and context files for AI coding agents. The core judgement: the value is the preset plus the init/upgrade plumbing, not the underlying linters, and the trade-off is that the rule set is deliberately not yours to shape from scratch.
- Who is it for?
- Adopt Ultracite if you want one lint and format configuration shared across a monorepo and across AI agents, and you are willing to accept a preset you did not write. Do not adopt it if your project depends on a specific ESLint plugin that is not in the supported set, or if you need per-package rule divergence that the unified config cannot express.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 1 day ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The problem Ultracite targets: lint configuration as shared infrastructure
Setting up linting in a JavaScript or TypeScript repository is not hard in the way that writing a parser is hard. It is hard in the way that maintaining a shared house style across twenty packages is hard. Each package gets its own config file, each config drifts, and the drift is invisible until a pull request fails on a rule that only exists in one directory. Ultracite's answer is to stop treating lint configuration as per-package source and treat it as one preset that every package extends. The README describes it as a production-grade, zero-configuration preset for ESLint, Biome, and Oxlint, and the CLI is the delivery mechanism for that preset. The intended user is a team that has already decided it wants strict, consistent rules and does not want to spend a sprint negotiating them. The monorepo section of the README is explicit about the goal: one unified toolchain configuration across every package and app, eliminating duplicate config files. If your repository is a single small package with a config you are happy with, the problem Ultracite solves is not your problem.
What the preset actually is: rules plus generated agent context
The README lists the published presets as Biome, ESLint, Oxlint, Oxfmt, Prettier and Stylelint, and says ultracite init wires these up while the configuration docs list the exact import paths for referencing them by hand. That distinction matters. Ultracite is not a linter. It does not parse your source. It ships rule sets that extend the linter you already chose, and a CLI that writes the config files which pull those rule sets in. The second half of the mechanism is less common: the init flow takes an --agents flag and generates ruleset and context files for AI coding agents, with universal producing an AGENTS.md. The README names Claude Code, GitHub Copilot, Cursor, Gemini and others. The stated intent is that humans and models share one consistent style. That is the part of the design worth examining, because it means the preset has two consumers with different failure modes. A human who disagrees with a rule can override it locally. A model that has been handed the same rule file will reproduce the rule in generated code, so a rule you dislike propagates into new files faster than you can review it. The rule set is the product, and it is deliberately not neutral.
Getting it running: init, check, fix, doctor, upgrade
The entry point is npx ultracite init. The README states the interactive setup guides you through choosing formatter and linter, framework, editor and AI agents, then installs and configures everything, and that re-running it adjusts an existing setup. Package manager detection is automatic, with pnpm dlx, yarn dlx and bunx as alternatives. For CI or scripted setup, the README documents non-interactive flags: --linter takes Biome, ESLint or Oxlint, --pm takes the package manager, --editors and --agents accept lists with universal as a catch-all, --frameworks enables framework-aware rules, --js-plugins enables optional Oxlint JS plugins (eslint-plugin-github, eslint-plugin-sonarjs, oxlint-plugin-react-doctor), --type-aware turns on type-aware linting, --install-skill installs a reusable skill after setup, --skip-install configures without installing dependencies, and --quiet suppresses prompts and is auto-enabled in CI. Day-to-day you use ultracite check to lint without writing changes and ultracite fix to lint and auto-fix; both accept an optional list of files or globs, and unknown flags are passed through to the underlying linter. Two commands stand out. ultracite doctor verifies the setup and diagnoses configuration issues including linter version mismatches. ultracite upgrade updates Ultracite and reinstalls the linter toolchain at the versions it supports. Those two commands are the admission that this preset has a version coupling problem, and they are the reason to prefer the CLI over hand-copying import paths.
The --claude and --codex flags: autonomous repair with a re-lint gate
The most opinionated feature in the README is that ultracite fix accepts --claude or --codex to hand remaining unfixable issues to the Claude Code or Codex CLI, which the README says repairs them autonomously file by file, each fix verified by a re-lint before it is marked done. Read that carefully. The deterministic linter runs first and fixes what it can. Whatever is left, the kind of thing that normally requires a human to restructure code, is delegated to a model, and the acceptance criterion is that the linter passes afterwards. That is a reasonable gate and a narrow one. A re-lint confirms the rule is satisfied; it does not confirm the change preserved behaviour. The README does not describe a diff review step, a dry-run mode, or a cap on how many files the agent may touch in one invocation. Treat this as a convenience for mechanical residue, not as a substitute for reviewing the diff. Teams that already run an agent-assisted workflow may find it useful. Teams that do not should leave the flag alone, because the failure mode is a large, plausible, linter-clean diff.
Where Ultracite is the wrong tool
Zero-configuration is a claim about the default state, not about every state. The README says you can override anything when you need to, which is true of any preset that extends a config file, but overriding a large rule set one rule at a time is a different activity from authoring your own, and the preset's own documentation is the place the rule semantics live. The sharper limitation is plugin coverage. The README lists exactly three optional Oxlint JS plugins and describes ESLint as the most mature ecosystem with the largest plugin support. If your repository depends on a lint plugin outside the supported set, and that dependency is load-bearing for correctness rather than style, Ultracite configures the linter around you rather than for you. A second boundary is divergence. The monorepo pitch is one unified configuration across every package. If your packages genuinely need different rule sets, for example a browser package and a Node CLI with incompatible globals, a single preset is the wrong shape and you will spend your time writing per-package overrides that defeat the point. A third is version coupling: because Ultracite pins the toolchain versions it supports, upgrading your linter independently of ultracite upgrade is the kind of drift ultracite doctor exists to catch. That is a maintenance obligation, not a bug.
Alternatives and the difference in approach
The obvious alternative is to configure Biome, ESLint or Oxlint yourself. The difference is not quality, it is who owns the rule decisions and who pays for the churn. A hand-written Biome config is a handful of lines you fully understand, and when a rule starts producing noise you change it in the same file you wrote. Ultracite inverts that: you inherit hundreds of rules you did not choose, and your overrides live alongside a preset that can change underneath you on the next ultracite upgrade. The second alternative is a shared internal config package, a private npm module that other packages extend. That keeps ownership in-house and works well for organisations with a strong opinion about their own rules, but it does not generate agent context files and it does not ship the init, doctor and upgrade commands. Ultracite's specific advantage is the packaging: one command that installs the linter, writes the editor settings, emits the agent files and gives you a diagnostic command when the versions drift. If you do not need the agent files and you are comfortable maintaining a config package, the shared package is more transparent. Note that the README's performance claims, subsecond performance and near-instant analysis, describe the Rust-based tooling that Ultracite configures, not Ultracite itself, which is a CLI that runs at setup time.
Licence, maintenance and what to verify before adopting
Ultracite is MIT licensed, copyright Hayden Bleasel. For the preset and CLI that means you can use, modify and redistribute it, including in commercial and closed-source work, provided the licence notice is retained. This is not legal advice, and the licence covers Ultracite's own code, not the linters it configures, which carry their own terms. Maintenance cost is the part worth budgeting. The version history shows a fast release cadence, with 7.11.1, 7.11.0 and 7.10.8 all landing within the same week in September 2026. A preset that moves that often is a preset that will occasionally change a rule under you. The mitigation is built in: ultracite upgrade reinstalls the toolchain at supported versions, and ultracite doctor diagnoses mismatches. The practical verification sequence is to run npx ultracite init on a branch, inspect the generated config and agent files before committing, run npx ultracite check to see the real violation count on your existing code, and only then decide whether the preset's rules are ones you can live with. If the violation count is dominated by rules you would disable, the preset is not saving you configuration work; it is relocating it. The specific judgement: Ultracite is a good fit for a TypeScript monorepo that wants one lint standard, uses an AI agent in its workflow, and is willing to follow the preset's release train through ultracite upgrade. It is a poor fit for a repository whose lint rules are a product requirement rather than a house style.
Editorial conclusion
Adopt Ultracite if you want one lint and format configuration shared across a monorepo and across AI agents, and you are willing to accept a preset you did not write. Do not adopt it if your project depends on a specific ESLint plugin that is not in the supported set, or if you need per-package rule divergence that the unified config cannot express. Before committing, run npx ultracite init in a branch and then npx ultracite doctor to confirm the linter version it installed matches what the preset expects, and check whether the framework, editor and agent flags you need are present in the CLI reference.
Community notes