Policy groups answer "which node should handle this"
In a Clash / Clash Meta (mihomo) config file, proxies lists every available node, while proxy-groups is where routing actually gets decided. Rules (rules) only determine which policy group a given connection is handed to; the policy group itself then decides which specific node to use. If you only define a manual select group, routing depends entirely on manual clicks, and a dead node won't be switched away from automatically. That's why almost every config also sets up a few automated policy groups — they hand the job of "picking a node" to an algorithm instead of a human.
mihomo supports three main types of automated policy groups: url-test (auto speed test), fallback (failover), and load-balance (load balancing). All three share the same health-check mechanism, but their decision logic and use cases are completely different — mixing them up carelessly hurts results. Let's break each one down by parameters, behavior, and use case.
url-test: automatically picks the fastest node by latency
url-test is the most common automated type. The core logic: periodically request a test URL through every node in the group, record the response time, then route current traffic through whichever node responds fastest. It answers the question "of all these nodes, which one is fastest right now" — a good fit for most everyday use cases where latency is the main concern.
proxy-groups:
- name: Auto Select
type: url-test
proxies:
- HK-01
- HK-02
- SG-01
- JP-01
url: "https://www.gstatic.com/generate_204"
interval: 300
tolerance: 50
lazy: true
- url: the address the speed test hits. Usually a lightweight endpoint that reliably returns 204, so the test itself doesn't eat bandwidth or get its results skewed by interference.
- interval: the gap between two speed tests, in seconds. The example above tests every 300 seconds — too short and nodes get hammered with test requests constantly; too long and a slowing node won't get switched away from for a while.
- tolerance: the switching threshold, in milliseconds. A switch only happens once the newly-measured fastest node beats the currently used node by more than this margin. This exists to prevent constant back-and-forth flapping between two nodes with similar latency, which would cause frequent connection interruptions.
- lazy: when true, speed tests only fire while a connection in the group is actually active — idle groups aren't tested in the background, saving traffic and load on nodes. When false, tests run on the interval regardless of whether the group is in use.
Note that tolerance isn't a "latency threshold" — it's a "switching bar." Say the current node measures 120ms and another measures 100ms, with tolerance set to 50ms: the 20ms gap isn't big enough, so no switch happens. Only once the gap exceeds 50ms does an actual switch occur. This is deliberate, to avoid flipping back and forth over a few milliseconds of difference.
fallback: only moves to the next node once the top pick fails
fallback's logic is completely different from url-test — it doesn't compare speed at all, it only cares whether a node is alive. Nodes in the group are ranked by the order they're listed, and the system always prefers the node at the top of that list as long as its health check passes. Only once the currently-used node fails a check (timeout or unreachable) does it move down the list, trying each subsequent node until one connects.
proxy-groups:
- name: Fallback
type: fallback
proxies:
- Primary-HK
- Backup-SG
- Backup-JP
url: "https://www.gstatic.com/generate_204"
interval: 180
tolerance: 0
Here, list order is priority order: Primary-HK comes first, and as long as its health check passes, traffic stays on it — even if a lower-ranked node happens to test with lower latency, it won't get preempted. This is the opposite of url-test's "whoever's fastest wins" approach. fallback is about stability and predictability, best suited to cases where you already know which node has the best line quality and just want a safety net for when it occasionally glitches — for example, giving a dedicated fixed-line node one or two backups.
The tolerance parameter barely matters in a fallback group, since it's not doing a "faster/slower" comparison — only a binary "reachable or not" check. Most configs just set it to 0 or omit it. What actually matters is url and interval, which determine how often the health check runs and where it points; too long an interval means traffic can keep hitting a dead primary node for a while after it fails.
load-balance: spreads traffic across multiple nodes
load-balance solves a different problem entirely — not "pick the single fastest one," but "spread concurrent connections across multiple nodes." The typical goal is to ease bandwidth pressure on a single node, or to keep several similarly-good nodes all busy instead of letting one sit at full load while others idle.
proxy-groups:
- name: Load Balance
type: load-balance
proxies:
- HK-01
- HK-02
- HK-03
url: "https://www.gstatic.com/generate_204"
interval: 300
strategy: consistent-hashing
The strategy parameter is what defines this type. mihomo offers two distribution algorithms:
- consistent-hashing: computes a hash from connection info such as source and destination address, and assigns a fixed node accordingly. The same source hitting the same destination will most likely always land on the same node, which avoids the login-state loss or download interruptions that happen when a session switches nodes mid-way. Good for long-lived connections and anything needing session stickiness.
- round-robin: new connections are assigned to nodes in the group in rotation. Distribution is more even, but different requests to the same site can land on different nodes, which causes trouble with services sensitive to IP consistency (such as sites that tie CAPTCHAs or login sessions to a specific IP).
Worth noting: load-balance doesn't remove a failed node and redistribute all traffic away from it — it still relies on health checks to determine whether a node is alive, temporarily skipping dead ones, but its distribution logic has no concept of "failover priority" ordering. If node quality varies a lot within the group, load balancing can end up routing some connections through the slow ones, which feels less consistent than url-test. This type suits scenarios where node quality is roughly similar and you just want to spread the load — not scenarios where quality varies and you want to pick the best one.
url test endpoint must be reachable through every node and return consistent results. If the test endpoint itself is being tampered with in some regions, health checks become unreliable, causing switches that shouldn't happen or missing ones that should. It's best to stick to the same test URL consistently so results are easy to compare when troubleshooting.
Which type to pick: a quick comparison
| Type | Decision basis | Typical use case | Key parameters |
|---|---|---|---|
| url-test | Lowest latency wins | Everyday browsing, chasing best speed | interval / tolerance |
| fallback | Priority order by liveness | Known preferred node + backup safety net | proxies order / interval |
| load-balance | Spreads concurrent connections | Multiple nodes of similar quality, spreading load | strategy |
In practice, all three types can be nested and combined. A common setup is building a default "Auto Select" group with url-test, then giving certain high-priority destinations (streaming, download tools) a dedicated load-balance group to spread bandwidth, while giving a critical node its own fallback group as insurance. Policy groups can reference each other — a select group's options can include specific nodes or the name of another policy group, so upper-level rules only need to point at the outermost select, while the automated logic lives in the inner groups. This keeps the overall config much cleaner.
Common pitfalls and how to troubleshoot
A frequent complaint is "I set up url-test but it never switches nodes" — this is usually because tolerance is set too high, or the latency gap between nodes in the group just isn't big enough to justify a switch in the system's judgment. Try temporarily lowering tolerance to a single digit to confirm switching resumes, then dial it back to a sensible value once you've verified the logic works. Another common issue is a fallback group "still using the primary even though it's clearly unreachable" — usually caused by interval being set too long so the next health check hasn't run yet, or the test endpoint not returning the expected 204 and getting mistakenly read as alive.
Another pitfall is treating load-balance as "a faster url-test," expecting it to automatically pick the best node — but its design goal is spreading load, not picking the optimum. If a group mixes in one clearly worse node, some connections' experience gets dragged down; in that case, either move the slow node out of the group or switch the group to url-test instead. When troubleshooting, keep an eye on each node's current latency reading and which node the group has actually selected in the client UI — most GUI clients (such as Clash Verge or Clash for Windows-style clients) show per-node latency and the current selection live in the policy group view, which is far more intuitive than digging through logs.