> For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt.

# Formatting

Rstack CLI includes a formatter built on [Prettier](https://prettier.io/). Compared with running Prettier directly, `rs fmt` offers better performance in two ways:

- **Parallel formatting**: Files are formatted concurrently in a worker pool.
- **Yuku parser**: The high-performance [Yuku](https://yuku.fyi/) parser is used by default for JavaScript, JSX, and TypeScript files.
- **Persistent cache**: Content-based results let later runs skip formatting unchanged files.

`rs fmt` supports Prettier options and plugins and adds built-in capabilities such as [sorting package.json fields](#sort-package-json).

## Basic usage

Run `rs fmt` without file arguments to format files in the current directory and save the changes:

```bash
rs fmt
```

Use `--check` to verify formatting without changing files:

```bash
rs fmt --check
```

See the [`rs fmt` CLI reference](/guide/cli/fmt.md) for more command-line options.

## Configuration

Use [`define.fmt()`](/guide/configuration.md#define-fmt) in `rstack.config.ts` to set formatting rules. It supports all [Prettier options](https://prettier.io/docs/options):

```ts title="rstack.config.ts"
import { define } from 'rstack';

define.fmt({
  printWidth: 100,
  singleQuote: true,
});
```

In addition to Prettier options and `overrides`, Rstack CLI provides two options:

- [`ignorePatterns`](#ignore-files): exclude files with Gitignore-compatible patterns.
- [`sortPackageJson`](#sort-package-json): sort fields in `package.json` files. The default value is `false`.

:::warning Prettier configuration files

`rs fmt` does not automatically load Prettier configuration files, `.prettierignore`, or `.editorconfig`. Keep formatting options and additional ignore rules in `define.fmt()`. To load an ignore file explicitly, use [`--ignore-path`](/guide/cli/fmt.md#--ignore-path-path).

:::

## Supported languages

`rs fmt` supports the same built-in languages as [Prettier](https://prettier.io/docs/) and normally infers the language from the file name:

- [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript), [JSX](https://react.github.io/jsx/), [Flow](https://flow.org/), and [TypeScript](https://www.typescriptlang.org/)
- [CSS](https://developer.mozilla.org/en-US/docs/Web/CSS), [Less](https://lesscss.org/), and [SCSS](https://sass-lang.com/)
- [HTML](https://en.wikipedia.org/wiki/HTML), [Angular](https://angular.dev/), [Vue](https://vuejs.org/), [Ember/Handlebars](https://emberjs.com/), [Lightning Web Components (LWC)](https://developer.salesforce.com/developer-centers/lightning-web-components), and [MJML](https://mjml.io/)
- [JSON](https://json.org/) and [YAML](https://yaml.org/)
- [GraphQL](https://graphql.org/)
- [Markdown](https://commonmark.org/), including [GFM](https://github.github.com/gfm/) and [MDX v1](https://mdxjs.com/)

You can add support for other languages with [Prettier plugins](#prettier-plugins).

## Formatting scope

`rs fmt` determines the formatting scope from the paths passed on the command line. You can combine the following inputs:

- **Files**: format only the specified files.
- **Directories**: scan directories recursively and format supported files.
- **Glob patterns**: match multiple paths, and prefix a pattern with `!` to exclude matches.

When no paths are provided, `rs fmt` formats the current directory. All glob patterns are resolved from the current working directory. Quote them so that `rs fmt`, rather than the shell, expands them:

```bash
# Format a directory and a file
rs fmt src package.json

# Format JavaScript and TypeScript files, excluding generated files
rs fmt "src/**/*.{js,ts}" "!src/generated/**"
```

When scanning directories or globs, `rs fmt` follows `.gitignore` rules, skips binary files, and does not traverse version-control directories or `node_modules`. It also skips files for which Prettier cannot infer a parser.

`.gitignore` applies only when scanning directories and globs. It does not exclude files passed explicitly on the command line. To always exclude a file, use [`ignorePatterns`](#ignore-files).

## Ignore files

Use `ignorePatterns` to exclude files from formatting:

```ts title="rstack.config.ts"
import { define } from 'rstack';

define.fmt({
  ignorePatterns: ['dist/**', 'coverage/**', '**/generated/**'],
});
```

Patterns follow Gitignore syntax and are resolved relative to the directory containing the Rstack configuration file. Because they are applied after the files are selected, they also exclude files passed explicitly on the command line.

### Lock files

By default, `rs fmt` ignores common lock files, including `package-lock.json`, `pnpm-lock.yaml`, and `skills-lock.json`.

To format these files, use a negated pattern to explicitly include them:

```ts title="rstack.config.ts"
import { define } from 'rstack';

define.fmt({
  ignorePatterns: ['!pnpm-lock.yaml'],
});
```

### Ignore order

`rs fmt` uses the following three steps to decide which paths to format:

1. **Process command-line arguments and `.gitignore`**: It first processes the files, directories, and glob patterns passed on the command line. A glob that starts with `!` excludes matching paths. Directory and glob scans follow `.gitignore`, while files passed directly do not. Paths excluded in this step cannot be re-included later.
2. **Apply default ignore rules and `ignorePatterns`**: By default, the command ignores [lock files](#lock-files), then applies `ignorePatterns`. These rules are evaluated in order, with later rules taking precedence. For example, `!pnpm-lock.yaml` re-includes the otherwise ignored file.
3. **Apply files specified with [`--ignore-path`](/guide/cli/fmt.md#--ignore-path-path)**: Each ignore file is evaluated separately, and later rules take precedence within that file. Exclusions from different files and `ignorePatterns` are combined: if any source ignores a path, that path remains excluded, even if another source re-includes it.

> Even when a file is passed directly on the command line, the default ignore rules, `ignorePatterns`, and rules from `--ignore-path` still apply. The same is true for paths specified with [`--stdin-filepath`](/guide/cli/fmt.md#--stdin-filepath-path) and for documents formatted through [`--lsp`](/guide/cli/fmt.md#--lsp).

## Sort package.json fields \{#sort-package-json}

Enable `sortPackageJson` to sort fields in each selected `package.json` with [`sort-package-json`](https://github.com/keithamus/sort-package-json):

```ts title="rstack.config.ts"
import { define } from 'rstack';

define.fmt({
  sortPackageJson: true,
});
```

## Overrides

Use the `overrides` field to set options for specific files. Each override supports these fields:

- `files`: files or glob patterns to match.
- `options`: formatting options applied to matching files.
- `excludeFiles`: optional files or glob patterns to exclude.

```ts title="rstack.config.ts"
import { define } from 'rstack';

define.fmt({
  overrides: [
    {
      files: 'docs/**/*.md',
      excludeFiles: 'docs/generated/**',
      options: {
        proseWrap: 'always',
      },
    },
  ],
});
```

### Pattern matching

The `files` and `excludeFiles` patterns are resolved relative to the directory containing the Rstack configuration file.

In `files`, a pattern without `/` matches file names at any depth, while a pattern containing `/` matches relative paths. In this example, `*.md` matches Markdown files in any directory, while `scripts/**/*.js` matches paths relative to the configuration directory:

```ts
define.fmt({
  overrides: [
    { files: '*.md', options: { proseWrap: 'always' } },
    { files: 'scripts/**/*.js', options: { singleQuote: true } },
  ],
});
```

### Merge order

When multiple overrides match, they are applied in declaration order, so later values take precedence. Here, `README.md` matches both overrides, so the final `printWidth` is `80`:

```ts
define.fmt({
  overrides: [
    { files: '*.md', options: { printWidth: 100 } },
    { files: 'README.md', options: { printWidth: 80 } },
  ],
});
```

## Cache

`rs fmt` uses a persistent cache by default for file-based `--write`, `--check`, and `--list-different` runs. Formatting results use file content and final formatting options, so changing either causes the file to be formatted again. Unsupported parser lookups normally use the file path and final options. For filenames without an extension, they also use file content because Prettier may infer a parser from the shebang. Installed Prettier plugins are identified by their package name, version, and entry point; local, linked, or unversioned plugins bypass the cache.

The default cache directory is `.rstack/cache/fmt` under the Rstack configuration root. When a command runs from a subdirectory, it continues to use the cache next to the resolved `rstack.config.*` file. Stdin formatting does not use this cache.

Use [`--cache-location <path>`](/guide/cli/fmt.md#--cache-location-path) to store the cache in a different directory. Relative paths are resolved from the current working directory. Custom directories are excluded from file discovery but are not automatically ignored by Git.

Use [`--no-cache`](/guide/cli/fmt.md#--no-cache) to run without reading, creating, or updating the cache:

```bash
rs fmt --no-cache
```

You can safely delete `.rstack/cache` to clear cached results. Do not treat the entire `.rstack` directory as disposable because it may also contain user-maintained Git hook scripts.

## Prettier plugins

To add formatting capabilities that are not built into Rstack CLI, install the corresponding [Prettier plugin](https://prettier.io/docs/plugins) and add it to `plugins`. Plugins can be referenced by package name, file path, or URL. Package names and relative paths are resolved from the directory containing the Rstack configuration file.

Because `rs fmt` loads plugins in workers, plugin objects cannot be passed directly. Reference each plugin by package name, path, or URL instead.

For example, install and enable [`prettier-plugin-tailwindcss`](https://github.com/tailwindlabs/prettier-plugin-tailwindcss):


```sh [npm]
npm install -D prettier-plugin-tailwindcss
```

```sh [yarn]
yarn add -D prettier-plugin-tailwindcss
```

```sh [pnpm]
pnpm add -D prettier-plugin-tailwindcss
```

```sh [bun]
bun add -D prettier-plugin-tailwindcss
```

```sh [deno]
deno add -D npm:prettier-plugin-tailwindcss
```

```ts title="rstack.config.ts"
import { define } from 'rstack';

define.fmt({
  plugins: ['prettier-plugin-tailwindcss'],
});
```

To enable a plugin only for specific files, add `plugins` to the `options` of an [`overrides`](#overrides) entry.
