# How to Use Brace Expansion Patterns in the TSSLint CLI to Lint Multiple Projects at Once

> Lint multiple TypeScript projects simultaneously using TSSLint CLI brace expansion patterns with the --project flag. Optimize your workflow today.

- Repository: [Johnson Chu/tsslint](https://github.com/johnsoncodehk/tsslint)
- Tags: how-to-guide
- Published: 2026-03-04

---

**Use brace expansion patterns like `{tsconfig.json,packages/*/tsconfig.json}` with the `--project` flag to lint multiple TypeScript projects in a single TSSLint command.**

TSSLint, the TypeScript linter from the `johnsoncodehk/tsslint` repository, supports linting across multiple projects simultaneously by leveraging standard shell brace expansion. This allows you to target several `tsconfig` files without invoking the CLI multiple times, streamlining CI pipelines and monorepo workflows.

## How Brace Expansion Works in TSSLint

TSSLint does not implement custom brace expansion logic. Instead, it relies on your shell to expand patterns like `{a,b,c}` into separate arguments before the Node.js process receives them. In [`packages/cli/index.ts`](https://github.com/johnsoncodehk/tsslint/blob/main/packages/cli/index.ts), the CLI scans `process.argv` for project flags (lines 70-96) and treats every subsequent token as a glob pattern to resolve via `fs.globSync` (lines 101-110).

When you execute:

```bash
npx tsslint --project {tsconfig.json,packages/*/tsconfig.json}

```

Your shell expands the braces into two arguments—[`tsconfig.json`](https://github.com/johnsoncodehk/tsslint/blob/main/tsconfig.json) and `packages/*/tsconfig.json`—before TSSLint processes them. The CLI then resolves each glob to matching configuration files and queues them for the linting worker defined in [`packages/cli/lib/worker.ts`](https://github.com/johnsoncodehk/tsslint/blob/main/packages/cli/lib/worker.ts).

## Linting Multiple Projects with Brace Expansion

### Basic Syntax for Root and Package Projects

The most common use case in monorepos involves linting the root project alongside all packages. The README (lines 152-154) documents the recommended pattern:

```bash
npx tsslint --project {tsconfig.json,packages/*/tsconfig.json}

```

This single command lints both the root [`tsconfig.json`](https://github.com/johnsoncodehk/tsslint/blob/main/tsconfig.json) and every [`tsconfig.json`](https://github.com/johnsoncodehk/tsslint/blob/main/tsconfig.json) found in immediate subdirectories of `packages/`.

### Combining Framework-Specific Flags

TSSLint supports framework-specific project flags such as `--vue-project`, `--mdx-project`, and `--astro-project`. Each accepts brace expansion independently:

```bash
npx tsslint --vue-project {apps/*/tsconfig.json,libs/*/tsconfig.json}

```

This targets Vue projects in both `apps/` and `libs/` directories without affecting standard TypeScript projects.

### Linting Heterogeneous Projects

You can combine multiple project flags in one invocation to lint disparate project types simultaneously:

```bash
npx tsslint \
  --project {tsconfig.json,extensions/*/tsconfig.json} \
  --vue-project apps/vue/**/tsconfig.json \
  --mdx-project docs/mdx/**/tsconfig.json

```

The CLI resolves each flag’s arguments separately, aggregating all discovered configurations into a single linting run.

## Implementation Details

The argument resolution logic resides in [`packages/cli/index.ts`](https://github.com/johnsoncodehk/tsslint/blob/main/packages/cli/index.ts). After identifying project flags (lines 70-96), the code iterates over remaining arguments and passes them directly to `fs.globSync` (lines 101-110). This design means:

- **No internal brace parsing**: TSSLint receives already-expanded paths from the shell.
- **Standard glob support**: Patterns like `**/tsconfig.json` or `packages/*/tsconfig.json` work natively.
- **Cross-platform compatibility**: While brace expansion is a POSIX shell feature, Windows users can achieve similar results using Git Bash, WSL, or by passing multiple explicit arguments.

## Summary

- **Brace expansion** allows you to specify multiple `tsconfig` paths in a single `--project` argument by leveraging shell syntax like `{a,b,c}`.
- TSSLint receives expanded arguments and resolves each via `fs.globSync` in [`packages/cli/index.ts`](https://github.com/johnsoncodehk/tsslint/blob/main/packages/cli/index.ts) (lines 101-110).
- You can combine brace expansion with framework-specific flags (`--vue-project`, `--mdx-project`, etc.) to lint heterogeneous monorepos in one command.
- The README officially documents the pattern `{tsconfig.json,packages/*/tsconfig.json}` as the standard approach for multi-project linting.

## Frequently Asked Questions

### Does TSSLint support brace expansion on Windows?

TSSLint itself processes whatever arguments the shell provides. Windows Command Prompt does not perform brace expansion, but you can use Git Bash, WSL, or PowerShell with explicit arrays to achieve the same result. Alternatively, pass multiple `--project` arguments explicitly: `npx tsslint --project tsconfig.json --project packages/*/tsconfig.json`.

### Can I use brace expansion with npm scripts?

Yes, but you must quote the pattern to prevent premature expansion. In your [`package.json`](https://github.com/johnsoncodehk/tsslint/blob/main/package.json), wrap the brace expression in double quotes so the shell expands it at execution time rather than when parsing the script:

```json
{
  "scripts": {
    "lint:all": "tsslint --project \"{tsconfig.json,packages/*/tsconfig.json}\""
  }
}

```

### What other project flags support brace expansion?

All framework-specific project flags support the same glob and brace expansion logic as `--project`. This includes `--vue-project`, `--mdx-project`, `--astro-project`, `--svelte-project`, and any future framework integrations added to TSSLint. Each flag is processed independently in [`packages/cli/index.ts`](https://github.com/johnsoncodehk/tsslint/blob/main/packages/cli/index.ts).

### How does TSSLint handle glob patterns versus brace expansion?

TSSLint treats every argument after a project flag as a **glob pattern** to be resolved by `fs.globSync`. Brace expansion happens **before** TSSLint sees the arguments, performed by your shell. Therefore, `{a,b}/*.json` first becomes `a/*.json b/*.json`, and then each glob is resolved separately. This two-phase process allows complex combinations like `{packages,apps}/*/tsconfig.json` to work seamlessly.