Quality Checks - Krate Docs
You're viewing an older version ().
Krate Docs

Compiler-enforced accessibility, SEO, and performance gates.

#Quality Checks

Krate can enforce accessibility, SEO, and performance rules as part of the build. Checks run against the final rendered HTML — exactly what ships — so a rule can never be fooled by a component that only looks right at author time.

Checks are strictly opt-in: without a checks key in krate.config.ts, krate build never fails for quality. krate check runs the built-in rules on demand.

#Enabling checks

// krate.config.ts
export default defineConfig({
  checks: {
    a11y: "error",
    seo: "warning",
    perf: "warning",
    budget: { js: 150 },       // KB per route
    failOn: "error",
  },
});

With this config, krate build fails when an error-severity finding is produced. krate check runs the same rules and always exits non-zero when a finding meets failOn.

#The krate check command

krate check          # build, then evaluate quality gates
krate check ./site   # explicit project directory

The command builds the site and re-reads the emitted dist/ output, so the report reflects the real artifact. It exits 0 when no finding meets the fail-on threshold, and 1 otherwise — ideal for CI.

# CI
krate check && echo "quality gates passed"

#Built-in rules

RuleCategoryDefaultFlags
a11y/img-alta11yerror<img> missing an alt attribute
a11y/heading-ordera11ywarningskipped heading levels, missing/multiple <h1>
a11y/accessible-namea11ywarningicon-only links/buttons with no accessible name
a11y/duplicate-ida11ywarningrepeated id values
a11y/landmarka11ywarningno <main>/<nav>/landmark role on the page
a11y/form-labela11ywarningform control with no associated label
a11y/tabindexa11ywarningpositive tabindex (breaks focus order)
a11y/aria-rolea11ywarningunknown/invalid ARIA role value
a11y/color-contrasta11ywarninginline text/background contrast below 4.5:1
a11y/broken-anchora11ywarningin-page #id link with no matching id
seo/titleseoerrormissing <title> or title over 60 characters
seo/descriptionseowarningmissing/over-long meta description
seo/canonicalseowarningmissing <link rel="canonical">
seo/ogseowarningmissing Open Graph tags (og:title/og:type/og:url)
seo/og-imageseowarningmissing or relative og:image
seo/langseowarning<html> missing lang
seo/broken-linkseowarninginternal link to an unknown route
seo/duplicate-metaseowarningtitle/description shared across pages
perf/js-budgetperfwarningroute JS over budget.js
perf/image-dimsperfwarning<img> missing width/height (layout shift)

alt="" is accepted as intentional decoration; the a11y/img-alt rule only fires when the attribute is absent.

#Severity & overrides

Each category accepts "error", "warning", "off", or a boolean (true = default severity, false = off). Tune individual rules and suppress noise globally:

checks: {
  seo: "warning",
  rules: {
    "a11y/img-alt": "off",       // disable one rule
    "perf/js-budget": "error",   // escalate one rule
  },
  ignore: ["seo/og"],            // suppress a rule everywhere
  failOn: "error",               // or "warning" for stricter CI
}

failOn sets the minimum severity that fails the build/check. Warnings are still reported (and visible in the output) without failing when failOn: "error" (the default).

#Perf budgets

budget.js is the per-route client-JS budget in kilobytes, counting the page's hydration bundle plus the shared runtime chunk:

checks: {
  perf: "warning",
  budget: { js: 100 },
}

#Custom rules

Author rules in TypeScript and point checks.custom at the module. Custom rules run in the embedded QuickJS runtime (@krate/plugin provides the types) — no Node and no subprocess.

// checks/no-lorem.ts
import { defineCheckRule } from "@krate/plugin";

export default defineCheckRule((page) => {
  const findings = [];
  if (/lorem ipsum/i.test(page.html)) {
    findings.push({
      rule: "custom/no-lorem",
      message: "Remove placeholder copy.",
      severity: "warning",
    });
  }
  return findings;
});
// krate.config.ts
checks: {
  custom: ["./checks/no-lorem.ts"],
}

A custom rule receives:

  • page.route — URL route (e.g. /blog/hello)
  • page.source — source path relative to the project root
  • page.html — the final rendered HTML
  • page.jsBytes — the route's client-JS weight
  • page.ast — the parsed program as a kind-tagged AST document (when available)

and returns an array of { rule?, message, severity?, line?, col?, hint? }. A finding only needs message; everything else has sensible defaults.

#Findings format

Findings reuse the compiler's shared diagnostic format, so they match parse and build errors:

/pricing
    x seo/title  page has no <title>
      hint: Export a <Head><title>…</title></Head> or rely on seo.siteName.
    ! perf/js-budget  route ships 212.4KB of JS (budget 150.0KB)

Last updated: 2026-10-16

Contributors: Noinkin