---
changelog:
  category: Release
  version: ultracite@8.1.0
date: '2026-10-26T02:02:35Z'
seo:
  description: >-
    Update Biome to 2.6.3. Biome 2.6 renamed useSortedClasses to
    useTailwindSortedClasses and moved its functions option to the top-level
    tailwind.mergeFunctions…
title: ultracite@8.1.0
type: changelog
---
## Minor Changes

- daf7b0f: Update Biome to 2.6.3. Biome 2.6 renamed `useSortedClasses` to [`useTailwindSortedClasses`](https://biomejs.dev/linter/rules/use-tailwind-sorted-classes/) and moved its `functions` option to the top-level `tailwind.mergeFunctions`, so the 8.0 core preset failed to load with "Found an unknown key `useSortedClasses`". The core preset now uses the new name and lists the same functions under `tailwind.mergeFunctions` and, for `cva` and `tv`, `tailwind.variantFunctions`, which sorts the classes in their variant objects. The rule also switched to Tailwind CSS v4's class order, so `ultracite fix` re-sorts class lists whose order changed the first time it runs with Biome 2.6.
  
  Biome 2.6 also promoted 59 nursery rules to stable groups. The presets turn on the ones that match rules the Oxlint presets enable, or that have no Oxlint counterpart and fit the preset:
  
  - Core: `noLoopFunc`, `noUnnecessaryTemplateExpression`, `useArraySome`, `useRegexpTest`, `useMathMinMax`, `noExcessiveNestedCallbacks` (with a limit of 10, matching `max-nested-callbacks`), `useDomNodeTextContent`, `useDomQuerySelector`, `useImportsFirst`, `useNamedCaptureGroup`, `useUnicodeRegex`, `useVarsOnTop`, `useThisInClassMethods`, `useReduceTypeParameter`, `useIframeSandbox`, `noDuplicateFieldDefinitionNames` for GraphQL, `noDuplicateSelectors` and `useBaseline` for CSS, and `noEmptyObjectKeys` and `noTopLevelLiterals` for JSON.
  - React: `noComponentHookFactories`, `noJsxNamespace`, `noJsxLeakedDollar`, `noReactStringRefs` and `useReactAsyncServerFunction`.
  - Vue: `noVueImportCompilerMacros`, `noVueRefAsOperand`, `noVueVOnNumberValues`, `useVueValidVFor`, `useScopedStyles`, `useVueConsistentDefinePropsDeclaration` and `useVueNextTickPromise`.
  - Astro: `useScopedStyles`, which reports `<style is:global>`.
  - Svelte: `noInlineStyles`, matching ESLint's `svelte/no-inline-styles`.
  - Qwik: `useQwikLoaderLocation`.
  - Jest and Vitest: `noConditionalExpect`, `noIdenticalTestTitle`, `useExpect`, `useTestHooksInOrder`, `useTestHooksOnTop`, and `useConsistentTestIt` set to `test()` at the top level and `it()` inside `describe`, matching `consistent-test-it`'s defaults.
  
  `noInlineStyles` stays off outside Svelte, `noExcessiveSelectorClasses` stays off because it has no default limit, and `noUntrustedLicenses` stays off because it reads `node_modules`, which the preset ignores.
  
  GraphQL files are now sorted. The core preset has always turned on `useSortedSelectionSet`, but Biome only runs assist actions on GraphQL files when `graphql.assist.enabled` is set, so it never ran. The preset now sets it and turns on Biome 2.6's [`useGraphqlSortedDefinitions`](https://biomejs.dev/assist/actions/use-graphql-sorted-definitions/), [`useGraphqlSortedVariables`](https://biomejs.dev/assist/actions/use-graphql-sorted-variables/) and [`useGraphqlSortedArguments`](https://biomejs.dev/assist/actions/use-graphql-sorted-arguments/), whose fixes `ultracite fix` applies. Biome marks the selection-set fix unsafe, because GraphQL returns fields in the order they're selected, so selection sets are reported by `ultracite check` and only sorted by `ultracite fix --unsafe`.
  
  Biome 2.6 formats and lints YAML, SCSS and Markdown. YAML and SCSS files are now formatted like the rest of the project. The core preset turns Biome's Markdown formatter off, because in 2.6.3 it drops the space before some inline code spans and changes the rendered text, so `.md` files are left as they were. It turns on Markdown frontmatter parsing, so the linter reads a leading `---` block as frontmatter rather than a heading.
  
  Requires @biomejs/biome >= 2.6.2
- d8124d5: Ultracite now requires Node.js 22.22.2 or later on Node 22, or 24.15 or later; Bun is unchanged. `eslint-plugin-jsdoc`, which every ESLint setup installs, has declared that range since version 64, so on older Node versions npm and pnpm warned when installing it and Yarn 1 refused to install it. Two ESLint framework plugins declare more: `@darraghor/eslint-plugin-nestjs-typed` (the `nestjs` preset) asks for Node.js 24 and `eslint-plugin-astro` (the `astro` preset) for 22.22.3 or 24.16. Both run on older versions, but Yarn 1 enforces what they declare.
- 9a1ce92: Format `.astro` files with Oxfmt. When the project or one of its workspaces uses Astro, `ultracite init` turns on Oxfmt's `astro` option in the root `oxfmt.config.ts` and installs `@astrojs/compiler-rs`, the compiler that Oxfmt's bundled `prettier-plugin-astro` loads. Until now, Oxfmt skipped `.astro` files. For Astro 6 and earlier, which keep line breaks between tags as spaces, it writes `astro: { compressHTML: "html" }` so formatting can't change what a page renders. An `astro` value already in the config is kept, so `astro: false` still opts out. `ultracite upgrade` keeps the compiler at the version this release was tested with, and switching from Oxlint to another linter removes it. Existing projects get it by re-running `ultracite init`, or by setting `astro: true` by hand as described in [Formatting Astro files](/docs/configuration#formatting-astro-files-oxfmt). Oxfmt formats `.astro` files from 0.73.0; older releases ignore the option.
- e4be64a: Add `playwright`, `react-native` and `drizzle` framework presets. `ultracite init` offers them, and pre-selects them when the project depends on `@playwright/test`, `react-native` or `drizzle-orm` (React Native also pre-selects React). The ESLint presets use each library's ESLint plugin, the Biome presets use the rules Biome 2.6 made stable, and the Oxlint presets add no plugin rules, because Oxlint has no plugin for these libraries.
  
  - **Playwright:** `ultracite/eslint/playwright` turns on every rule in [`eslint-plugin-playwright`](https://github.com/mskelton/eslint-plugin-playwright) in test files, except `no-hooks`, `require-soft-assertions` and `require-tags`, which would report ordinary tests. `ultracite/biome/playwright` turns on Biome's Playwright rules, such as `noPlaywrightMissingAwait` and `noPlaywrightWaitForTimeout`, and the test rules the Jest and Vitest presets use, such as `noFocusedTests` and `useExpect`. It leaves out `useConsistentTestIt`, because Playwright has no `it()`. On every linter, a hook that only needs `testInfo`, as in `test.beforeEach(async ({}, testInfo) => ...)`, no longer trips core's empty-pattern rule.
  - **React Native:** `ultracite/eslint/react-native` turns on the rules in [`eslint-plugin-react-native`](https://github.com/Intellicode/eslint-plugin-react-native) and Meta's [`@react-native/eslint-plugin`](https://www.npmjs.com/package/@react-native/eslint-plugin), such as `no-raw-text`, `no-unused-styles` and `no-deep-imports`. `eslint-plugin-react-native` hasn't been updated for ESLint 10, so the preset wraps it with [`@eslint/compat`](https://www.npmjs.com/package/@eslint/compat), which `init` installs too, and npm projects get a peer override for it. `ultracite/biome/react-native` turns on `noReactNativeRawText`, `noReactNativeLiteralColors`, `noReactNativeDeepImports` and `useReactNativePlatformComponents`. Both declare the `__DEV__` global.
  - **Drizzle:** both presets turn on the rules that report a `delete()` or `update()` with no `.where()` ([`eslint-plugin-drizzle`](https://orm.drizzle.team/docs/eslint-plugin) and Biome's `noDrizzleDeleteWithoutWhere` and `noDrizzleUpdateWithoutWhere`), for objects named `db` or `tx`. Without a name, the ESLint rules report every `.delete()` call, `Map#delete` included, and the Biome rules report nothing.
  
  These rules check their libraries' APIs, which is why they're in presets rather than in core. On Biome they would otherwise misfire: an explicit severity overrides Biome's dependency check, so `noReactNativeRawText` in core would report text inside any JSX element, including a `<div>`.

## Patch Changes

- 72890be: Update `eslint-plugin-unicorn` to 79. The ESLint preset turns on its two new rules, [`no-unnecessary-default-arguments`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-unnecessary-default-arguments.md) and [`no-repeated-call-wrappers`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-repeated-call-wrappers.md), like every other Unicorn rule. Unicorn 79 stopped [`no-top-level-side-effects`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-top-level-side-effects.md) from reporting unknown calls during module evaluation by default; the preset sets its new `checkUnknownCalls` option, so it keeps reporting them as it did with Unicorn 77. `prefer-ternary` and `prefer-minimal-ternary` now also merge branches that differ only in the callee or a computed member, such as `(test ? a : b)(value)`.
  
  Unicorn 78 also reports code that contains comments, which many rules used to skip, and `prefer-default-parameters` now checks fallback expressions, so existing code can get new reports. Unicorn 79 turns autofixes that could change behaviour in rare cases into suggestions, in rules such as `prefer-spread` and `prefer-math-min-max`.
- 72890be: Update the ESLint plugins `init` installs: typescript-eslint 8.72, `eslint-plugin-jsdoc` 65.4, `eslint-plugin-n` 18.5, `eslint-plugin-jest` 29.17, `@vitest/eslint-plugin` 1.6.28, `@next/eslint-plugin-next` 16.4, `@angular-eslint/eslint-plugin` 22.6, `eslint-plugin-svelte` 3.23.1, `eslint-plugin-storybook` 10.6.3, `eslint-plugin-qwik` 1.20.3, `@tanstack/eslint-plugin-query` 5.104.5, `@darraghor/eslint-plugin-nestjs-typed` 7.5.8, `eslint-plugin-react-doctor` 0.9.18 and `prettier-plugin-astro` 1.1.2, plus the Oxlint JS plugins `oxlint-plugin-react-doctor` 0.9.18 and `@shadcn/lint` 0.2.3. None of them adds or removes a rule, so the presets are unchanged. The releases fix false positives and add options the presets leave at their defaults, such as typescript-eslint's `await-thenable` `allowMixedPromiseArrays` and jsdoc's `check-alignment` `ignoreEmptyLines`. The presets were checked against ESLint 10.13.
- 14b8e04: Update oxfmt to 0.74.0. Markdown files are now formatted by oxfmt's own Markdown formatter instead of its bundled Prettier, so `ultracite fix` can reformat some `.md` files that were already clean, including sorting imports in JavaScript and TypeScript code blocks. `.mdx` files still go through Prettier. The releases also add an `astro` option that formats `.astro` files through `prettier-plugin-astro` (it needs `@astrojs/compiler-rs` installed in the project) and an `associations` option that formats files as a chosen language. See the [0.72.0](https://github.com/oxc-project/oxc/releases/tag/oxfmt_v0.72.0), [0.73.0](https://github.com/oxc-project/oxc/releases/tag/oxfmt_v0.73.0) and [0.74.0](https://github.com/oxc-project/oxc/releases/tag/oxfmt_v0.74.0) release notes for the full list of formatting fixes.
- 1fa337e: Update oxlint to 1.89.0 and `oxlint-tsgolint` to 7.0.2005. The releases add no rules, so the Oxlint presets are unchanged and the `oxlint` peer range stays at `^1.86.0`. Several rules now report cases they used to miss, so upgrading can surface new errors in existing code: `prefer-const` checks destructuring assignments inside blocks, `sort-keys` compares computed identifier keys, `no-param-reassign` reports writes to rest parameters, and `unicorn/prefer-string-replace-all` follows regexes stored in variables. `react/no-unescaped-entities`, `react/jsx-no-target-blank` and `unicorn/no-useless-switch-case` now offer suggestions. See the [1.87.0](https://github.com/oxc-project/oxc/releases/tag/oxlint_v1.87.0), [1.88.0](https://github.com/oxc-project/oxc/releases/tag/oxlint_v1.88.0) and [1.89.0](https://github.com/oxc-project/oxc/releases/tag/oxlint_v1.89.0) release notes for the full list.
- 5eeb6e5: `ultracite fix --hook` no longer fixes the whole project when it can't read an edited file's path from the agent's hook payload. A payload with no path, one in a shape the hook doesn't know, text that isn't JSON, or stdin that can't be read now fixes nothing. The whole-project run it used to fall back to could reformat files the agent never touched. Payloads that name the edited file are fixed as before.
