---
title: CLI Reference
description: Command-line interface for @specdiff/cli: detect breaking changes between JSON Schema and OpenAPI documents.
url: https://pr-1-b9e16090e83d.thally.app/specdiff/cli
---

# CLI Reference

Command-line interface for @specdiff/cli: detect breaking changes between JSON Schema and OpenAPI documents.

## Installation

Install `@specdiff/cli` as a dev dependency:

```bash
npm install -D @specdiff/cli
```

Once installed, the `specdiff` binary is available through `npx`:

```bash
npx specdiff --help
```

Requires Node.js 22 or later.

## Commands

### Compare two documents

```
specdiff <before> <after> [options]
```

Compares a before and after JSON Schema or OpenAPI 3.x document and reports every change classified as breaking, warning, or info.

### List all rules

```
specdiff rules [--json]
```

Prints the full 45-rule catalogue with default severity and scope. Pass `--json` to get machine-readable JSON output.

### Explain a rule

```
specdiff explain <code>
```

Describes a single rule by its code, including title, description, severity, scope, and remediation guidance.

### Help and version

```
specdiff --help
specdiff --version
```

Also accepted as `-h` / `-v` or as subcommands (`help`, `version`).

## Compare flags

All flags apply to the `specdiff <before> <after>` compare command. Flags accept both `--flag value` and `--flag=value` syntax.

| Flag | Values | Default | Description |
|---|---|---|---|
| `--format` | `text`, `json`, `markdown` | `text` | Report output format |
| `--fail-on` | `breaking`, `warning`, `info`, `none` | `breaking` | Exit 1 when a change at or above this severity exists |
| `--ignore-rule <code>` | Rule code (repeatable) | none | Drop changes produced by a rule; unknown codes cause a usage error |
| `--ignore-path <pointer>` | JSON pointer prefix (repeatable) | none | Drop changes at or beneath a JSON pointer path; leading `#` is optional |
| `--kind` | `auto`, `openapi`, `json-schema` | `auto` | Force the document kind instead of auto-detecting |
| `--direction` | `request`, `response`, `neutral` | `neutral` | Direction for JSON Schema diffs (ignored for OpenAPI, which derives direction automatically) |
| `--output <file>` / `-o <file>` | File path | none | Write the report to a file instead of stdout |
| `--no-color` | boolean | auto | Disable ANSI colour in text output |
| `--color` | boolean | auto | Force ANSI colour on |

When neither `--color` nor `--no-color` is provided, colour is enabled automatically when the output format is `text` and stdout is a TTY.

## Exit codes

| Code | Name | Meaning |
|---|---|---|
| 0 | `ok` | No change at or above the `--fail-on` threshold, or a help/version/rules/explain command succeeded |
| 1 | `thresholdExceeded` | At least one change meets or exceeds the `--fail-on` severity threshold |
| 2 | `usage` | Usage error such as an unknown flag, missing argument, or unknown rule code |
| 3 | `inputError` | An input document could not be read or parsed |

## File format support

The parser selects a format based on the file extension:

- `.json` -- parsed as JSON
- `.yaml` or `.yml` -- parsed as YAML
- Any other extension -- JSON is attempted first; if that fails, YAML is used as a fallback

The parsed content must be a JSON object. Both JSON Schema documents and OpenAPI 3.x documents are supported. When `--kind` is set to `auto` (the default), Specdiff treats a document as OpenAPI if either file has a string `openapi` key; otherwise it treats both as JSON Schema.

## Usage examples

Compare two OpenAPI documents and fail on breaking changes (the default):

```bash
npx specdiff examples/petstore-v1.yaml examples/petstore-v2.yaml
```

Generate a Markdown report without failing:

```bash
npx specdiff examples/petstore-v1.yaml examples/petstore-v2.yaml \
  --format markdown --fail-on none
```

Compare JSON Schema documents with machine-readable output:

```bash
npx specdiff examples/user-v1.json examples/user-v2.json \
  --format json --fail-on none
```

Explain a specific rule:

```bash
npx specdiff explain required-parameter-added
```

Write the report to a file:

```bash
npx specdiff before.yaml after.yaml --format markdown -o report.md
```

### CI recipe (GitHub Actions)

```yaml
name: API compatibility
on: pull_request
jobs:
  specdiff:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with: { fetch-depth: 0 }
      - uses: actions/setup-node@v4
        with: { node-version: 22 }
      - name: Extract base branch spec
        run: git show origin/${{ github.base_ref }}:openapi.yaml > /tmp/openapi-base.yaml
      - name: Fail on breaking changes
        run: npx -y @specdiff/cli /tmp/openapi-base.yaml openapi.yaml --fail-on breaking --format markdown | tee -a "$GITHUB_STEP_SUMMARY"
```

## Programmatic usage

The `@specdiff/cli` package exports `runCli` so you can embed the CLI in other tools without spawning a subprocess. `runCli` never calls `process.exit`; it returns the exit code as a number.

```ts
import { runCli, type CliIo } from "@specdiff/cli";

const io: CliIo = {
  stdout: (text) => process.stdout.write(text),
  stderr: (text) => process.stderr.write(text),
  cwd: process.cwd(),
  isTty: process.stdout.isTTY === true,
};

const code = await runCli(
  ["before.yaml", "after.yaml", "--format", "json"],
  io,
);
process.exitCode = code;
```

### Exported functions

- `runCli(argv, io)` -- runs a command for the given argv (without the `node` and script entries) and returns the exit code. Never calls `process.exit`.
- `parseArgs(argv)` -- parses argv into a `ParsedCommand` object. Throws an `Error` with `name: "UsageError"` on malformed input.
- `loadDocument(filePath, cwd)` -- reads and parses a JSON or YAML file from disk. Rejects with a `DocumentLoadError`.
- `parseDocumentText(text, fileName)` -- parses text as JSON or YAML based on the file extension.
- `createDocumentLoadError(filePath, message)` -- factory function for `DocumentLoadError` instances.
- `isDocumentLoadError(error)` -- type guard that checks whether an error is a `DocumentLoadError`.

### Exported constants

- `EXIT_CODES` -- object with named exit codes: `{ ok: 0, thresholdExceeded: 1, usage: 2, inputError: 3 }`
- `HELP_TEXT` -- the full help string printed by `--help`

### Exported types

- `CliIo` -- the I/O surface passed to `runCli`, with `stdout`, `stderr`, `cwd`, and optional `isTty` fields
- `OutputFormat` -- `"text" | "json" | "markdown"`
- `KindOption` -- `"auto" | "openapi" | "json-schema"`
- `CompareCommand` -- the fully parsed compare invocation, including `before`, `after`, `format`, `failOn`, `ignoreRules`, `ignorePaths`, `kind`, `direction`, `color`, and `output`
- `ParsedCommand` -- discriminated union of all command types: `CompareCommand`, rules, explain, help, and version
- `DocumentLoadError` -- an `Error` with `name: "DocumentLoadError"` and a `filePath` property identifying the file that failed to load