spectral lint: Lint OpenAPI in CI
spectral lint validates an OpenAPI/AsyncAPI file against a ruleset and exits non-zero when problems at or above the fail severity are found.
Spectral is the de facto OpenAPI linter. In CI you point it at your spec, load a ruleset, and gate the PR on the exit code so style and correctness regressions never merge.
What it does
spectral lint parses one or more JSON/YAML API documents and runs every enabled rule from the resolved ruleset (default spectral:oas). It reports results grouped by severity (error, warn, info, hint) and exits non-zero when any result meets the --fail-severity threshold.
Common usage
spectral lint openapi.yaml
spectral lint --ruleset .spectral.yaml openapi.yaml
# CI: only fail on real errors, machine-readable output
spectral lint --fail-severity=error --format=junit \
--output results.xml openapi.yamlOptions
| Flag | What it does |
|---|---|
| -r, --ruleset <file> | Path or URL to the ruleset (default .spectral.yaml/.json/.js) |
| -f, --format <fmt> | Output format: stylish, json, junit, html, text, teamcity |
| -o, --output <file> | Write results to a file instead of stdout |
| -F, --fail-severity <level> | Minimum severity that makes the process exit non-zero |
| -D, --display-only-failures | Show only results at or above fail-severity |
| --verbose | Print resolver and rule loading detail |
In CI
Run spectral lint --fail-severity=error as a required PR check so warnings stay advisory while errors block the merge. Commit a .spectral.yaml that extends: ["spectral:oas"] and add your house rules on top; pin the spectral version so a ruleset engine change does not surprise the pipeline.
Common errors in CI
The gate output looks like openapi.yaml\n 3:10 error oas3-schema ...\n\n✖ 12 problems (2 errors, 10 warnings, 0 infos, 0 hints); a non-zero exit follows when errors meet --fail-severity. "Could not parse ... ruleset" means a YAML syntax error in .spectral.yaml. "Unknown ruleset severity" means a typo in a rule severity value. "No ruleset has been found" means neither a default file nor --ruleset resolved.