KiCad's net classes get you a long way, but sooner or later you need a rule they cannot express — extra clearance around a high-voltage net, a minimum annular ring for a specific via, or a keepout near the board edge. That is what custom design rules are for.

Short answer: KiCad's custom design rules live in Board Setup → Design Rules → Custom Rules (stored in a plain-text .kicad_dru file). Each rule has a constraint (what to enforce), a condition (when it applies), and an optional layer scope. The Design Rule Checker enforces them automatically on every run.

What custom design rules do that net classes cannot

Net classes assign one clearance and one track width to a named group of nets. That is perfect for "all my USB nets get 0.2 mm clearance," but it breaks down the moment your requirement is conditional. Custom rules add a small expression language on top of the board, so you can say things like:

  • Enforce 1 mm clearance whenever either net in a pair belongs to the HV class.
  • Require a wider track only on the Power net and only on the front copper layer.
  • Apply an edge keepout to everything, regardless of net class.
  • Demand a minimum annular ring on vias in a particular area.

If you have ever fought with net classes and design rules trying to express one of these, custom rules are the missing piece.

The anatomy of a rule: rule, condition, constraint

Every custom rule is an S-expression with three moving parts:

  • rule — a name you choose. It shows up in the DRC report, so make it descriptive.
  • constraintwhat to enforce: a clearance, a track width, an annular ring, and so on, with min, max, or opt values.
  • conditionwhen the rule applies, written as a boolean expression over the two objects being checked, A and B.

A rule with no condition applies everywhere. A rule with a condition only fires when that expression evaluates to true for the objects DRC is comparing.

Here is the canonical clearance example — 1 mm of clearance whenever either side of a check touches the HV net class:

(rule "HV clearance"
  (constraint clearance (min 1mm))
  (condition "A.NetClass == 'HV' || B.NetClass == 'HV'"))

A and B are the two items DRC is comparing (two pads, a track and a pad, a track and a zone, and so on). The || means the rule triggers if either object is on the high-voltage net, which is exactly what you want for a clearance rule.

A track-width rule

Constraints are not limited to clearance. Say your power net must be at least 0.5 mm wide, but only on the front copper layer:

(rule "Power track width"
  (layer "F.Cu")
  (constraint track_width (min 0.5mm))
  (condition "A.NetClass == 'Power'"))

Two things to note. The optional (layer ...) scopes the rule to a single layer — omit it and the rule applies to all copper layers. And because a track only involves one object, the condition only needs to reference A.

A second example: board-edge clearance

A common manufacturing requirement is keeping copper away from the routed board outline. This rule enforces a 0.3 mm gap between any copper item and the Edge.Cuts layer:

(rule "Edge clearance"
  (constraint edge_clearance (min 0.3mm))
  (condition "A.Type == 'Track' || A.Type == 'Pad' || A.Type == 'Zone'"))

If you would rather constrain via annular rings instead, the same structure applies — swap the constraint type:

(rule "Min via annular ring"
  (constraint annular_width (min 0.15mm))
  (condition "A.Type == 'Via'"))

That single rule catches every via whose copper ring is too thin for your fab's tolerances — one of the most common causes of a failed check. If you have hit it before, our guide to fixing common KiCad DRC errors walks through the fixes.

Common constraint types

The constraint keyword decides what is being measured. These are the ones you will reach for most:

Constraint Enforces Typical use
clearance Copper-to-copper spacing High-voltage gaps, sensitive nets
track_width Minimum/maximum trace width Power and current-carrying nets
annular_width Via/pad ring width Meeting fab drill tolerances
hole_size Drilled hole diameter Minimum manufacturable drill
hole_clearance Copper-to-hole spacing Drill-to-copper safety
edge_clearance Copper-to-board-outline gap Routing and V-scoring margins
courtyard_clearance Footprint courtyard overlap Component collision checks
disallow Forbids an item in a region Keepouts (e.g. no vias in an area)

Each accepts min, max, and/or opt values, and every rule can carry a condition and an optional layer scope. Rules are evaluated top to bottom, and the first matching rule for a given check wins — so order your most specific rules first.

How DRC enforces your rules

Once a rule is saved in Board Setup, there is nothing else to wire up. The Design Rule Checker reads your .kicad_dru file and evaluates every rule on each run, listing violations alongside the built-in checks with the rule name you gave it. That naming is why descriptive rule names pay off — "HV clearance violation" is far easier to triage than a generic spacing error.

Custom rules are especially valuable for controlled-impedance work in KiCad, where trace width and spacing on specific differential pairs have to hold to tight tolerances that no single net class can capture.

Keep your rules honest on every push

Custom rules are only as good as the last time someone remembered to run DRC. It is easy to tighten a rule, tweak a trace, and forget to re-check before handing the board to a fab.

That is where GoForFab helps: connect your KiCad project and every push automatically runs DRC — custom rules and all — using kicad-cli, then hands you the full report next to your Gerbers, BOM, and 3D renders. Your .kicad_dru file is respected exactly as written, so the checks you author locally are the checks that run on every commit. It is free forever for solo work, so your rules never quietly go stale.