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

# Configuration

Rstack CLI centralizes the configuration for your project's tools in a single file. Define only the configurations your project needs with the `define.*()` APIs.

## Configuration file

Create `rstack.config.ts` in the project root and call the relevant `define.*()` APIs:

```ts title="rstack.config.ts"
// Configuration guide: https://rstack.rs/config
import { define } from 'rstack';

define.app({
  // Rsbuild configuration
});

define.test({
  // Rstest configuration
});

define.lint({
  // Rslint configuration
});

define.fmt({
  // Formatting configuration
});
```

The configuration file does not require a default export. Each `define.*()` API can be called at most once; defining the same configuration type more than once throws an error.

By default, Rstack CLI looks for a file with one of the following names:

- `rstack.config.ts`
- `rstack.config.js`
- `rstack.config.mts`
- `rstack.config.mjs`

All `rs` commands accept the global `-c, --config` option for loading a file with a different name or location:

```bash
rs build --config ./configs/rstack.config.ts
```

## Importing dependencies \{#loading-dependencies-on-demand}

Rstack keeps a project's build, test, lint, formatting, and other settings in one `rstack.config.*` file. When a command loads the config file, it also loads every top-level import, even if it does not use the related configuration. Importing every tool and plugin at the top level can therefore add startup overhead to commands such as `rs lint` and `rs fmt`.

Choose the import style based on the config contents:

- Prefer simpler static imports when the config is only for an application and its tests, a library and its tests, or a documentation site.
- If the same config also includes lint, formatting, or staged-file checks, consider dynamically importing dependencies inside the relevant async configuration function. This lets checks skip those dependencies.

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

define.app(async () => {
  const { pluginReact } = await import('@rsbuild/plugin-react');
  return {
    plugins: [pluginReact()],
  };
});

define.lint(({ js }) => [js.configs.recommended]);

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

## Configuration APIs

Configuration options follow the formats of the underlying tools. When using APIs and helpers that Rstack CLI re-exports, prefer the `rstack/app`, `rstack/lib`, `rstack/test`, and `rstack/lint` entry points.

| API                                 | Tool                                                                    | Commands                                                                                                |
| ----------------------------------- | ----------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
| [`define.app()`](#define-app)       | [Rsbuild](https://rsbuild.rs/config/)                                   | [`rs dev`](/guide/cli/dev.md), [`rs build`](/guide/cli/build.md), [`rs preview`](/guide/cli/preview.md) |
| [`define.lib()`](#define-lib)       | [Rslib](https://rslib.rs/config/)                                       | [`rs lib`](/guide/cli/lib.md)                                                                           |
| [`define.doc()`](#define-doc)       | [Rspress](https://rspress.rs/api/config/config-basic)                   | [`rs doc`](/guide/cli/doc.md)                                                                           |
| [`define.test()`](#define-test)     | [Rstest](https://rstest.rs/config/)                                     | [`rs test`](/guide/cli/test.md)                                                                         |
| [`define.lint()`](#define-lint)     | [Rslint](https://rslint.rs/config/)                                     | [`rs lint`](/guide/cli/lint.md)                                                                         |
| [`define.fmt()`](#define-fmt)       | [Prettier](https://prettier.io/docs/options)                            | [`rs fmt`](/guide/cli/fmt.md)                                                                           |
| [`define.staged()`](#define-staged) | [lint-staged](https://github.com/lint-staged/lint-staged#configuration) | [`rs staged`](/guide/cli/staged.md)                                                                     |

### `define.app()` \{#define-app}

Defines the [Rsbuild configuration](https://rsbuild.rs/config/) for an application. It accepts a configuration object or a configuration function. The function receives the standard Rsbuild configuration parameters.

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

define.app({
  html: {
    title: 'My App',
  },
  output: {
    distPath: {
      root: 'dist',
    },
  },
});
```

### `define.lib()` \{#define-lib}

Defines the [Rslib configuration](https://rslib.rs/config/) for a library. It accepts a configuration object or a configuration function. The function receives the standard Rslib configuration parameters.

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

define.lib({
  dts: true,
  format: 'esm',
});
```

### `define.doc()` \{#define-doc}

Defines the [Rspress configuration](https://rspress.rs/api/config/config-basic) for a documentation site. It accepts a configuration object or an async configuration function.

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

define.doc({
  root: 'docs',
  title: 'My Site',
});
```

`@rspress/core` is an optional dependency of Rstack CLI. Install it in every project that uses the `rs doc` command:


```sh [npm]
npm install -D @rspress/core
```

```sh [yarn]
yarn add -D @rspress/core
```

```sh [pnpm]
pnpm add -D @rspress/core
```

```sh [bun]
bun add -D @rspress/core
```

```sh [deno]
deno add -D npm:@rspress/core
```

### `define.test()` \{#define-test}

Defines the [Rstest configuration](https://rstest.rs/config/). It accepts a configuration object or a configuration function.

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

define.app({
  // Shared application configuration
});

define.test({
  setupFiles: ['./tests/rstest.setup.ts'],
  testEnvironment: 'happy-dom',
});
```

When `extends` is omitted, Rstack CLI automatically connects the test configuration to `define.app()` through the Rsbuild adapter. If no application configuration is defined, it falls back to `define.lib()` through the Rslib adapter. The application configuration takes precedence when both are defined. Set `extends` explicitly to opt out of this automatic inheritance.

If the root test configuration does not define `extends` and contains `projects`, Rstack CLI applies automatic inheritance to each inline project that omits its own `extends`. A function-based application or library configuration is resolved once and shared by those projects. String project entries are passed to Rstest unchanged; they load their external configurations independently and do not inherit the current application or library configuration.

> For more guidance on testing, see [Testing](/guide/testing.md).

### `define.lint()` \{#define-lint}

Defines the [Rslint configuration](https://rslint.rs/config/). Pass the configuration directly, or use a synchronous or asynchronous function. The function receives all exports from `rstack/lint`, so presets and plugins do not need to be imported manually.

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

define.lint(({ js, ts }) => [
  js.configs.recommended,
  ts.configs.recommendedTypeChecked,
]);
```

### `define.fmt()` \{#define-fmt}

Defines formatting settings for [`rs fmt`](/guide/cli/fmt.md). Pass a configuration object directly, or use a synchronous or asynchronous function that returns one.

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

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

For detailed usage, see [Formatting](/guide/formatting.md).

### `define.staged()` \{#define-staged}

Defines the [lint-staged configuration](https://github.com/lint-staged/lint-staged#configuration) used to run tasks on staged Git files. It accepts either an object that maps glob patterns to tasks or a task-generator function. Tasks can be commands, command arrays, or functions supported by lint-staged.

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

define.staged({
  '*.{js,jsx,ts,tsx}': ['rs lint', 'rs fmt'],
  '*.{json,jsonc,md,mdx,css,html,yml,yaml}': 'rs fmt',
});
```

Unlike the other commands, `rs staged` requires a `define.staged()` configuration and reports an error when it is missing.
