Why move Clash rules into rule providers?
A long rules: list works well while a profile is small. Over time, however, personal exceptions, application domains, advertising filters, and team-maintained destinations can turn one configuration into a file that is difficult to review safely. A small edit near the bottom may accidentally change precedence, and sharing one reusable list with several devices can mean copying the same lines into multiple profiles. Clash rule providers solve that maintenance problem by storing a collection of matching rules separately and referencing it from the main configuration.
A provider is not a proxy server, a proxy group, or a subscription. It is a named source of rules that Clash loads into the routing engine. Your main configuration still decides what to do when a rule matches: for example, send a domain set to a policy group, reject a known unwanted destination, or direct a trusted local service. The provider supplies the matching criteria; the rule that calls RULE-SET supplies the action. Keeping those responsibilities distinct makes a configuration easier to audit and helps explain why a rule matched without confusing “which domains are in the list?” with “which outbound policy handles them?”
Externalizing rules is most valuable when a list is reused, changes independently from the rest of a profile, or needs a clear review history. It is less useful for a handful of stable, highly specific exceptions that are easier to understand inline. Providers also introduce a dependency: a client must fetch, parse, and refresh the remote file. Treat the repository and its update process as part of your network configuration, not as an infallible extension of the client.
This guide uses the modern Mihomo-compatible rule-provider form. Individual Clash-derived clients can bundle different core versions or expose different update controls, so confirm that the core actually running in your client supports the fields you use. A GUI label may say “Clash” even when the embedded engine and accepted configuration schema differ from another application. For routing precedence and the interaction between specific rules and catch-all rules, see our Clash rule routing best practices guide.
Choose a provider format and hosting model
Before creating a GitHub repository, decide what kind of rules the file will contain. Mihomo rule providers commonly use a behavior such as domain, ipcidr, or classical. A domain provider is appropriate for domain-oriented matches, an IP CIDR provider describes address ranges, and a classical provider can hold supported full rule expressions. The declared behavior must agree with the entries you publish; it is not a cosmetic label that asks the parser to guess what you meant.
The serialized file format is a separate choice from behavior. For a YAML provider, use a YAML document with a payload list. Each list item should be a string in the syntax appropriate to the provider’s behavior. For instance, a domain list may use DOMAIN or DOMAIN-SUFFIX expressions, while a classical list may contain full supported rules such as a domain suffix or process-name match. Do not paste a complete Clash profile into a provider file: provider content is a rule collection, not a second top-level configuration with its own rules: and proxy-groups: sections.
GitHub offers two practical hosting patterns. A raw file URL from a repository is convenient for a personal list and keeps the source, commit history, and review discussion together. A GitHub Pages URL can provide a stable public address when you want to publish generated files from a separate branch or directory. Neither approach removes the need to check availability, response content, and access permissions. A private repository may require authentication that your Clash core does not have, and a login page or error page returned in place of YAML will not become a valid provider merely because its URL ends in .yaml.
A moving branch such as main is convenient for routine updates because the same URL serves the newest committed version. It also means that an upstream change can alter routing at the next refresh. For a high-assurance environment, pin the URL to a reviewed commit or publish a release-specific file, then update the reference deliberately. If you choose a moving branch, protect it with review requirements and keep changes small enough to inspect. Avoid using a raw URL copied from a temporary preview or a personal fork that may disappear when its owner changes accounts.
Keep the repository structure understandable. One provider per purpose is usually easier to maintain than a single enormous list with mixed semantics. Separate files can distinguish, for example, work domains, local services, and a carefully curated block list. Name each file by its function, document its intended action in the main configuration, and make sure the repository README explains who maintains it and how additions are reviewed. This is especially useful when a colleague needs to decide whether a surprising match is intentional or a stale entry.
Write the YAML provider and reference it from Clash
Start with a short, valid file and a small number of representative entries. A domain provider might look like this:
payload:
- DOMAIN-SUFFIX,example.org
- DOMAIN,api.example.net
The entries above are examples only; replace them with destinations you are authorized to route and syntax supported by your core. Keep indentation consistent, use spaces rather than tabs, and quote a value if its characters could be interpreted unexpectedly by YAML. A provider file should contain no unrelated headings, Markdown fences, comments that break a parser, or HTML copied from a repository page. Before publication, inspect the raw response rather than relying only on how the file appears in GitHub’s web interface.
In the main profile, define the provider under rule-providers, give it a stable local cache path, and then invoke it in rules. A minimal example is:
rule-providers:
example-sites:
type: http
behavior: domain
format: yaml
url: https://raw.githubusercontent.com/OWNER/REPOSITORY/main/rules/example-sites.yaml
path: ./ruleset/example-sites.yaml
interval: 86400
rules:
- RULE-SET,example-sites,Proxy
- MATCH,DIRECT
Substitute the repository owner, repository name, file path, and policy group with values that exist in your setup. The example’s interval is expressed in seconds; choose an interval that matches how often the list genuinely changes rather than refreshing every few minutes by habit. A longer interval reduces needless requests and limits how frequently a remote edit can affect your routing. It does not guarantee that an update succeeds at a particular time, so check the client’s provider status or logs when freshness matters.
The local path is where the core stores its downloaded copy; it is not the GitHub URL and should not be confused with a browser download destination. Use a distinct file path for each provider, and keep the provider names unique within the profile. The value after RULE-SET must match the provider name exactly, and the action must refer to a policy group or supported action that exists in the same configuration. A correctly fetched file can still have no effect if the name is misspelled or the calling rule is never reached.
Rule order remains decisive. Clash evaluates rules in order and uses the first matching rule, so place a provider call where its scope belongs relative to specific exceptions, other providers, and broad rules such as MATCH. If a domain is meant to stay direct even though it appears in a broader provider, put the exception earlier. Conversely, an early broad provider can capture traffic before a later, more specific rule has a chance to handle it. When testing, check both the matching rule and the selected policy group rather than assuming the provider’s presence alone determines the outcome.
For a classical provider, declare behavior: classical and place supported rule expressions in the payload. For IP ranges, use the appropriate IP CIDR behavior and valid CIDR notation. Do not mix unrelated entry types simply because YAML accepts them as strings: semantic validation belongs to the core and may fail when it tries to interpret a rule. Start with one behavior per provider unless you have verified that the exact core version supports the structure you intend to use.
Publish changes and control scheduled updates
Create the repository, add the provider file at the path used in the URL, and commit it. Then open the raw URL directly in a browser or retrieve it with a command-line HTTP client. Confirm that the response contains the expected YAML rather than a GitHub sign-in page, a 404 page, a repository landing page, or a proxy-generated block page. A URL that looks plausible in the address bar is not proof that the core receives the intended file.
Before connecting the provider to your everyday profile, validate its YAML and inspect the diff. A simple YAML parser can detect indentation errors and malformed document structure, but it cannot necessarily determine whether every Clash-specific rule expression is semantically valid. Core-level validation is still necessary. Test a temporary profile or a low-risk environment first, then examine logs for provider initialization, download, and parsing messages. If the client supports a manual provider update, use it to verify the initial fetch before relying on the scheduled interval.
Keep update responsibility explicit. The interval in the main profile requests periodic refreshes for an HTTP provider, but it does not edit the repository or prove that GitHub has a newer commit. If changes are infrequent, a daily or longer interval may be sufficient; if a list is operationally sensitive, pair a sensible interval with a review and notification process. Avoid publishing rapid automated changes without checking the resulting file: a scheduled job that repeatedly commits broken output can make a bad provider consistently available.
For teams, a basic GitHub workflow can validate each proposed change before merging. A useful pipeline checks YAML parsing, verifies that the top-level payload is a list, rejects empty or duplicate entries when those are not intentional, and optionally runs a core-aware validation tool. Have a maintainer review changes that broaden a match, alter an IP range, or introduce a rule that could capture a large share of traffic. Publish only after the checks pass. The commit history then provides a practical answer to “when did this routing behavior change?” and gives you a known revision to restore if an update causes trouble.
Decide how you will recover before you need to. Keep a last-known-good commit or file, and record the provider URL and expected behavior alongside the profile. If a newly published list causes unexpected matches, revert the offending change or point the profile to a reviewed revision, refresh the provider, and verify that the cached copy has updated. Merely restarting Clash may not solve the problem if the same invalid or unwanted content is downloaded again. In managed environments, coordinate repository permissions and review rules with the people responsible for the network policy.
Troubleshoot providers that fail to load or update
When a provider appears unavailable, separate transport failure from parsing failure. A DNS error, TLS handshake problem, timeout, or HTTP status error points toward reachability, repository permissions, or an incorrect URL. A successful HTTP response followed by a YAML or rule error points toward file content, format, or behavior. The distinction matters: changing YAML indentation cannot repair a blocked request, and changing the proxy group cannot make an HTML error page parse as a rule list.
If the client reports that the provider loaded but traffic does not follow it, verify the complete chain. Confirm that the active profile—not an old profile tab—contains the provider declaration; check that the provider name in RULE-SET matches; ensure the rule appears before any rule that would already match the same request; and confirm that its target policy group exists. Then inspect the actual requested host and the core’s rule-matching log. A browser page may contact several domains, so a single domain appearing in the list does not imply that every connection involved in the page load uses the same route.
A provider that updates in one client but not another often points to differences in core version, configuration path, cache state, network access, or client refresh behavior. Compare the exact URL and provider settings first, then check each client’s logs and last-update status. Some interfaces distinguish between refreshing the profile and refreshing an individual provider; one action may not perform the other. Be cautious about deleting cache files by hand because their location varies, and removing the wrong file can make diagnosis harder. Prefer the client’s documented refresh or reload controls.
If a provider loads inconsistently, inspect the raw file for accidental changes in encoding, line endings, indentation, or top-level structure. Ensure that the file remains a YAML document with the expected payload, that every entry is represented as a string, and that the selected behavior matches the contents. A repository can also return a temporary error or rate limit response; retry after confirming what the server actually returned instead of assuming the cached file is current. Do not respond to an intermittent fetch issue by making the refresh interval extremely short, which can amplify requests without fixing the underlying cause.
Finally, make updates observable. Record a last-reviewed date in the repository documentation, use descriptive commit messages, and note which provider and policy group are expected to change when a revision is published. During troubleshooting, capture the active core version, provider status, relevant log lines, and the commit currently served by the URL. This evidence makes it possible to distinguish a bad rule from a stale cache or unreachable host and gives another operator enough context to reproduce the result.
Inline rules remain simpler than providers for a few stable exceptions, while some GUI clients offer convenient built-in lists that reduce setup but may provide less control over review history, hosting, or update cadence. When you need reusable, inspectable YAML rules, a GitHub-hosted provider gives you a clear source and a deliberate update path—provided you validate changes and keep rule order understandable. If you want a client workflow that makes profile and routing management easier to inspect than a hand-maintained collection of tools, compare your current setup with Clash V.CORE and download Clash V.CORE to test it with your own validated provider files.