Why Use Rule Providers?
A Clash configuration can accumulate hundreds of routing rules over time. Keeping every rule in the main YAML file makes it harder to review changes, reuse a rule set in another profile, and update a list without touching unrelated proxy groups or DNS settings. A rule provider moves a collection of rules into a separate file and lets Mihomo fetch and maintain that file for you.
This separation is useful when you maintain your own domain lists, want to share a list across several profiles, or need to update a set of rules independently of a subscription. It does not create new proxy nodes or proxy groups. Instead, the provider supplies rules that your existing configuration references. Mihomo still evaluates the main rules: list in order and applies the policy specified by each matching rule.
This guide uses Mihomo, the maintained core commonly bundled with Clash Verge Rev and other Clash-compatible clients. The provider syntax shown here is intended for Mihomo. Older Clash cores and third-party clients may not support every option, so check the core version and the client’s configuration handling before copying the examples.
The Basic Pattern
Store a rule list in a separate file, declare it under rule-providers, and reference it from rules with a RULE-SET entry.
1Create a GitHub-Hosted Rule Provider
Start by creating a repository for your rules, or use a dedicated folder in an existing repository. A public repository is the simplest option because Mihomo can fetch its raw files without authentication. Keep the file focused on one purpose—for example, a list of domains for a service or a small collection of network ranges. Clear names make it easier to understand what a provider does when you return to the configuration later.
For a domain provider, create a YAML file containing one domain entry per line. With behavior: domain, the file is a list of domain names, not a list of full Clash rule expressions:
The +. prefix represents a domain and its subdomains. A plain entry such as api.example.net matches that specific host. Replace the example domains with domains you have verified are relevant to your routing policy. Do not assume that adding a broad suffix is harmless: an overly general entry can send unrelated traffic through the same proxy or direct route.
Next, add a provider declaration to your Mihomo configuration. Replace YOUR-NAME, YOUR-REPOSITORY, and the file path with your actual GitHub account, repository, and YAML file location. The URL must point to the raw file, not the regular GitHub page that displays the file in a browser.
Here, my-services is the provider name used later in the rules list. type: http tells Mihomo to retrieve the file over HTTP or HTTPS. behavior: domain tells it how to interpret the payload, while format: yaml identifies the file format. The local path is where the core stores its downloaded copy; choose a location the client can write to and keep the path distinct for each provider. interval: 86400 requests a refresh every 86,400 seconds, or one day.
Provider paths are local paths, not GitHub URLs. Their resolution and persistence can depend on the client’s working directory, profile handling, and permissions. If a client recreates temporary configuration files, a relative path may behave differently after a restart. Use the client’s supported profile directory or a documented writable location, and check the Mihomo log if the provider cannot be saved or loaded.
Keep the Repository Public and Predictable
A raw GitHub URL should return the YAML file directly. Do not put credentials, subscription links, private addresses, or other sensitive data in a public repository. For stricter change control, use a raw URL that points to a specific commit rather than a moving branch.
2Reference the Provider and Control Rule Order
Declaring a provider only makes the rule set available; it does not automatically route any traffic. Add a RULE-SET line to the main rules: list and choose the policy group or action that should receive matching requests. The provider name in the rule must match the key under rule-providers exactly.
In this example, domains in my-services go to the Proxy policy group. The later suffix rule sends matching traffic directly only if it was not already matched by the provider. The final MATCH rule catches traffic not handled by an earlier rule. Replace Proxy with a policy or group that actually exists in your configuration; an unknown target can make the configuration invalid or leave the routing result different from what you intended.
Rule order matters. Mihomo evaluates rules from top to bottom and uses the first applicable match. Put a provider above a broad rule that would otherwise capture its traffic, such as a general domain rule or a catch-all rule. A provider placed after MATCH will never be reached. Conversely, put a deliberate exception before the provider if that exception should take priority.
When a provider is designed to contain complete Clash rules instead of simple domain or IP entries, use behavior: classical. The payload then contains rule expressions, such as domain-suffix or process-name rules, rather than the compact domain entries shown above:
Declare that file with behavior: classical, then reference it using the same RULE-SET,provider-name,policy form. Do not mix formats casually: a domain provider expects domain entries, while a classical provider expects complete rule expressions. For IP ranges, use behavior: ipcidr and provide valid CIDR entries in the file. Select the behavior that matches the payload rather than trying to make one provider file serve incompatible rule types.
Do Not Add the Same Rule Twice Without a Reason
If a domain already appears in a provider, duplicating it in the main rules list can make later edits confusing. Keep exceptions explicit and place them intentionally before or after the provider according to the result you want.
3Test Updates and Diagnose Common Errors
Before relying on a new provider, validate the configuration and confirm that the raw URL serves the expected file. In a browser, open the raw URL and check that the response contains the YAML payload rather than a GitHub page, a sign-in prompt, or an error message. You can also use a command-line request to inspect the response:
After saving the profile, reload it using the client’s profile controls or restart the core if required. Then inspect the Mihomo log for provider download, parsing, or file-permission errors. Client interfaces differ: some expose provider status and manual update controls, while others rely more heavily on core logs. A successful configuration parse is necessary, but it does not by itself prove that a particular request matched the provider.
Test with a domain you deliberately placed in the provider. Check the connection or traffic details in the client and confirm both the matched rule and the selected policy. If the connection uses a different policy, verify that the domain is present in the fetched file, that the provider’s behavior matches the payload, that the provider name is spelled consistently, and that no earlier rule takes precedence.
Common Failure Checks
- The provider fails to download: Open the raw URL directly, confirm the repository and file are public, and check for a typo in the branch or file path. A normal GitHub web URL is not a substitute for a raw-content URL.
- The YAML file cannot be parsed: Check indentation, quoting, and the top-level
payload:key. Avoid tabs and confirm that each entry is valid for the selected behavior. A domain list is not interchangeable with a classical rule list. - The provider loads but matches nothing: Confirm the provider is referenced in
rules:, the name is identical in both places, and the provider rule appears before any rule that would capture the same traffic. Test a hostname that exactly corresponds to an entry. - Changes do not appear immediately: A provider may retain a local copy until its next refresh interval. Use the client’s manual update action if available, then check the log and the saved provider file. A branch URL follows the branch’s current content, while a commit-pinned URL intentionally stays fixed.
- The configuration works until the client updates a subscription: Some clients regenerate subscription profiles and may overwrite direct edits. Keep custom changes in a supported override, merge, or separately managed profile rather than assuming that edits to a generated file will persist.
- A broad rule routes too much traffic: Narrow the domain entries, add a specific exception in the correct position, and retest. Do not solve an unexpected match by placing a catch-all earlier, because that can prevent unrelated rules from running.
For maintainable updates, review changes before merging them into the branch that your profile fetches. Give the file and provider a clear purpose, avoid unrelated edits, and keep a known-good copy so you can roll back quickly. If the rule list is important to a daily workflow, test a change in a separate profile or with a small set of representative domains before applying it to every device.
Finally, treat a remotely hosted rule list as configuration you depend on. A GitHub outage, repository rename, accidental deletion, malformed commit, or network restriction can prevent a refresh. Keep the last working local copy available where practical, monitor provider status after significant edits, and use a commit-pinned URL when you need reproducible behavior. Branch-based URLs are convenient for automatic updates; commit-based URLs offer stronger predictability but require you to update the URL deliberately when approving a new version.
With the provider declaration, payload format, and rule order all aligned, custom rules become easier to reuse and maintain without turning the main Clash profile into an unmanageable list. Start with one narrowly scoped provider, verify its match in the client, and expand only after the download and routing behavior are clear.