Rules & Config 12-minute read

How to Write Custom Clash Rules: Rule Types, Matching Order, and the MATCH Fallback

Learn Clash rule syntax for DOMAIN, DOMAIN-SUFFIX, IP-CIDR, and PROCESS-NAME, how top-down matching works, what no-resolve means, and how to use MATCH as a fallback.

Before Rules Can Work: Rule Mode, Traffic Capture, and Persistent Config Changes

Custom Clash rules choose an outbound route for connections that have already reached the core. Correct rules do not guarantee that all app traffic passes through them: the system proxy generally affects only apps that honor proxy settings, while TUN can capture more traffic but is still subject to routing, permissions, and exclusions. When troubleshooting, first check the client's Connections page to confirm the target request appears, then inspect the matched rule.

This guide covers common Clash rule syntax and uses Clash Meta (mihomo) as its main reference for process detection. Support varies by core and operating system, so a client's editing interface should not be treated as a definitive list of core capabilities. Check the core information or startup logs to confirm which core is running, then use features supported by that core.

  1. Switch the operating mode to Rule; the corresponding config setting is mode: rule. Global mode does not route traffic using the regular rules described here.
  2. Make sure the active config is the one you're editing, not another subscription with the same name.
  3. Back up the original config, validate the YAML with the client's built-in config checker, then reload it.
  4. Close existing connections from the target app and send the request again. Established connections usually do not switch routes automatically when rules change.

Rule Syntax Basics: Types, Match Values, and Policy Names

Most rules use the format type,match value,policy. The policy can be a built-in option such as DIRECT or REJECT, or the name of a proxy node or group defined in the config. MATCH takes no match value and is written as MATCH,policy. Separate fields with commas, and place each rule as a string in the YAML list.

Rule typeExampleWhat it matches
DOMAINDOMAIN,api.example.com,DIRECTAn exact domain match
DOMAIN-SUFFIXDOMAIN-SUFFIX,example.com,DIRECTThe root domain and its subdomains
DOMAIN-KEYWORDDOMAIN-KEYWORD,example,REJECTA string anywhere in the domain name
IP-CIDRIP-CIDR,192.168.0.0/16,DIRECT,no-resolveA destination IPv4 address in this subnet
IP-CIDR6IP-CIDR6,fc00::/7,DIRECT,no-resolveA destination IPv6 address in this subnet
PROCESS-NAMEPROCESS-NAME,curl.exe,DIRECTA matching detected process name
MATCHMATCH,DIRECTConnections not matched by any preceding rule

The proxy group name must exist

PROXY is not an automatically available "master proxy switch." If your config has no node or group named PROXY, referencing it may cause a missing-proxy error when the config loads. Likewise, Proxy Select and Proxy Select 2 are distinct names; don't guess based on how they appear in the UI.

The snippet below illustrates a rule list only. It assumes the original config already defines a proxy group named "Proxy Select". If it doesn't, replace that name with an existing policy instead of pasting the snippet and expecting a group to be created automatically.

rules:
  - "DOMAIN,api.example.com,DIRECT"
  - "DOMAIN-SUFFIX,example.com,Proxy Select"
  - "MATCH,Proxy Select"

Domains in rules do not include https://, a path, or a port. To target the /docs path in https://example.com/docs, you can't use DOMAIN: these rules route connections at the network level, not HTTP paths.

Top-Down Matching: Put Specific Exceptions First and Broad Rules Later

Regular rules are checked in list order. The first match determines the policy, and matching stops there; the core will not continue looking for a "more specific" rule. Rules are not automatically sorted with DOMAIN before DOMAIN-SUFFIX, nor reordered based on subnet size. Rule order is part of the config logic.

rules:
  - "DOMAIN,api.example.com,DIRECT"
  - "DOMAIN-SUFFIX,example.com,REJECT"
  - "MATCH,DIRECT"
  • api.example.com: The first rule matches and uses DIRECT; the second rule won’t reject it.
  • www.example.com: The first rule doesn’t match, so the second matches and uses REJECT.
  • example.com: The second rule also matches; a suffix rule includes the root domain itself.
  • notexample.com: This is not within the example.com domain hierarchy, so the third rule applies.

If you swap the first two rules, api.example.com will also be rejected. You don't need duplicate rules to fix this; just move the exception above the broader rule. A common layout is specific exceptions, optional LAN direct rules, category rule sets, regional IP rules, and the fallback last. This order isn't mandatory, though: whether an exception should take priority over a LAN policy depends on your needs.

Keyword Rules Can Match More Than You Expect

DOMAIN-KEYWORD,example matches a string anywhere in a domain name, not a specific domain hierarchy; it may also match notexample.com. To route a site and its subdomains, DOMAIN-SUFFIX is usually a better starting point. Don't put a short keyword rule at the top just to save a few lines—it can catch unrelated services too.

IP-CIDR and no-resolve: Preventing Active DNS Lookups, Not Disabling DNS

IP-CIDR checks whether the destination address belongs to a subnet. If a request includes a domain name, the core may need to obtain the destination IP before it can evaluate an IP rule. Adding no-resolve tells the core not to trigger a DNS lookup just to evaluate that rule. It does not mean "skip IP matching," nor does it mean the connection will never use DNS.

rules:
  - "IP-CIDR,10.0.0.0/8,DIRECT,no-resolve"
  - "IP-CIDR,172.16.0.0/12,DIRECT,no-resolve"
  - "IP-CIDR,192.168.0.0/16,DIRECT,no-resolve"
  - "IP-CIDR6,fc00::/7,DIRECT,no-resolve"
  - "MATCH,DIRECT"

The examples above cover three common private IPv4 ranges and the IPv6 unique local address range. They are LAN rule examples, not a complete list of special-purpose address ranges. If the connection is already going to 192.168.1.1, the destination IP is known, so a rule with no-resolve can still match.

Test Domain and IP Access Separately

A direct connection to 192.168.1.1 does not guarantee that a domain resolving to that address will match the same rule. If the core does not yet know the actual destination address, no-resolve affects whether it actively resolves the domain for an IP rule. The destination IP already in use, DNS cache, and Fake-IP mappings can also affect the result; check the connection details.

PROCESS-NAME: Permissions and Platform Limits

Process rules are useful when a particular app should always use a specific route. For example, on Windows, PROCESS-NAME,curl.exe,DIRECT can match connections the core identifies as belonging to curl.exe. Use the process name shown in the connection details; don't substitute a desktop shortcut name or window title.

  • Check platform support: Process detection depends on the core, operating system, and permissions. In mihomo, find-process-mode affects process lookup; if it is set to off, process rules cannot be expected to identify apps correctly.
  • Check where the traffic comes from: Traffic forwarded by a router from another device usually does not expose the remote app's local process name to the router. In that case, consider source-address rules instead of trying to force a process-name match.
  • Check the order: To let a process rule take priority over regular website routing, place it before the relevant domain rules. If it should only supplement them, place it after those rules but before MATCH.
  • Check helper processes: An app may use multiple processes to connect to the network. A browser engine, updater, and main app may appear under different names, so inspect connections individually.

Per-app proxy settings and app exclusion lists in Android clients often control which apps are captured by the VPN. They are not equivalent to desktop PROCESS-NAME rules. Traffic excluded by an app filter never reaches the core for regular rule matching.

MATCH Fallback: The Last Rule Routes Unmatched Traffic

MATCH has no domain or subnet condition; it catches connections that reach it. Put it at the end of the regular rule list. If it comes first, later regular rules never get a chance to match. Usually one explicit fallback is enough; adding more does not create failover.

mode: rule
rules:
  - "DOMAIN,api.example.com,DIRECT"
  - "DOMAIN-SUFFIX,example.com,REJECT"
  - "IP-CIDR,192.168.0.0/16,DIRECT,no-resolve"
  - "MATCH,DIRECT"

This syntax example uses built-in policies only: reject a specific domain and send all other traffic direct. It is not a general-purpose proxy setup. To send unmatched traffic through a proxy, replace DIRECT on the last line with the name of an existing proxy group, and make sure that group is set to the intended route.

There is no one-size-fits-all fallback policy. A proxy by default can cover unclassified services outside mainland China, but may send local services on a detour. Direct by default avoids unintended proxying, but requires rules for the services you want to route differently. Decide on the default behavior first, then add exceptions; this is much easier to troubleshoot than repeatedly switching global mode.

Testing and Troubleshooting: From the Running Config to a Fresh Connection

A good rule troubleshooting process follows the full chain: was the config loaded, did the request reach the core, which rule matched, and which route was ultimately used? A webpage either loading or failing is not enough to distinguish DNS, rule, and node problems.

  1. Check the final config: Confirm there is only one expected top-level rules: key, the list indentation is consistent, and no tabs are used. Find where the new rule actually appears, especially whether it was appended after MATCH.
  2. Check the load logs: If a policy is reported as missing, verify the proxy group name character by character. If a rule type is unsupported, check the core's capabilities; changing indentation won't resolve a feature mismatch.
  3. Send a new request: Close the existing connection first, then visit the test destination. In Connections, check the domain, destination IP, rule type, and proxy chain. Field names vary between clients.
  4. Isolate proxy entry issues: An explicit proxy request can rule out apps that ignore the system proxy. Still, confirm that the listening port belongs to the active core.
curl -I --proxy http://127.0.0.1:7890 https://example.com

This example assumes the local HTTP or mixed proxy port is 7890. If mixed-port is actually 7897, update the command to match. This tests the explicit HTTP proxy path; it does not by itself confirm that TUN capture works. In the earlier reject example, a failed request to that domain is expected—check the match log as well.

How to Triage Three Common Symptoms

  • Saved rules have no effect: Check the active config and final rule list first, then the operating mode. Finally, close old connections and try again. Don't immediately add duplicate rules.
  • Domain rules never match: Check whether the core has domain information. If it only has the destination IP and no usable domain mapping or sniffing result, it cannot identify a site from a domain rule alone.
  • The proxy group matches, but traffic takes the wrong route: Check the group's current selection and the proxy chain. Rules choose a policy; the proxy group then chooses the specific node. Check both.

For reliable changes, modify one type of rule at a time, validate the config, and retest with a new connection. Put specific rules first, broad rules later, and finish with MATCH. Use persistent overrides to prevent a subscription update from undoing your changes and restoring the old route.

Download ClashChoose a client for your platform