---
title: Configuration
---

import { FileTree } from "@astrojs/starlight/components";

The TypeSpec compiler and libraries can be configured either via a configuration-file or command line flags.

## Configuration file

TypeSpec configuration can be provided via the `tspconfig.yaml` configuration file.

### Project Configuration

A `tspconfig.yaml` file can be marked as a **project configuration** by setting `kind: project` at the top level:

```yaml title=tspconfig.yaml
kind: project
entrypoint: main.tsp
emit:
  - "@typespec/openapi3"
```

A project configuration marks a **project boundary** — it serves the same role as `package.json` does today for boundary detection, but is specific to TypeSpec. When the compiler or IDE encounters a `tspconfig.yaml` with `kind: project`, it treats that directory as the root of a TypeSpec project.

#### `kind`

Set to `"project"` to mark the directory as a TypeSpec project root.

**Constraints:**

- `kind: project` can only be used in files named `tspconfig.yaml`. Custom-named config files (e.g. used with `--config`) cannot be project configs.

#### `entrypoint`

Declares the main TypeSpec file for the project. This is used by both the CLI (`tsp compile <dir>`) and the IDE (language server) to determine which file to compile.

- **Default:** `main.tsp` (when `kind: project` is set but no `entrypoint` is specified)
- Can only be used when `kind: project` is set.

```yaml title=tspconfig.yaml
kind: project
entrypoint: src/service.tsp
```

#### Entrypoint Resolution Priority

When compiling a directory, the compiler resolves the entrypoint in this order:

1. **Project tspconfig** — If the directory has a `tspconfig.yaml` with `kind: project`, use its `entrypoint` (defaults to `main.tsp`)
2. **package.json `tspMain`** — If a `package.json` exists with a `tspMain` field, use that
3. **`main.tsp`** — Fall back to `main.tsp` in the directory

The IDE language server uses the same priority when walking up directories to find the project root for a given TypeSpec file. When a project boundary (`kind: project`) is found, the walk stops — files outside the project boundary are not considered.

### Discovery

The TypeSpec compiler will look for the closest `tspconfig.yaml` file located in the same directory or closest parent directory from the TypeSpec entrypoint.

For example if running `tsp compile /dev/foo/bar/main.tsp`, the compiler will lookup the file at the folllowing paths (in order):

- `/dev/foo/bar/tspconfig.yaml`
- `/dev/foo/tspconfig.yaml`
- `/dev/tspconfig.yaml`
- `/tspconfig.yaml`

### Schema

The file is a `yaml` document with the following structure. See the [next section](#typespec-configuration-options) for details on each option.

```typespec
model TypeSpecProjectSchema {
  kind?: "project";
  entrypoint?: string;
  extends?: string;
  parameters?: Record<{default: string}>;
  `environment-variables`?: Record<{default: string}>;
  `warn-as-error`?: boolean;
  `output-dir`?: string;
  `trace`?: string | string[];
  imports?: string[];
  emit?: string[];
  `dry-run`?: boolean;
  options?: Record<unknown>;
  linter?: LinterConfig;
}

model LinterConfig {
  extends?: RuleRef[];
  enable?: Record<RuleRef, boolean | object>;
  disable?: Record<RuleRef, string>;
}
```

### Extending Project Files

There may be instances where you want to build different folders with varying options (such as different emitters), but still want to share some common configurations.

In such cases, you can use the `extends` property in the configuration file.

For instance, in `<my-pkg>/tspconfig.yaml`:

```yaml title=tspconfig.yaml
options:
  emitter1:
    some-option: my-name
  emitter2:
    some-other-option: This is a title
```

in `<my-pkg>/proj2/tspconfig.yaml`, enable `emitter1` using the options specified in the parent `tspconfig.yaml`

```yaml title=proj2/tspconfig.yaml
extends: ../tspconfig.yaml
emit:
  - emitter1
```

#### What gets extended

The extending logic follows these rules:

- **Root-level properties**: Shallow merge for all properties except `options`
- **Options property**: Deep merge at one level (per emitter)
- **Override behavior**: Properties specified in the extending file will completely override those from the extended file

**Root-level merge behavior:**
When extending a configuration, most properties (like `emit`, `imports`, `trace`, etc.) are merged at the root level. If the same property exists in both files, the extending file's value completely replaces the extended file's value.

**Options merge behavior:**
The `options` property receives special treatment with a one-level deep merge:

- Different emitters from both files are combined
- If the same emitter is configured in both files, the extending file's emitter configuration completely overrides the extended file's configuration for that emitter
- Individual emitter options are not merged - it's all or nothing per emitter

**Example:**

```yaml
# Base config (parent/tspconfig.yaml)
emit:
  - emitter1
options:
  emitter1:
    option-a: value-a
    option-b: value-b
  emitter2:
    option-x: value-x

# Extending config (child/tspconfig.yaml)
extends: ../tspconfig.yaml
emit:
  - emitter3  # Completely replaces the emit array
options:
  emitter1:   # Completely replaces emitter1 options
    option-c: value-c
  emitter3:   # Added alongside emitter2 from parent
    option-y: value-y

# Resulting merged config:
# emit: [emitter3]  # Only emitter3, emitter1 is gone
# options:
#   emitter1: { option-c: value-c }  # Only option-c, option-a and option-b are gone
#   emitter2: { option-x: value-x }  # Inherited from parent
#   emitter3: { option-y: value-y }  # From extending config
```

### Variable interpolation

The TypeSpec project file provides variable interpolation using:

- built-in variables
- environment variables
- config file parameters
- emitter options can reference each other

Variable interpolation is done using an variable expression surrounded by `{` and `}`. (`{<expression>}`)

Examples:

- `{output-dir}/my-path`
- `{env.SHARED_PATH}/my-path`

### Interpolation of Emitter Path Config

Certain emitter configurations can be interpolated using a specific rule designed to collapse a path.

If a variable is succeeded by a `/` or `.` and the emitter responsible for interpolating the config doesn't supply that variable, the path segment will be omitted.

For instance, consider the following config value: `{service-name}/output.{version}.json`
Here's what would be produced:

| Service name value | Version value | Result                    |
| ------------------ | ------------- | ------------------------- |
| `"PetStore"`       | `"v1"`        | `PetStore/output.v1.json` |
| `"PetStore"`       | `undefined`   | `PetStore/output.json`    |

#### Built-in variables

| Variable name              | Scope                    | Description                                                                          |
| -------------------------- | ------------------------ | ------------------------------------------------------------------------------------ |
| `cwd`                      | \*                       | Points to the current working directory                                              |
| `project-root`             | \*                       | Points to the the tspconfig.yaml file containing folder.                             |
| `output-dir`               | emitter options          | Common `output-dir` See [output-dir](#output-dir---configure-the-default-output-dir) |
| `emitter-name`             | emitter options          | Name of the emitter                                                                  |
| `service-name`             | service name             | Name of the service                                                                  |
| `service-name-if-multiple` | service name if multiple | Name of the service if multiple, undefined if one                                    |

#### Project Parameters

A TypeSpec project file can define certain parameters that can subsequently be specified through the CLI.
Parameters can be organized in a nested structure, to access different levels of the structure, use dots (`.`) in the variable expression.
Therefore, parameter names should not contain `.` in their name.

The `{cwd}` and `{project-root}` variables can be utilized in the default value of these parameters.

These parameters can then be referred to by their name in a variable interpolation expression.

All parameters must have a default value.
**Example:**

```yaml title=tspconfig.yaml
parameters:
  base-dir:
    default: "{cwd}"

output-dir: {base-dir}/output
```

The parameter can then be specified via `--arg` in this format `--arg "<parameter-name>=<value>"` and for nested structures `--arg "<parameter-name>.<nested-parameter-name>=<value>"`

```bash
tsp compile . --arg "base-dir=/path/to/base"
```

#### Environment variables

A TypeSpec project file can specify which environment variables it can interpolate.

The `{cwd}` and `{project-root}` variables can be used in the default value of these environment variables.

These environment variables can then be referred to by their name in a variable interpolation expression, using the `env.` prefix.

All environment variables must have a default value.

**Example:**

```yaml title=tspconfig.yaml
environment-variables:
  BASE_DIR:
    default: "{cwd}"

output-dir: {env.BASE_DIR}/output
```

#### Emitter Options

Emitter options can refer to each other by using the other option's name as the variable expression.

Interpolation is only possible among emitter options from the same emitter.

```yaml title=tspconfig.yaml
options:
  @typespec/openapi3:
    emitter-output-dir: {output-dir}/{emitter-sub-folder}
    emitter-sub-folder: bar

```

Emitter options support a nested structure, enabling complex configurations.

```yaml title=tspconfig.yaml
options:
  emitter-sub-folder:
    sub-folder: bar
```

To set these values via the CLI, use dots to navigate deeper levels in the definition. `--option "<option-name>.<nested-option-name>=<value>"`
Due to this capability, emitter option names should not contain a `.` in their name.

## TypeSpec Configuration Options

| Config          | Cli                       | Description                                              |
| --------------- | ------------------------- | -------------------------------------------------------- |
| `kind`          |                           | Set to `"project"` to mark as a project boundary         |
| `entrypoint`    |                           | Main TypeSpec file (requires `kind: project`)            |
| `output-dir`    | `--output-dir`            | Default output directory                                 |
| `config`        | `--config`                | Path to config file or folder to search for config file. |
| `trace`         | `--trace`                 | Specify tracing area to enable                           |
| `warn-as-error` | `--warn-as-error`         | Treat warning as error                                   |
| `imports`       | `--import`                | Additional imports to include                            |
| `emit`          | `--emit`                  | Emitter configuration                                    |
| `options`       | `--option` or `--options` | Emitter configuration                                    |
| `dry-run`       | `--dry-run`               | Tell emitters to run in dryRun mode                      |
| `linter`        |                           | Linter configuration                                     |

### `output-dir` - Configure the default output dir

Specify the common output-dir for all emitters. See [this](#configuring-output-directory) to configure per emitter.

```yaml title=tspconfig.yaml
output-dir: {cwd}/typespec-build
```

Output dir can be provided using the `--output-dir` cli flag

```bash
tsp compile . --output-dir "./typespec-build"
```

Output dir must be an absolute path in the config. Use `{cwd}` or `{project-root}` to explicitly specify what it should be relative to.

See [output directory configuration for mode details](#configuring-output-directory)

### `trace` - Configure what to trace

Configure what area to trace. See [tracing docs](./tracing.md)

```yaml title=tspconfig.yaml
# Trace all.
trace: *

# or specific areas
trace:
  - import-resolution
  - projection
```

Trace can be provided using the `--trace` cli flag

```bash
tsp compile . --trace import-resolution --trace projection
```

### `warn-as-error` - Treating Warnings as Errors

All warnings will be treated and emitted as errors, resulting in a non-zero exit code in the event of a warning.

**It is recommended to use this feature in Continuous Integration (CI) to ensure all warnings are addressed.**

```yaml title=tspconfig.yaml
warn-as-error: true
```

or via the cli

```bash
tsp compile . --warn-as-error
```

### `--ignore-deprecated`

Suppress all `deprecated` diagnostics that are raised when declarations are marked with the `#deprecated` directive.

```bash
tsp compile . --ignore-deprecated
```

### `imports` - Configure additional imports

```yaml title=tspconfig.yaml
imports:
  - sidecar.tsp
```

Specify additional TypeSpec files to import

```bash
tsp compile . --import "sidecar.tsp"
```

### `emit` - Specifying which emitters to run

Specify which emitters to use and their options if applicable.

The value can be the name of an emitter or a path to the emitter package/entrypoint.

```yaml title=tspconfig.yaml
emit:
  - emitter1 # Package name
  - /path/to/emitter2 # Give a path to an emitter
```

or via the cli

```bash
tsp compile . --emit emitter1 --emit /path/to/emitter2
```

### `options` - Configuring emitters

Emitters can define a set of options, those can be set as the value of the map.

```yaml title=tspconfig.yaml
options:
  # Enable and configure emitter1
  emitter1:
    option1: "option1-value"
    option2: "option1-value"
  # Only enable emitter2
  emitter2: true
```

Emitters options can also be provided using the `--option` in this format `--option=<emitterName>.<optionName>=<value>`

```bash
tsp compile . --option "emitter1.option1=option1-value"
```

Options specified via the CLI take precedence over the ones specified in `tspconfig.yaml`.

#### Emitters built-in options

##### `emitter-output-dir`

Represent the path where the emitter should be outputing the generated files.

Default: `{output-dir}/{emitter-name}`

See [output directory configuration for mode details](#configuring-output-directory)

### `linter` - Setting Up Linters

This allows you to configure the linter rules to be enabled in this repository. When referencing a rule or ruleset, use their ID, which follows the format `<libraryName>/<ruleName>`.

```yaml
linter:
  extends: # Extend `recommended` ruleset from @typespec/best-practices library
    - "@typespec/best-practices/recommended"

  enable: # Explicitly enable some rules
    "@typespec/best-practices/no-x": true

  disable: # Disable some rules defined in one of the ruleset extended.
    "@typespec/best-practices/no-y": "This rule cannot be applied in this project because X"
```

#### Configuring rule options

Some rules accept options to customize their behavior. To pass options, use an object instead of `true` when enabling the rule:

```yaml
linter:
  enable:
    # Enable with default options
    "@typespec/my-linter/required-doc": true

    # Enable with custom options
    "@typespec/my-linter/naming-convention":
      style: "PascalCase"
      allowUnderscores: false
```

When an object is provided, the values are merged with the rule's default options. See each rule's documentation for available options.

## CLI Flags for Emitter Control

### `--no-emit`

This flag disables emitters. Emitters will not run, and no files will be emitted.

This flag can also be used to suppress the "There are no emitters" warning.

```yaml title=tspconfig.yaml
tsp compile . --no-emit
```

### `--dry-run`

This flag tells compatible emitters to run in dry-run mode. In this mode, emitters will not emit any files, but will still run and log diagnostics.

```yaml title=tspconfig.yaml
tsp compile . --dry-run
```

## Other Command line flags

### `--config`

Specify a different config file for build overrides.

```bash
tsp compile . --config ./tspconfig.alt.yaml
```

:::note
`--config` cannot point to a project configuration (one with `kind: project`). Project configs must be named `tspconfig.yaml` and are auto-discovered. Use `--config` with a non-project build config that can optionally use `extends` to inherit from the project config.

When using `--config`, project-specific settings (like `entrypoint`) are automatically inherited from the project `tspconfig.yaml` that would normally apply to the entrypoint — the same project config that would be found if `--config` was not specified. Build settings (like `emit`, `options`, `linter`) are **not** inherited — use `extends` for that.
:::

### `--watch`

Start the tsp compiler in watch mode: watch for file changes and compile on save.

```bash
tsp compile . --watch
```

:::caution
Known issue: the watch mode does not pickup changes in JS files that are indirectly included (only imported via another JS file.)
:::

### `--nostdlib`

Don't load the TypeSpec standard library.

```bash
tsp compile . --nostdlib
```

### `--version`

Log the version of the tsp compiler.

```bash
tsp compile . --version
```

### `--pretty`

**Default: `true`**

Enable/Disable pretty logging (colors, diagnostic preview, etc.).

```bash
tsp compile . --pretty=false
```

## Configuring Output Directory

The TypeSpec compiler assigns a unique output directory to each emitter that runs, in order to minimize conflicts. By default, the output directory of an emitter is set to:

```
{output-dir}/{emitter-name}
```

where:

- `output-dir` is the common output directory for the compiler, which can be configured via `--output-dir`.
- `emitter-name` is the name of the emitter package (for example, `/openapi3`).

For instance, if the emitters `@typespec/openapi3` and `@typespec/jsonschema` are given, the default output folder structure would be:

{/* prettier-ignore */}
<FileTree>
- \{project-root}/tsp-output
  - @typespec:
    - openapi3
      - ... openapi3 files ...
    - jsonschema
      - ... json schema files ...
</FileTree>

You can change the compiler's `output-dir` with `--output-dir` or by setting that value in the tspconfig.yaml, which would result in the following structure:

```bash
--output-dir={cwd}/my-custom-output-dir
```

{/* prettier-ignore */}
<FileTree>
- \{cwd}/my-custom-output-dir
  - @typespec:
    - openapi3
      - ... openapi3 files ...
    - jsonschema
      - ... json schema files ...
</FileTree>

To change a specific emitter's output directory, you can set the `emitter-output-dir` option for that emitter:

```bash
--option "@typespec/openapi3.emitter-output-dir={project-root}/openapispec"
```

{/* prettier-ignore */}
<FileTree>
- \{project-root}
  - openapispec
    - ... openapi3 files ...
  - tsp-output
    - @typespec
      - jsonschema
        - ... json schema files ...
</FileTree>
