Spectral vs Redocly Linting Rule Coverage
This guide sits inside the Contract Linting & Governance reference under API Design Fundamentals & Architecture. It compares Spectral and Redocly on the axis that actually decides adoption: what each tool catches by default, how far you can extend it, and where each one leaves a gap you have to close yourself.
The decision you are actually making
The symptom that brings teams here is usually one of two things. Either a broken contract shipped to consumers — a missing operationId, an undocumented 4xx, a $ref to a schema that no longer exists — and someone asked “why didn’t linting catch this?” Or a governance initiative landed and you need one tool to enforce naming, security, and documentation standards across dozens of specs in CI. Both questions reduce to the same trade: Spectral is a portable, JSONPath-driven rule engine with a lean default ruleset; Redocly is a more opinionated platform whose linter comes bundled with docs preview and bundling.
Neither is a drop-in replacement for schema validation. Both sit on top of the OpenAPI Specification and JSON Schema 2020-12 dialect. If you are still deciding how strict your governance layer should be, the parent Contract Linting & Governance reference frames the policy questions; this page is the tooling head-to-head. If you already know you are staying on Spectral, skip ahead to Writing Custom Spectral Rules.
Minimal reproduction: same spec, two linters
Here is a deliberately flawed fragment — a missing operationId and an undocumented error response:
# openapi.yaml (OpenAPI 3.1.0)
openapi: 3.1.0
info: { title: Orders API, version: "1.0.0" }
paths:
/orders/{id}:
get:
summary: Fetch an order
responses:
"200":
description: OK
Spectral flags the missing operationId via its built-in operation-operationId rule. Redocly’s recommended ruleset flags it via operation-operationId too, and additionally warns on the missing 4xx response through operation-4xx-response. Same input, different default reach — which is the whole story in miniature.
Capability comparison
| Capability | Spectral | Redocly CLI |
|---|---|---|
| Built-in ruleset | spectral:oas (+ spectral:asyncapi) |
recommended, minimal, recommended-strict |
| Default focus | Structural OpenAPI + JSON Schema validity | Structural + naming, security, docs completeness |
| Rule model | JSONPath given + then function |
Named visitor keyed to node type |
| Custom logic | Core functions + custom JS functions | Config assertions + custom plugins (JS) |
| Config file | .spectral.yaml / .spectral.json |
redocly.yaml |
| Ruleset sharing | extends local path, npm pkg, or URL |
extends + plugins, npm-published |
| Bundling | Not built in (use external bundler) | redocly bundle built in |
| Docs preview | None | redocly preview-docs built in |
| Output formats | stylish, json, junit, sarif, and more | stylish, json, checkstyle, github-actions |
| OpenAPI 3.1 / 2020-12 | Yes | Yes |
The table’s center of gravity is the last few rows. Spectral is a linter and nothing else, which keeps it composable. Redocly is a small platform: the same binary lints, bundles, and serves preview docs, which is attractive when you want one dependency instead of three.
Built-in rulesets compared
Spectral’s spectral:oas is the baseline nearly everyone starts from. It enforces that operations have operationIds and tags, that paths are declared, that schemas are valid against JSON Schema 2020-12 in 3.1 mode, that info has contact and description, and that there are no unused components. You opt in with a one-line extends and then dial individual rules up or down.
# .spectral.yaml
extends: ["spectral:oas"]
rules:
operation-tag-defined: error
info-contact: off
Redocly ships three tiers. minimal is a light structural pass; recommended adds naming and documentation rules such as operation-4xx-response, operation-summary, and no-ambiguous-paths; recommended-strict promotes many warnings to errors. You select and override the same way:
# redocly.yaml
extends:
- recommended
rules:
operation-4xx-response: error
tag-description: warn
The practical difference: Redocly’s recommended will fail a spec that Spectral’s spectral:oas passes, because Redocly bakes in more style opinion. That is a feature if you want turnkey governance and a friction point if your existing specs were written before those opinions existed.
Custom rule authoring
This is where the two tools diverge most, and where migration cost lives.
Spectral rules are declarative given/then pairs. given is a JSONPath expression selecting nodes; then names a field and a function to run against it. Simple policies need no code at all:
# .spectral.yaml — require every operation to declare a security scheme
rules:
operation-must-have-security:
description: Every operation must declare security.
given: "$.paths[*][get,post,put,patch,delete]"
severity: error
then:
field: security
function: truthy
When declarative functions are not enough, Spectral lets you drop to a JavaScript function — the full authoring workflow, testing, and packaging is covered in Writing Custom Spectral Rules.
Redocly custom rules come in two flavors. Lightweight policies use configurable assertions directly in redocly.yaml:
# redocly.yaml — assertion-based custom rule
rules:
rule/operation-security-required:
subject:
type: Operation
property: security
assertions:
defined: true
severity: error
Anything requiring real logic becomes a Redocly plugin — a JavaScript module exporting a visitor keyed to OpenAPI node types:
// plugins/security-plugin.js
module.exports = function securityPlugin() {
return {
id: 'local',
rules: {
oas3: {
'operation-security-required': () => ({
Operation(operation, { report, location }) {
if (!operation.security) {
report({ message: 'Operation must declare security.', location });
}
},
}),
},
},
};
};
The mental models are different. Spectral asks “which JSONPath nodes, and what shape must they have?” Redocly asks “when you visit this node type, what do you assert?” Neither is harder in the abstract, but the visitor model gives Redocly plugins easy access to parent context, while Spectral’s JSONPath is faster to write for shape-only checks.
Config formats and sharing
Spectral centralizes on .spectral.yaml (or .json). Rulesets share cleanly: extends accepts a local path, a published npm package, or a URL, so a platform team can publish @acme/spectral-ruleset and every service extends it. Redocly centralizes on redocly.yaml, which does double duty — it configures linting and the bundle/preview commands and API registry references. Shared rules travel as plugins plus extends, also npm-publishable.
The consolidation cuts both ways. One redocly.yaml is convenient, but it couples your lint config to Redocly’s other features; a .spectral.yaml does exactly one thing and travels anywhere Spectral runs.
Bundling and preview extras in Redocly
Redocly’s differentiator is not really rule coverage — it is the surrounding commands. redocly bundle flattens a multi-file spec with external $refs into a single deliverable, and redocly preview-docs serves reference documentation locally. If your workflow already needs bundling and docs, folding them into the linter removes two dependencies. Spectral does none of this; you pair it with a separate bundler and docs generator. For a governance program whose output feeds a generated changelog, that bundled single-file artifact is often the exact input the diff tool wants.
Standard alignment
Linting has no dedicated RFC. Both tools anchor to the same two normative standards, and it is worth stating exactly what each linter does and does not guarantee:
| Standard | Role in linting | Spectral | Redocly |
|---|---|---|---|
| OpenAPI Specification 3.1.0 | Structural document model both tools traverse | Validates via spectral:oas |
Validates via recommended |
| JSON Schema 2020-12 | Schema dialect used by OpenAPI 3.1 schema objects |
Resolves and validates | Resolves and validates |
The key point: neither linter is the normative validator. A spec can pass both linters and still violate the specification in a way the ruleset simply does not check. Treat lint as an advisory style and governance layer over schema validation, never as proof of conformance.
CI ergonomics and safety implications
Both tools return a non-zero exit code on error-severity findings, so both gate a pipeline the same way. The ergonomics differ in reporting. Spectral emits SARIF and JUnit natively, which slot into code-scanning dashboards and test reporters with no glue. Redocly emits a github-actions format that annotates pull-request diffs inline, which is the smoother experience if GitHub is your only CI.
# Spectral in CI, failing the build and emitting SARIF
spectral lint openapi.yaml --ruleset .spectral.yaml \
--format sarif --output results.sarif --fail-severity=error
# Redocly in CI with PR annotations
redocly lint openapi.yaml --format=github-actions
The safety implication is the same for both: set --fail-severity=error (Spectral) or promote critical rules to error (Redocly) so that only intentional, reviewed downgrades let a spec through. A rule left at warn does not block anything, and a warning nobody reads is governance theater.
SDK and codegen downstream effect
Lint findings ripple into generated clients. A spec that passes linting but leaves operationId unset forces code generators to synthesize method names from paths — producing brittle, ugly SDK surfaces that churn every time a path changes:
- // operationId missing → generator invents a name from the path
- client.getOrdersById(id) // regenerates to getOrders_id() next release
+ // operationId: "getOrder" enforced by lint → stable method name
+ client.getOrder(id) // stable across spec edits
Enforcing operation-operationId at error severity in either tool is the single highest-leverage rule for SDK stability. Make it a blocking check before any codegen step runs.
Common mistakes
| Mistake | Correct approach |
|---|---|
| Treating lint as OpenAPI conformance validation | Run schema validation separately; lint is an advisory style layer |
| Copying a Spectral ruleset into Redocly unchanged | Rewrite: JSONPath given/then does not map to Redocly visitors |
Leaving critical rules at warn severity |
Promote SDK- and security-critical rules to error so CI blocks |
Picking Redocly only for recommended, then fighting its opinions |
Start from minimal and add rules you actually want |
Forgetting --fail-severity=error in Spectral CI |
Set it explicitly; otherwise the build passes on errors |
FAQ
Can I run Spectral rules inside Redocly or vice versa?
Not natively. The rule engines are incompatible: Spectral evaluates JSONPath given/then pairs with function objects, while Redocly rules are named visitors keyed to OpenAPI node types. You can run both linters in the same pipeline against the same spec — many teams do, using Spectral for portable structural checks and Redocly for bundling and docs — but a rule authored for one tool must be rewritten to move to the other.
Which tool has broader built-in rule coverage out of the box?
Redocly ships more opinionated built-in rules covering naming, security, and documentation completeness, plus bundling and preview in the same binary. Spectral’s spectral:oas ruleset focuses on structural OpenAPI and JSON Schema validity and is more portable across CI systems. For pure structural correctness the two overlap heavily; Redocly’s recommended tier extends further into style and documentation, which is either turnkey governance or unwanted opinion depending on your existing specs.
Do Spectral and Redocly validate against the OpenAPI Specification itself?
Both validate structural conformance to the OpenAPI Specification and resolve JSON Schema 2020-12 constructs used by OpenAPI 3.1 schema objects. Neither is the normative validator, so treat lint results as advisory style and governance checks layered on top of schema validation, not a replacement for it. A spec can pass both linters and still violate the specification in a way no rule happens to cover.
Related
- Contract Linting & Governance — the reference that frames linting policy and where these tools fit
- API Design Fundamentals & Architecture — the parent reference covering contract-first design across the API surface
- Writing Custom Spectral Rules for API Governance — author the custom Spectral rules this comparison references
- Generating API Changelogs from OpenAPI Diffs — consumes the bundled spec artifact your linter produces