YAML fields, references, and runtime configuration

Clash Configuration File
Reference Guide

Look up ports, DNS, proxy groups, rules, and overrides. First identify the field’s level, then check whether your current core supports it.

If you’re importing a subscription or enabling the system proxy for the first time, follow the user guide to connect. This page explains why configs are written this way and where to check the results of a change. If you hit an error, use its line number to find the relevant section.

01 YAML Structure & References

A Clash config isn’t a sequence of commands to run in order; it’s data that describes network behavior. The top level usually contains listening ports, operating mode, DNS settings, proxy nodes, proxy groups, and rules. The core reads the file and creates these objects, then uses matching rules to choose an outbound route for each connection. A file that saves successfully doesn’t guarantee a node can connect, and valid syntax doesn’t guarantee every reference points to an existing name.

Indentation defines field ownership

YAML uses spaces to express nesting. Use two spaces consistently and never mix in tabs. Put a space after a colon when it’s followed by a value, and start list items with a hyphen and a space. Fields at the same level must line up. A one-space indentation slip can put a top-level rules list inside the DNS object, causing the field to be ignored or a type error to appear. Turning on whitespace markers is more reliable than judging indentation by eye.

# Minimal standalone config for testing; direct connections only, no proxy nodes
mixed-port: 7890
allow-lan: false
mode: rule
log-level: info

dns:
  enable: true
  enhanced-mode: fake-ip
  fake-ip-range: 198.18.0.1/16
  nameserver:
    - 223.5.5.5

proxies: []
proxy-groups: []

rules:
  - MATCH,DIRECT

The example checks whether the config loads, but all connections go direct, with no proxy outbound. An empty list is written as []; it means there are no entries, not that the field is missing. If you’re troubleshooting editor or folder permissions, start with this minimal file to verify the loading path, then add your own nodes and proxy groups one section at a time. Don’t start by wiring in a full subscription, external rules, and override scripts all at once.

Strings, booleans, and lists

Write booleans as true or false, ports as integers, and node names and rule strings in quotes when needed. Take extra care with names containing colons, hash signs, or other special characters: a hash may start a comment, and a colon followed by a space may be read as a mapping separator. Even if a password contains only digits, quote it to preserve it as a string and avoid type changes when it’s read.

Block-style YAML is easier to scan; inline mappings in braces are more compact, and both can represent the same object. This guide favors block style so it’s easy to see which fields belong together. Don’t wrap the YAML in an extra layer of Markdown fences; code fences on a webpage aren’t part of the config. Copy only the code itself, and save it as plain text—not a document created by a rich-text editor.

Names form a chain of references

A proxy group references a node’s name, and a rule references the group’s name. References must match the full name, including spaces, capitalization, and punctuation. If you rename a group but don’t update the target in your rules, the core may report that the proxy doesn’t exist. To track down this kind of error, follow the rule target backward: find the group with the same name, then check that each member it references exists.

Don’t repeat top-level keys. Two rules keys don’t automatically concatenate, and two dns keys don’t automatically merge. Parsers may reject duplicate keys or keep only one. To add rules, edit the existing list; to preserve a subscription’s structure, use an override mechanism explicitly supported by your client. YAML itself can’t infer that you meant to “join these two sections.”

When working with subscriptions, distinguish the source config from the runtime config. After downloading a subscription, the client may apply port overrides, DNS overrides, or merged rules. Editing the source file in Profiles without seeing a change doesn’t necessarily mean the core failed to read it; a later setting may have overwritten it. Note the active config’s name and source, and verify each change against the actual runtime config and logs.

02 Ports, Modes & Access Boundaries

Port fields describe where the client accepts connections on your local machine, not the port on a remote server. A browser or command-line tool sends requests to this local endpoint, where the core can then route them according to your rules. After changing a port, apps using the old one won’t update automatically. Windows system proxy settings, standalone browser settings, and terminal environment variables may each store their own address, so check them all.

Separate listeners and mixed ports

FieldPurposeCommon point of confusion
portHTTP proxy listenerSupports tunnels via CONNECT; that doesn’t mean it can only access HTTP websites.
socks-portSOCKS proxy listenerThe app must support SOCKS; the same port number doesn’t make it an HTTP proxy.
mixed-portShared HTTP and SOCKS listenerThe listener detects the protocol, but the app must still be configured with the correct proxy type.
allow-lanWhether LAN access is allowedAlso depends on the listening address and your operating system’s firewall.
# General-purpose fields for local use
mixed-port: 7890
allow-lan: false
bind-address: 127.0.0.1
mode: rule
log-level: info
ipv6: false

If you don’t need to share the connection over your LAN, keep access limited to this machine. The listener address and access setting in the example are both intended for local use. To share it with a phone or another computer, enabling Allow LAN alone isn’t enough: set the listener address to cover the relevant network interface, allow trusted network access in the firewall, and enter this computer’s LAN address on the other device—not its own loopback address.

A listener often fails because its port is already in use. First close any duplicate client instances, then check which process owns the port. Don’t keep switching ports and forget to update app settings. Run the command below in a Windows terminal to see the listener and process ID for that port. This helps identify what’s using it; don’t terminate a process just because you see its ID. Check its name and purpose in Task Manager first.

netstat -ano | findstr :7890

Rule, global, and direct modes

mode: rule routes connections according to the rules, in order, and is suitable for everyday split routing. Global mode sends connections to the selected global policy, but only if the traffic reaches the core in the first place. Direct mode sends intercepted connections straight to their destinations. The mode isn’t a system-wide traffic interception switch: changing from rule mode to global won’t make an app that ignores the system proxy start using one.

System Proxy in General is a client action that sets the Windows system proxy; it isn’t the same as the YAML operating mode. It usually affects apps that follow the system proxy. TUN uses a virtual network adapter and routes to capture traffic, and requires support from the core, permissions, and services. Don’t assume Service Mode or TUN Mode in legacy Clash for Windows works the same way as the equivalent features in current Mihomo clients.

Don’t confuse logs with the control interface

For everyday use, log-level can stay at info; temporarily switch to debug when troubleshooting. Debug logs may contain destination domains, connection details, and config paths. Remove subscription URLs, credentials, and personal browsing records before sharing them. More logs don’t necessarily make an issue easier to diagnose. Reproduce it once, then find the relevant connection in chronological order instead of collecting everything over a long period.

The external control interface lets a client UI or dashboard manage the core; it is not a proxy endpoint for apps. If you need to configure external-controller, bind it to the loopback address whenever possible. If remote access is essential, set up authentication and access controls separately. Don’t enter the control interface’s port as a browser proxy, and don’t expose an admin interface to your entire LAN just to let other devices get online.

Top-level ipv6 and IPv6 options in the DNS module have different scopes. Disabling one field doesn’t disable IPv6 on your system’s network adapter or change every app’s DNS resolution path. If certain destinations fail only on particular networks, check system addresses, DNS responses, rule matches, and outbound connectivity. Don’t attribute every problem to a port or a single proxy toggle.

After changing fields in this section, first check that the core is listening, then verify the app’s proxy address, and finally check the mode and outbound route. This order helps distinguish an unreachable local endpoint from a remote connection failure. For setup steps, see the system proxy guide. If you still can’t connect after closing the client, see the FAQ for troubleshooting leftover system proxy settings.

03 DNS & Domain Resolution

DNS translates domain names into addresses, but proxy configurations don’t always resolve them at the same point. The system may resolve a name first, an app may use its own resolver, the core may intercept the request, or the remote proxy may handle the final lookup. To find out whether a DNS setting is working, ask where that particular query entered the system and which resolver answered it—not just whether the config contains a familiar-looking server list.

A local listener doesn’t automatically intercept DNS

# Basic DNS snippet; use an unprivileged port for the local test listener
dns:
  enable: true
  listen: 127.0.0.1:1053
  ipv6: false
  enhanced-mode: fake-ip
  fake-ip-range: 198.18.0.1/16
  fake-ip-filter:
    - "*.lan"
    - "localhost"
  nameserver:
    - 223.5.5.5
    - 119.29.29.29

enable turns on the core’s DNS module, and listen sets the listener address. The example uses a loopback address and an unprivileged port for testing; it won’t automatically redirect every Windows DNS request. Standard DNS settings for a network adapter usually accept only a server address, not a string with this custom port. Full interception also requires the relevant client or TUN configuration.

nameserver is a list of upstream resolvers, not necessarily a strict primary-and-backup sequence. Concurrency, caching, and selection behavior can differ between cores. If you add multiple servers, a failure doesn’t necessarily mean “the first one is broken.” To test, reduce the variables: start with one upstream that’s reachable from your current network, verify the basics, then add encrypted DNS or domain-based routing.

Fake IP and real addresses

Fake-IP mode first returns a mapped address to the app, while the core keeps track of the association between that address and the domain. Once the connection reaches the core, it can route it based on the domain. This preserves domain information, but depends on DNS queries and connections following the same interception path. If an app gets a mapped address and then connects directly, outside the core, access may fail. Stale cached results after closing the client can also cause temporary connectivity issues.

fake-ip-filter excludes selected domains from receiving mapped addresses. Local network discovery, some device services, and apps that require real addresses may need exceptions, but a longer list isn’t automatically better. Excluding every frequently used domain changes the expected resolution path. Add the smallest exception that fixes a reproducible issue, clear the relevant app cache after changing it, and check the result.

Redir Host generally returns real addresses and can suit some scenarios where mapped addresses aren’t accepted, but it won’t fix every app compatibility issue. Whether domain information is preserved, the system resolves the request first, or the destination address changes can all affect rule behavior. Choose a mode by testing it with your app and interception method, not by assuming one is always faster than the other.

Mihomo domain-based DNS policies

# Mihomo snippet: add this to the existing dns object; do not create a second dns key
dns:
  nameserver-policy:
    "+.example.com":
      - 223.5.5.5
  proxy-server-nameserver:
    - 223.5.5.5

nameserver-policy assigns upstream resolvers to specific domains. This example shows the field structure only; the reserved example domain doesn’t need special handling. Mihomo’s proxy-server-nameserver resolves proxy server hostnames. These fields address different names: the domain of the website you’re visiting and the hostname of the proxy node you’re connecting to. Don’t treat them as the same DNS step just because both involve domains.

If a proxy node uses a hostname, DNS may be needed just to start the connection. If resolving that node requires going through the node itself, you’ve created a bootstrap loop. First check that the server hostname can be resolved through an independent, working path; then consider whether website lookups should use the proxy. If an encrypted DNS upstream also uses a hostname, check its bootstrap resolution and connection path. Changing just one address won’t necessarily break the loop.

A DNS leak test shows which resolver egress was observed under its particular test conditions; it doesn’t establish a single result for all traffic. Browser secure DNS, an app’s own DoH, the system cache, or LAN DNS may bypass the expected path. Check browser settings, the core’s DNS logs, and TUN interception separately. One website test can’t replace verifying the actual resolution path.

04 Proxy Node Fields & Protocol Compatibility

The proxies list stores the details for each proxy outbound. Each entry needs enough information to identify the protocol, server address, and port; authentication fields vary by protocol. A node name shown in the client is only a local label—it doesn’t replace authentication details. Renaming a node to make it easier to recognize won’t change the server location or give it protocol features the server doesn’t support.

Check the address first, then authentication

# Example proxy entries: reserved domain and dummy password cannot be used to connect
proxies:
  - name: "Example SS"
    type: ss
    server: ss.example.com
    port: 443
    cipher: aes-128-gcm
    password: "your-password"
    udp: true

  - name: "Example Trojan"
    type: trojan
    server: trojan.example.com
    port: 443
    password: "your-password"
    sni: trojan.example.com
    skip-cert-verify: false
    udp: true

server should be a hostname or IP address. Don’t paste in a full webpage URL with a scheme, path, and query parameters. port is the port the remote service listens on; it doesn’t need to match your local mixed-port. Use the values supplied by your service. A port’s popularity for websites doesn’t mean every proxy node should use it.

The Shadowsocks cipher and password must match the server. The cipher isn’t a performance option you can choose at will; a typo or unsupported cipher will cause a connection failure. Key formats may also differ between protocol generations, so changing only the protocol name while keeping the other fields can’t work. If your subscription already provides working nodes, keep their original parameters rather than removing fields you don’t recognize.

TLS, SNI, and certificate verification

TLS nodes often require a server name, certificate, and transport settings. SNI is the server name sent during the TLS handshake and may differ from the IP address used for a direct connection; follow the server’s actual configuration. A certificate error doesn’t necessarily mean the password is wrong. It could be caused by an incorrect system clock, a name mismatch, or interference along the network path. Check the error type in the logs before deciding which fields to review.

skip-cert-verify: false keeps certificate verification enabled. If a handshake fails, disabling verification shouldn’t be your go-to fix; it may hide a server name or certificate configuration problem. Check the system clock, then verify the SNI against your provider’s instructions. If many nodes in a subscription suddenly show certificate errors, also check whether you loaded the wrong file or are behind a network gateway that requires authentication.

VMess, VLESS, Trojan, Shadowsocks, and other protocols don’t share the same authentication fields. Some require a user ID, others a password, and some need specific transport and security settings as well. This guide doesn’t offer a “universal node” mixing every field: unsupported fields may be ignored, making it look as if an error has been fixed. Use a complete node definition that matches the protocol.

Both ends must support the transport

udp: true expresses the intent to allow UDP on that node; whether it actually works also depends on the protocol, server, network, and how traffic enters the core. The HTTP listener commonly used by system proxy settings can’t automatically intercept UDP from every app. If a game or voice app fails, first check whether its traffic reached the core, then confirm UDP support on the node instead of repeatedly toggling this one YAML line.

For WebSocket, gRPC, and other transports, the path, host header, and service name must match the server. A website loading successfully doesn’t mean the proxy handshake parameters are correct; a TCP connection to the server port doesn’t prove protocol authentication succeeded. A connection timeout, authentication failure, and interrupted handshake in the logs each point to a different stage. Troubleshoot that stage rather than changing every parameter at once.

The current core must support any new protocol or extended fields. Adding a few Mihomo settings won’t give the legacy Clash for Windows core new capabilities. When migrating, compare what Clash Plus, Clash Verge Rev, FlClash, and other clients actually support; see the client comparison. A client’s ability to import a file doesn’t guarantee its runtime core accepts every node type in it.

Finally, make sure node names are unique. Duplicate names can make references ambiguous, and subscription updates may change node names or order. For manual configs, use names that describe the node’s purpose; never include passwords, full subscription URLs, or personal account details. Remove credentials and private server information before sharing a config to troubleshoot. The field structure and error message are usually enough to tell a formatting issue from a protocol compatibility issue.

05 Proxy Group Selection & Health Checks

Proxy groups sit between rules and nodes. Rules pass connections to a stable group name, and the group chooses an outbound. That way, changing nodes doesn’t require rewriting every rule. Understand this indirection before designing groups: use one for manual selection, another for automatic testing, and separate groups for specific workloads where needed. There’s no need to duplicate the same members for every website.

Separate manual and automatic selection

# Uses the two example proxy nodes defined in the previous section
proxy-groups:
  - name: "Proxy Selection"
    type: select
    proxies:
      - "Auto Select"
      - "Example SS"
      - "Example Trojan"
      - DIRECT

  - name: "Auto Select"
    type: url-test
    proxies:
      - "Example SS"
      - "Example Trojan"
    url: https://www.gstatic.com/generate_204
    interval: 300
    tolerance: 50

select is a manual selection group; the client UI usually lets you switch members directly. Members can be nodes, other proxy groups, or built-in outbounds such as DIRECT. The example includes the automatic group as an option, so you can use automatic testing day to day or pin a specific node temporarily. These names are examples; if you change them, update the rule references too.

url-test compares candidate outbounds using test requests. interval is the check interval, usually in seconds; tolerance helps prevent frequent switching due to small differences. Check the current core’s documentation for its exact meaning and units. Common implementations express tolerance in milliseconds. Don’t set an extremely short interval just to make the UI refresh constantly: health checks also generate connections and traffic.

A successful test doesn’t guarantee it works for your use case

A successful test request means a request to that address through that outbound completed at that moment. It doesn’t predict how video, downloads, games, or work systems will perform. The latency reading may reflect connection setup, the handshake, and the response time, but it doesn’t directly measure sustained bandwidth. Even a node with a low test latency can perform poorly for real workloads due to congestion, packet loss, or destination-side restrictions.

Choose a stable test URL that returns the expected response, then verify performance against your actual use case. If every node fails its test at once, check whether the test target is reachable and DNS is working before concluding that all the servers are down. For the difference between latency figures and real-world performance, see How Proxy Latency Tests Work.

Failover and load balancing

fallback usually selects the first available outbound in its candidate list, making it suitable for a primary and backup connection. It isn’t another name for automatically choosing the lowest-latency node. load-balance distributes connections according to the supported strategy; it won’t simply combine multiple nodes’ bandwidth to speed up a single connection. If a website is sensitive to login sessions or changes in exit IP, consider whether the distribution method will affect session stability.

Keep nested proxy groups easy to follow. For example, “Work” can reference “Proxy Selection,” which in turn references specific nodes. Don’t have two groups reference each other, creating a loop. If you see a missing-group or circular-dependency error, map the one-way path from the rule to the node and expand any indirect references. More groups mean more complex troubleshooting, so start with a small number of groups whose purpose is clear.

Whether to include DIRECT in an automatic test group depends on your goal. It may pass the test and get selected, but connections will then go direct rather than through a proxy. If the purpose of a group is to always use a proxy, don’t let direct connections compete just because they have a lower test latency. The candidate list affects behavior more than small tweaks to the test interval.

Clients may remember a proxy group’s selection, so reloading doesn’t necessarily reset it to the first entry. If the correct rule is matched but traffic takes an unexpected route, inspect the group’s active selection and follow nested groups all the way to the final node. The outer group name alone doesn’t tell you the actual route. After switching subscriptions, check the client’s persistence settings to see how it restores selections for groups with the same name.

When providers supply nodes, a proxy group can use use to reference a node collection; see Section 07 for details. In that setup, provider health checks and group-level tests may run at the same time, so avoid duplicating checks at overly short intervals. After changing a group, confirm the config loads, switch the selection once in the UI, and check the actual outbound for a new connection to ensure the reference points where you expect.

06 Rule Syntax & Match Order

In rule mode, rules are typically checked from top to bottom, and a matching connection is passed to the selected policy. Put specific exceptions first, broader matches later, and the catch-all last. The rule list doesn’t automatically calculate the “most specific” route: once an earlier broad rule matches, later, more specific rules may never get a chance to handle that connection.

Put specific exceptions before the catch-all

# Uses the existing "Proxy Selection" group
rules:
  - DOMAIN,portal.example.com,DIRECT
  - DOMAIN-SUFFIX,example.com,Proxy Selection
  - DOMAIN-KEYWORD,example,Proxy Selection
  - IP-CIDR,192.168.0.0/16,DIRECT,no-resolve
  - IP-CIDR,10.0.0.0/8,DIRECT,no-resolve
  - GEOIP,CN,DIRECT
  - MATCH,Proxy Selection

DOMAIN matches an exact domain, DOMAIN-SUFFIX matches that domain and its subdomains, and DOMAIN-KEYWORD checks whether a domain contains a keyword. Keyword matches are often broader than expected and may catch unrelated services with similar names. If you know the target domain, prefer an exact or suffix rule; avoid sacrificing clarity just to write fewer lines.

The example puts a direct-access exception for a portal before the domain suffix rule, so the portal won’t be routed through Proxy Selection. Swap the two rules and the suffix rule catches the request first, making the exception ineffective. If a rule seems to have no effect, first check for an earlier matching rule rather than repeatedly adding the same rule at the bottom.

Domain rules and IP address rules

IP-CIDR checks whether a destination address is in a specified subnet. The trailing no-resolve means not to resolve a domain to an IP just for this address rule; if the connection already has a destination address, the rule may still match it. This isn’t a “disable all DNS” switch and won’t disable domain rules. It’s commonly used for LAN address exceptions to avoid unnecessary lookups.

GEOIP uses an IP address database to identify the destination IP’s region. It doesn’t look at where a domain is registered, a webpage’s language, or where the service provider is based. A website using a multi-region CDN may return different addresses for the same domain. If a service needs a specific route, use a clear domain rule rather than expecting a geolocation database to categorize every use case correctly.

MATCH is the catch-all and usually belongs at the end. It gives connections not handled by earlier rules an explicit outbound. If you put it in the middle of the list, later rules generally won’t take effect. Whether the catch-all goes through a proxy or direct depends on your needs. The example uses “Proxy Selection,” but that doesn’t make it the right default for every network.

Check rule matches on new connections

After changing rules, existing long-lived connections may continue using their original outbound, and browsers may reuse connections or cached resources. To verify a change, start a new request and, if needed, close old connections. Then check the matched rule, proxy group, and final outbound in Connections or the logs. Don’t decide a rule is broken based on one page refresh, and don’t stop at the group name without checking its active node.

Process rules depend on whether the operating system and core can identify the process. On Windows, permissions, interception methods, and app structure can all affect the result; browser child processes and system services may not have the names you expect. Before writing a rule, check the process information in connection records and use syntax supported by the current core. For configs shared across platforms, domain rules are usually easier to maintain than hard-coded local paths.

When you have a large ruleset, organize it around your use cases before deciding whether to delegate it to external rule sets. Keep LAN exceptions, service-specific exceptions, general routing, and the final catch-all clearly separated. Don’t concatenate rules from unknown sources just to make the config seem comprehensive. A longer list isn’t necessarily more accurate; conflicts and duplicates make it harder to explain why a rule matched.

If a rule fails in only one app, check how its traffic enters the core. Even a correct rule can’t do anything if the core never sees the connection. If the app resolves a domain to an IP before the request reaches the core, domain matching may also be affected. Check traffic entry, DNS resolution, matching, and outbound separately; this is often faster than adding more broad rules.

07 Proxy Subscriptions & External Rule Sets

Providers keep frequently changing content separate from the main config. A proxy provider manages a set of nodes, while a rule provider manages a set of match conditions; the main config keeps only the references and routing relationships. This lets you update nodes without rewriting local groups, or update rules without downloading the entire config again. However, providers add dependencies for downloading, parsing, caching, and references. A successfully loaded main config doesn’t prove that all provider content is available.

A full subscription isn’t the same as a proxy provider

# Local proxy provider example; create the corresponding file first
proxy-providers:
  local-nodes:
    type: file
    path: ./providers/local-nodes.yaml
    health-check:
      enable: true
      url: https://www.gstatic.com/generate_204
      interval: 600

proxy-groups:
  - name: "Subscription Selection"
    type: select
    use:
      - local-nodes

The example uses a local file to avoid including a private subscription URL in a tutorial. The current core must be able to read the file, and it must contain the data structure expected by a proxy provider. Relative paths are usually resolved from the load or working directory, which the client may set itself. Check logs and the client’s file management options to find the actual location; don’t guess based only on where the main config is stored.

# Example contents of providers/local-nodes.yaml
proxies:
  - name: "Local Example SS"
    type: ss
    server: ss.example.com
    port: 443
    cipher: aes-128-gcm
    password: "your-password"

A full subscription may include ports, DNS, proxy groups, and rules, while a proxy provider usually needs only a collection of nodes. Don’t assume the core can understand any subscription URL just because you put it in proxy-providers. First check the format supplied by your service and what the current core supports, then decide whether to import the full subscription or reference it as a node collection. A format mismatch may leave the provider empty without causing the main config to fail outright.

Organize rule providers by behavior

# Mihomo local rule provider snippet
rule-providers:
  local-direct:
    type: file
    behavior: classical
    format: yaml
    path: ./rules/local-direct.yaml

rules:
  - RULE-SET,local-direct,DIRECT
  - MATCH,Subscription Selection
# Example contents of rules/local-direct.yaml
payload:
  - DOMAIN-SUFFIX,example.com
  - IP-CIDR,192.168.0.0/16,no-resolve

This rule file wraps its entries in payload; the main config’s RULE-SET determines the outbound. Don’t paste a regular rules list into it unchanged, and don’t append a proxy group to every item. The rule set describes what to match; the main config connects it to an outbound. That separation makes it easier to reuse the same rules in different environments.

behavior must match the format of the rules. Domain lists, IP address lists, and classical rule entries aren’t interchangeable. Treating classical rules as a plain domain list may cause a parse error or produce entirely different matches. Mihomo supports other rule formats that legacy cores may not. For shared configs, use the intersection of formats that the target cores actually support rather than testing once in your own client.

Troubleshoot update failures in four stages

Remote providers also need a reachable download URL, an update interval, and a cache path. Check four stages: first, whether the network request succeeded; second, whether the response contains the expected YAML or rule data; third, whether the core can parse it; and fourth, whether a proxy group or rule actually references it. A webpage may return a login screen, subscription quota message, or error. An HTTP response doesn’t mean you received usable config data.

Update intervals are generally specified in seconds. Frequent refreshes aren’t a fix: the server may limit requests, and simultaneous updates from several clients may trigger those limits. Keep a working cache, then try one manual update and check the error. If you don’t know why an update failed, don’t clear every cache; a temporary download issue could leave you with no usable nodes at all.

Subscription URLs often contain private authorization details, so treat them like passwords. Screenshots, logs, and exported runtime configs may expose the full URL. If you need help, replace it with a reserved example domain while keeping the response status, parse error, and relevant field structure. Don’t give private subscriptions to unknown online conversion tools or include someone else’s subscription URL in a public config example.

After a node collection updates, name changes can affect manual selections or filters. Check that the provider has the expected number of entries, the proxy group still has candidates, and new connections use the expected outbound. If a download succeeds but the group contains no nodes, check reference names, format, and filter conditions. For specific error messages, see the subscription update FAQs and work through them one by one.

08 Overrides, Merging & Runtime Validation

Subscriptions update remote content; local overrides preserve your personal settings. Without a clear boundary, a subscription update may wipe out your rules, or a UI setting may overwrite edits to the source file. Find the client’s config management options first, and identify whether you’re editing a subscription source, an override snippet, or the final runtime file. Clash for Windows Mixin and the merge or scripting features in other clients aren’t interchangeable just because their names sound similar.

Merge behavior must be explicitly defined by the implementation

YAML describes data; it doesn’t specify how multiple files are merged. A client may recursively merge mappings, replace lists outright, or provide dedicated before-and-after rule insertion. Similar-looking “merge” buttons in different tools don’t guarantee the same behavior. Before applying a short rules list, find out whether it appends to the existing rules or replaces the entire list. Otherwise, you could end up with only your two rules.

# Example override intent: use only if the client supports this merge behavior
mixed-port: 7890
allow-lan: false
log-level: info

dns:
  ipv6: false

The example describes a fixed local listener and a few DNS options; it isn’t a complete runtime config. Loaded on its own, it lacks the rest of the network configuration. If a shallow merge replaces the entire DNS object, it may also remove existing upstreams. Apply it to a copy first, then inspect the generated config and confirm it still contains the existing nameserver, nodes, proxy groups, and rules.

To add personal rules, use a rule insertion point explicitly provided by the client. Put service-specific exceptions first and keep the final catch-all at the end; adding rules after an existing MATCH won’t work as intended. If the client can’t reliably merge rule lists, consider having a local main config reference a proxy provider instead of repeatedly editing the rule list generated from a full subscription.

Distinguish files, UI settings, and runtime state

Config sources may pass through several steps: downloading a subscription, applying local snippets, running scripts, writing the runtime file, and telling the core to reload. The client controls the order; don’t assume UI settings are always applied last. If changes save but nothing seems different, inspect the final runtime config first, check whether reloading succeeded, and then see whether old connections are still using their previous state.

If you use Mihomo’s command-line program, run the test command below to check the config. Replace the filename in the command with your actual file, and make sure the working directory includes any provider files it needs. Passing the test mainly means the core can accept the config; it doesn’t guarantee node authentication, remote downloads, or access to your apps will work. In a legacy environment, check the relevant core’s help output for supported arguments instead of assuming the executable name.

mihomo -t -f config.yaml

Validate one layer at a time: first syntax and references, then listener availability, then DNS and providers, and finally real connections. If an error includes a line number, also check the indentation, quotes, and list boundaries above that line; the parser may report where it detected the problem, not where it was first introduced. Retest after each fix instead of applying several speculative changes to a config that’s in use.

Save a rollback point, then test real requests

Before making changes, export the working config and note the active overrides and proxy group selections. Keep a local copy you can restore; don’t rely only on a subscription URL that may change. If connectivity breaks after an edit, restore the last working state rather than continuing to add fields while offline. Backups may also contain private credentials, so store them securely and don’t upload them to public spaces.

To test a port, use a tool that supports proxy settings, and distinguish reaching the local listener from successfully accessing the destination. On Windows, run curl.exe explicitly to avoid a same-named alias in some terminals. The target is a reserved example website. If it isn’t reachable from your current network, use the error to identify the stage that failed; the command’s exit status alone can’t tell you whether every node is working.

curl.exe -I --proxy http://127.0.0.1:7890 https://example.com/

Then check the connection records for the destination, matched rule, and final outbound, and test workloads that should go direct separately from those that should use a proxy. To validate TUN, also try an app that doesn’t use the system proxy and confirm that its traffic is captured as expected. Don’t run multiple clients that compete for the system proxy, virtual adapter, or listening ports. If behavior is unstable, start by leaving only one clearly enabled traffic interception path.

A maintainable config should answer four questions: where does traffic enter, where are domains resolved, which rule makes the routing decision, and which outbound is ultimately used? Make each change at one of these layers, leave comments explaining its purpose, and remove temporary exceptions that are no longer needed. That way, after a subscription update, system change, or client migration, you can trace the same path to find the problem instead of piling up a longer config from scratch.

Download a Client