Configuration Structure and YAML Syntax
A Clash config describes how the core listens for requests, resolves domain names, and selects an outbound route. It is not a complete set of preferences for the client interface. Window position, menu bar icon, and launch-at-login settings are usually stored separately by the GUI client. Before reading a config, check which core is running and which file the client actually loaded. A file named config.yaml is not necessarily active; subscription, local, and runtime-generated configs may all exist at once.
Mappings, Lists, and Indentation
YAML mappings use key-value pairs, while list items begin with a hyphen. Top-level dns is a mapping; proxies, proxy-groups, and rules are usually lists. Indent child fields farther than their parent. Use two spaces consistently and avoid tabs. Fields at the same level should line up. If a parser points to an error on one line, the cause may be on the previous line—for example, an unclosed quote or a missing hyphen before a list item.
mixed-port: 7890
allow-lan: false
mode: rule
log-level: info
dns:
enable: true
nameserver:
- https://dns.alidns.com/dns-query
proxies: []
proxy-groups:
- name: "Outbound Selection"
type: select
proxies:
- DIRECT
rules:
- MATCH,Outbound Selection
This structural example contains only a direct outbound and no usable remote proxy nodes. It is useful for checking YAML nesting, proxy group references, and fallback rules, but it cannot replace the node configuration from your provider. Do not concatenate snippets from different sections into one file: merge fields with the same top-level name in a single place. In particular, do not add two separate dns or rules sections and assume the core will merge them automatically.
Strings, Booleans, and Special Characters
Quote values containing a colon followed by a space, a hash sign, or characters that could be interpreted as another data type. In plain text, a hash sign may start a comment, so the remainder will not be read as part of a password or name. Write booleans as true or false, and ports as integers. Node names, group names, and rule targets are strings; references must match them exactly. Names can contain non-Latin characters, but leading or trailing spaces may also become part of the string.
With double quotes, escape backslashes where needed; ordinary strings that need no escapes can use single quotes. If an editor autocorrects straight quotes to curly quotes, the file may still parse but produce an unexpected string. When a reference fails, compare the raw text instead of relying on names that merely look alike in the interface. Give every node and proxy group a unique name. Do not use built-in outbound names such as DIRECT or REJECT for custom objects.
Config Sources and Validation
A subscription URL does not always return a complete YAML file. Some URLs return encoded node lists, some require server-side conversion, and some return different formats depending on the request. If an import fails, check the config type in the client first, then review the parser logs. A saved login page, error page, or expiration notice is not a valid config, even if it has a YAML file extension. Subscription URLs may contain credentials; never post them in public forums or screenshots.
If you have installed mihomo as a standalone command-line tool, run the syntax check below in Terminal. A GUI client’s bundled core may not be on your shell’s search path, so a command-not-found error does not mean the config is broken. Test with a similar core and the same resource directory as the client. Configs that reference external rule files also require those files to exist. Passing the test confirms the config can load; it does not prove that remote nodes are reachable or that traffic is routed as expected.
mihomo -t -f ./config.yaml
Keep a copy of the original config that connects successfully. Change one related set of fields at a time and note the expected result. This makes it easier to distinguish syntax errors from client overrides, network failures, and unexpected rule matches. Adding a large collection of unrelated snippets from the web all at once can mask the causes of errors and leave you without a useful baseline for rollback.
Listening Ports and Access Scope
Port fields define where local apps send proxy requests to the core. They are not remote node ports or the controller API port. After a browser connects to a local mixed port, the core applies its rules to choose a remote node or direct route. A remote node’s server port is configured under that node. Confusing these two layers can lead you to point the system proxy at a remote server or mistakenly change a remote node address to a loopback address.
HTTP, SOCKS, and Mixed Ports
| Field | Requests Accepted | Typical Use |
|---|---|---|
port | HTTP proxy, including CONNECT requests | For system HTTP and HTTPS proxy settings |
socks-port | SOCKS proxy | The app must support the corresponding proxy protocol |
mixed-port | HTTP and SOCKS proxies | Both protocols share one listening port |
external-controller | Core management API | Not an entry point for web traffic |
For everyday desktop use, a single mixed port is often enough. The example uses 7890, but clients do not all use this value. The port shown in the interface, the runtime config, and the system proxy settings must match. If you enable separate listeners, assign a different port to each to avoid binding conflicts. Disabling unused listeners is easier to understand than enabling every port field, and makes it easier to tell which entry point an app is using.
mixed-port: 7890
allow-lan: false
bind-address: "127.0.0.1"
mode: rule
Loopback Addresses and LAN Sharing
127.0.0.1 is the current device’s IPv4 loopback address. If you enter it on a phone, the phone connects to itself—not to your Mac. To share the Mac’s proxy with devices on your local network, allow LAN connections, configure an appropriate listening address, and enter the Mac’s actual LAN address on the other devices. Once the listener is exposed, account for the firewall, network isolation, and access controls. Enabling a single switch is not enough to define safe access.
allow-lan controls whether LAN requests are accepted; bind-address restricts the listening address. Actual accessibility depends on the combination of these fields, core behavior, and the system firewall. For desktop use, keep access on loopback. For sharing, limit access to trusted networks, and never forward a local proxy port directly to the public internet from your router. Other devices on a public Wi-Fi network are not trustworthy just because they share a subnet.
macOS System Proxy Settings
On macOS, Web Proxy and Secure Web Proxy usually point to the local HTTP listener. The Secure Web Proxy label does not mean the local listener needs TLS enabled. HTTPS sites generally use an HTTP CONNECT tunnel. With a mixed port, Web Proxy, Secure Web Proxy, and SOCKS Proxy can use the same loopback address and port. With separate ports, configure each one to match its listener rather than copying the example values.
The command below shows the current settings for the network service named Wi-Fi. Your service may have a different name; list available services first to confirm. If the system has multiple network services, inspect the one actually carrying the connection. External adapters, wired connections, or renamed services can make the service you check differ from the active route. A correct address in the command output also does not prove the client is listening, so check the local process too.
networksetup -listallnetworkservices
networksetup -getwebproxy Wi-Fi
networksetup -getsecurewebproxy Wi-Fi
networksetup -getsocksfirewallproxy Wi-Fi
lsof -nP -iTCP:7890 -sTCP:LISTEN
If a port is in use, identify the listening process before taking action. Do not terminate an unfamiliar system process. Two proxy clients running at once may compete for a port or take turns changing the system proxy. After quitting one, check that no stale system settings remain. If you change the port, also update shell environment variables, editor proxy settings, and any apps configured manually. Otherwise, the browser may work while some apps keep using the old address.
Modes and Traffic Entry Points
The operating mode determines how the core selects an outbound route after a request reaches it. System proxy and TUN determine how the request reaches the core. These are separate questions. Rule mode does not automatically capture traffic from every app, and enabling TUN does not mean all traffic must go through a remote proxy. To explain what happened to a connection, first identify its entry point, then check the core’s current mode, and finally inspect the matching rule.
Rule, Global, and Direct Modes
mode: rule selects a policy by evaluating the rules in order; mode: global uses the global policy; mode: direct routes traffic directly. These are not connection quality ratings or network permission levels. Global mode can help isolate whether a problem is related to rules during a short test, but it is not a switch that fixes every issue. If the selected remote node is unreachable, switching to global mode usually will not help.
mode: rule
log-level: info
ipv6: false
GUI clients generally let you change the mode in the interface, but that change may be sent to the running core through its controller API without being written back to the original YAML. Whether the mode persists after a reload depends on the client’s save behavior. Check both the file and the live interface when troubleshooting; the mode value in an editor alone does not confirm the current state. Client logs, the connections view, and the generated config provide more direct evidence.
System Proxy and Shell Environment Variables
The system proxy mainly affects apps that honor system proxy settings. Many command-line tools have their own proxy handling and do not read macOS network settings by default. You can set environment variables temporarily in the current shell to compare behavior. A new Terminal window will not automatically inherit variables added later in another window. Tools vary in which variable names and capitalization they support. If something fails, check that tool’s documentation instead of repeatedly toggling the system proxy.
export http_proxy=http://127.0.0.1:7890
export https_proxy=http://127.0.0.1:7890
export all_proxy=socks5h://127.0.0.1:7890
curl -I https://example.com
unset http_proxy https_proxy all_proxy
Here, socks5h means tools that support this scheme pass the destination hostname to the proxy for resolution, rather than resolving it locally and sending an address. Environment variables affect only programs that read them; they do not change the operating system’s network routes. Some tools give command-line options or config files higher priority than environment variables. For a useful test, minimize duplicate settings so you can tell which layer is taking effect.
TUN Configuration and Permissions
TUN uses a virtual network interface to capture a broader range of IP traffic and usually requires the client to install a helper service or obtain the necessary permissions. The fields below are a common mihomo configuration, not a format every GUI client exposes directly. Some clients manage TUN fields, choose interfaces, or generate route exclusions themselves; use the settings supported by that client. For setup steps, see the TUN mode guide.
tun:
enable: true
stack: mixed
auto-route: true
auto-detect-interface: true
dns-hijack:
- any:53
auto-route asks the core to set up the relevant routes; auto-detect-interface detects the outbound interface automatically. The interface and routes may change when you switch Wi-Fi networks, connect a dock, or start another VPN. If the connection drops, check the interface and route state before blaming a node. Corporate VPNs, virtual machines, and other network extensions can also alter traffic paths. Enable them one at a time and observe the results.
DNS hijacking rules have limits. The configuration above handles standard DNS port traffic; it does not automatically capture every app’s built-in encrypted DNS. If only some domains fail with TUN enabled, check the DNS mode, app-level settings, and route exclusions together. Before quitting the client, let it undo its network changes cleanly. Force-quitting may leave the network temporarily unusable.
Troubleshoot in a consistent order: turn off other VPNs and test with the system proxy alone; once that works, enable TUN; then restore other network tools. Change one condition at a time and note differences between the browser, Terminal, and the affected app. Windows app loopback is a separate platform feature, not another name for macOS TUN. See Windows app loopback for details.
DNS Fields and Name Resolution
A DNS setup needs to answer three questions: Does the app’s query reach the core? Which resolver does the core use? How does the answer affect the connection that follows? Adding a public DNS address alone does not ensure every app uses it. With a system proxy, an app may query the system resolver first; HTTP CONNECT and SOCKS requests with remote DNS may preserve the hostname. TUN, app-level encrypted DNS, and local caches can all change the path you observe.
Resolvers and Bootstrap DNS
dns.enable enables the core’s DNS module, and nameserver lists regular upstream resolvers. If an encrypted DNS server is specified by hostname, that hostname must be resolved to an IP address first. default-nameserver can handle this bootstrap lookup and is suited to explicit IP addresses. Avoid making every resolver depend on other hostnames that in turn rely on a proxy connection that is not yet available.
dns:
enable: true
ipv6: false
enhanced-mode: fake-ip
fake-ip-range: 198.18.0.1/16
default-nameserver:
- 223.5.5.5
nameserver:
- https://dns.alidns.com/dns-query
proxy-server-nameserver:
- https://dns.alidns.com/dns-query
fake-ip-filter:
- "*.lan"
- "*.local"
This example shows how the fields fit together; it does not mean any public resolver is right for every network. When choosing an upstream, consider whether it is reachable directly from your current network, whether internal domains need a dedicated resolver, and what DNS the remote node’s network requires. proxy-server-nameserver resolves proxy server hostnames separately from regular website lookups, helping reduce the risk of a dependency loop during startup.
fake-ip and Real-IP Modes
In fake-ip mode, matching domain names resolve to synthetic addresses. The core uses its mapping to recover the original hostname before connecting and applying rules. The example range is reserved for benchmarking; it is not an address for a remote proxy server. Seeing an address in this range does not necessarily mean DNS is broken. But if an app bypasses the core after receiving a synthetic address, the connection may fail, so the DNS and traffic entry points need to align.
A mode that returns real addresses behaves more like traditional DNS, but the link between a hostname and a connection can be affected by app caches, shared IPs, or connection methods. Neither mode is simply better in every case. LAN discovery, games, device management, and apps that explicitly validate addresses may need fake-ip exclusions. Before adding a filter, confirm the issue is address compatibility—not an unreachable node or destination service.
Choose Resolvers by Domain
Use nameserver-policy to assign a resolver to specific domains, for example, routing internal company domains to an internal DNS server. The example uses a sample domain and private IP; replace both with the values supplied by your organization. If the internal DNS server is reachable only through a corporate VPN, make sure the route allows queries to reach it. Sending internal domains to a public resolver usually returns no useful answer and may expose queries unnecessarily.
dns:
nameserver-policy:
"+.corp.example.com":
- 192.168.10.1
Merge this into the existing dns mapping; do not append it as a second top-level field with the same name. Before adding advanced DNS routing options that select an outbound based on rules, establish a working basic resolution path. Some DNS routing options also make queries subject to rule matching. If those rules themselves require DNS, follow the core documentation to resolve the dependency instead of adding more resolvers.
How to Investigate DNS Issues
First check whether the client logs show the query, then inspect the response address and the outbound used for the connection. A standard dig test usually cannot confirm an app’s built-in encrypted DNS behavior. A webpage opening in the browser also does not prove Terminal used the same resolution path. After changing the config, the browser, system, and core may each retain cached data. Close existing connections and make a fresh request; clear caches using the client’s supported method if needed.
IPv6 needs to be considered in layers: the top-level switch, whether DNS returns IPv6 addresses, and whether the operating system has a usable IPv6 route are separate conditions. Disabling one field does not explain every IPv6 issue. For slow connections or delays on the first request, compare DNS lookup time, connection setup time, and the selected outbound. Continue with a layered macOS speed troubleshooting guide rather than attributing every delay to DNS.
Proxy Node Fields and Remote Providers
A proxy node describes a specific way to connect remotely. Its key fields are the protocol, server address, server port, and authentication details. Proxy groups select nodes; rules select groups. These serve different purposes and cannot replace one another. Use the node fields supplied by your provider rather than guessing the protocol from a node’s name. A protocol name in a label is just a label; the core uses the type field to determine the actual protocol.
Common and Protocol-Specific Fields
name is the identifier used by proxy groups, server is the server hostname or IP address, and port is the remote service’s listening port. Authentication varies by protocol: some use a password, some a user ID, and others also require TLS and transport settings. Similar field names do not mean fields are interchangeable across protocols. The Shadowsocks example below illustrates the structure only; its hostname and password are instructional values and cannot establish a remote connection.
proxies:
- name: "Example Outbound"
type: ss
server: proxy.example.com
port: 443
cipher: aes-128-gcm
password: "your-password"
udp: true
The cipher, password, and server port must match the server configuration. Using a familiar web port does not make a node an HTTPS service or let a regular browser connect to it directly. udp: true means the config allows the capability; actual support also depends on the protocol implementation, server, upstream network, and app’s request path. If UDP fails, check the full chain instead of repeatedly toggling this field.
TLS, Server Names, and Transport Settings
For protocols that use TLS, the connection address and the name used for certificate validation may differ. server determines where to connect. In some protocols, fields such as servername specify and validate the server name; the exact field depends on the protocol’s config format. WebSocket paths, request headers, and gRPC service names must also match the server. If these parameters are missing, the TCP port may be reachable while the higher-level handshake still fails.
For certificate errors, check the system clock, server name, certificate chain, and server configuration first. Skipping certificate verification changes the security boundary and is not a general troubleshooting fix. Do not add fingerprints, transport optimizations, or connection reuse fields without understanding what they do. A field supported by another protocol may not work with this one. A parser accepting an unknown or irrelevant field does not mean it has the intended effect.
Remote Node Providers and Health Checks
proxy-providers separates node sources from the main config, making it useful for regularly updated node collections. Provider files must follow the node-provider format. A subscription containing full rules and DNS settings is not automatically a valid input of the same type. The example shows the remote source format and uses a sample URL. For production, use a trusted source and treat access credentials as private. Do not commit them to a public repository.
proxy-providers:
remote-pool:
type: http
url: "https://example.com/proxies.yaml"
path: ./providers/remote-pool.yaml
interval: 86400
health-check:
enable: true
url: https://www.gstatic.com/generate_204
interval: 600
interval sets the update interval; the health-check interval controls availability tests. They do different jobs. Paths are resolved relative to the core’s working directory, which a GUI client may replace with a dedicated data directory. If an update fails, distinguish a bad remote response, invalid format, and a local directory that cannot be written. Logs can also show whether a cached copy is still usable. Do not delete the cache without a backup if it contains the only working set of nodes.
Stable Node Names and References
Subscription updates may rename nodes. If a manually maintained group refers to each old name, those references can break after an update. Using a provider’s use collection is usually easier to maintain than copying many node names, though filters may need updating to match the naming scheme. Avoid duplicate names when combining sources. Duplicate names do more than clutter the interface: they can make selections, logs, and override targeting ambiguous.
A node appearing in the list does not mean it has passed an availability check. Troubleshoot layer by layer: DNS resolution, server connection, protocol handshake, then destination access. If one node fails, compare it with another in the same group. If all nodes fail, check the local network, entry point, system clock, and config source. A speed test also does not represent performance across every site, protocol, or time of day.
To choose a client, start with Clash Plus in the macOS download section, then compare Clash Verge Rev and FlClash based on the features you need. Similar interfaces do not guarantee that their cores support the same fields. To understand how GUI clients and cores divide responsibilities, read the Clash open-source ecosystem and its relationship to mihomo, then decide which layer should own the config.
Proxy Group Fields and Health Checks
A proxy group gives a set of nodes a single outbound name that rules can reference. Rules usually point to a group rather than a node that may change often, so swapping nodes does not require rewriting every rule. Groups can also reference other groups to combine manual and automatic selection. Keep references free of cycles, use unique group names, and make sure every referenced object exists in the final runtime config. A node present in the original subscription but removed by an override can still cause a broken reference.
Manual Selection and Nested Groups
proxy-groups:
- name: "Outbound Selection"
type: select
proxies:
- Automatic Selection
- DIRECT
- name: "Automatic Selection"
type: url-test
use:
- remote-pool
url: https://www.gstatic.com/generate_204
interval: 300
tolerance: 50
The remote-pool in this example refers to the provider defined in the previous section. proxies lists specific node or group names; use imports a provider collection. With select, the active outbound depends on the user’s current selection. It will not switch automatically just because a listed node has a connection problem, unless the selected item is itself a subgroup with automatic selection. List order does not indicate the current selection.
Nesting can separate regions, purposes, and selection methods, but too many layers make the config harder to read. Even when the connections view shows a rule target, follow the group’s current selection to find the final node. For troubleshooting, start with a simple selection group that directly references a known node and verify that the node works. Then restore automatic groups and more complex nesting. This separates policy issues from remote connection problems.
Automatic Selection, Failover, and Load Balancing
| Type | How It Works | Best For |
|---|---|---|
select | Keeps manual selection | When you need direct control over the outbound |
url-test | Selects nodes based on test results | Automatically picks from available candidates |
fallback | Tries available nodes in candidate order | Prefers a fixed outbound and fails over if it becomes unavailable |
load-balance | Distributes connections according to the selected policy | Distributing requests across multiple outbounds |
url-test measures performance against the specified test URL. It does not measure download bandwidth or provide an overall score for every destination. tolerance reduces frequent switching caused by small differences; its unit is milliseconds, not a guaranteed latency. When candidate nodes perform similarly, tolerating small variations can keep the outbound more stable than always chasing the lowest measurement.
fallback uses candidate order to express preference: it uses the first node while that node is available, rather than always choosing the lowest test result. load-balance distributes connections according to its configured strategy; it does not split one connection across multiple routes to combine their bandwidth. Apps that rely on login state, regional detection, or session consistency may be affected by using multiple outbounds. Do not enable load balancing just because the group name sounds useful.
Test URLs, Intervals, and Lazy Checks
Choose a test URL that is stable, lightweight, and representative of the connectivity you want to measure. A node that cannot reach the test site but can reach your actual destination may be marked unsuitable under that test. Conversely, passing the test does not mean every service is available. Understand these limits when choosing a URL; it is not a health check for the entire internet. If a result seems wrong, compare a real request to the destination with the logs.
Shortening interval increases the test frequency and uses more requests and device resources; it does not directly improve node bandwidth. Provider health checks and group tests can also duplicate probes. Some groups support lazy checking and run fewer tests while unused, so their status may take a moment to refresh after you switch to them. Set intervals based on how you use the client instead of reducing every value to the minimum.
Filters and Selection State
When filtering provider nodes with filter or an exclusion expression, first confirm that the names actually contain the text you expect. Parentheses, pipes, and other special characters have meaning in regular expressions; plain descriptions are not always reliable filters. A subscription rename can leave a group empty. After changing a filter, inspect the expanded node list instead of assuming the group still works because its title remains. An empty candidate list is a useful clue when automatic selection fails.
If the client or config saves selection state, reloading may restore the previous manual selection. A renamed node may prevent that selection from being restored. When testing YAML list order, check what is actually selected rather than assuming the first item is always active. For details and use cases of the three automatic strategies, see url-test, fallback, and load-balance compared before changing your groups.
Rule Syntax and Matching Order
The rules list is an ordered decision process. The core checks rules from top to bottom and uses the corresponding outbound when one matches, so changing the order can change the result. Put specific exceptions first, broader matches after them, and a catch-all rule last. Do not put MATCH at the top and expect later domain rules to apply; the catch-all has already accepted every request not otherwise constrained.
Domain, Suffix, and Keyword Rules
rules:
- DOMAIN,api.example.com,DIRECT
- DOMAIN-SUFFIX,example.org,Outbound Selection
- DOMAIN-KEYWORD,example,Outbound Selection
- IP-CIDR,192.168.0.0/16,DIRECT,no-resolve
- IP-CIDR6,fc00::/7,DIRECT,no-resolve
- MATCH,Outbound Selection
DOMAIN matches an exact domain, making it useful for a single-host exception. DOMAIN-SUFFIX matches the domain and its subdomains. DOMAIN-KEYWORD matches by substring, so it has a wider scope and is more likely to catch unrelated services. Do not include https://, a path, or query parameters in a rule domain; these rules do not match full web URLs. Prefer a narrowly scoped rule when targeting a specific host.
Each rule’s target must be an existing node, proxy group, or built-in outbound. A comma in Chinese punctuation cannot replace an ASCII comma, and extra spaces in names make references harder to verify. If a target is missing, check not only the rule but also whether an earlier node merge or group override changed its name. For frequently updated node collections, pointing to a stable group name is usually easier to maintain than targeting a single node directly.
IP Rules and DNS Side Effects
IP-CIDR and IP-CIDR6 match address ranges. If a request contains only a hostname, some IP rules may need to resolve it first. Adding no-resolve prevents that rule from initiating a DNS lookup just to match, but it does not mean all IP requests are ignored: if the connection already has a destination IP, the rule can still match it. This option controls DNS resolution, not whether traffic goes direct or through a proxy.
Rules for private address ranges can help protect LAN access, but a real network may also include other ranges and special routes. Do not route an entire public IP range directly just because one lookup returned an address in it. Large services can share IPs, and DNS answers can change across networks. Strategies based on explicit domains are usually more stable than following a one-time IP result. If IP-based routing is necessary, understand the range and how it is maintained.
Remote Rule Sets and Their Declarations
rule-providers:
local-services:
type: file
behavior: domain
format: yaml
path: ./rules/local-services.yaml
rules:
- RULE-SET,local-services,DIRECT
- MATCH,Outbound Selection
The corresponding rule file uses the structure below. Here, behavior: domain means the payload contains domain-matching entries, not complete rule statements. With classical, the payload format and supported rule types differ. The provider declaration, file format, and actual contents must all agree. Matching file extensions do not prove the internal structure is the same, and a webpage returned after a failed download is not a valid rule set.
payload:
- "+.example.org"
- "router.example.com"
A rule set stores match data; the RULE-SET rule in the main config determines which outbound to use. Successfully loading a rule set does not mean every domain in it will take the expected route: an earlier rule may already match. After updating a set, check the actual rule type and target shown in the connections view. Do not move an entire remote rule set to the top just to fix one domain, or you may change LAN and business exceptions that need to take priority.
Connection Reuse and Testing
Rule changes usually affect new connections. Existing long-lived connections, browser connection pools, and app sessions may keep using their previous routes. For a reliable test, close the relevant connection, request a specific destination, and inspect the matched rule, group, and final node. A webpage may contact many domains for its main document, images, login, and API requests; each may take a different route. Whether the page opens cannot confirm that every request followed the intended policy.
Domain information is not automatically visible at every entry point. An app that connects directly to an IP, uses its own resolver, or reuses an existing connection may expose different information to the rule engine. Sniffing can reveal a domain in supported cases, but it is not full-URL detection and cannot recover every encrypted connection. Base troubleshooting on the metadata shown in connection records. Do not assume the core can see everything in the browser’s address bar.
Config Overrides, Merging, and Validation
Overrides let you keep local ports, DNS, rules, or proxy selections while continuing to receive subscription updates. The key question is not whether you have an extra YAML file, but how the client combines its inputs into the final config. The original subscription, local overrides, client preferences, and runtime API changes may all belong to different layers. There is no universal answer across clients as to which one wins for a given field. Check the current client’s merge documentation and generated output.
Scalars, Mappings, and Lists
Scalar fields are often replaced by the newer value, such as changing the mixed port from one number to another. Mappings may be deep-merged or replaced wholesale; lists may be replaced, prepended, appended, or handled by a dedicated script. Do not assume merge behavior is the same across clients. Rule lists are especially important: replacement can discard the original rules, while appending may place custom rules after MATCH, where they can no longer match.
| Field Shape | Common Handling | What to Check |
|---|---|---|
Scalar, such as mixed-port | Replaced with the new value | Does the interface rewrite it afterward? |
Mapping, such as dns | Deep-merged or replaced entirely | Are the original child fields preserved? |
List, such as rules | Replaced, prepended, or appended | Catch-all and custom rule order |
Object list, such as proxy-groups | Handled according to the tool’s rules | Are objects matched by name? Are there duplicates? |
Keep Subscription Data Separate from Local Changes
Node credentials and remote node collections should generally follow trusted subscription updates. Listening ports, LAN permissions, and local DNS exceptions are better kept on the device. Do not edit a temporary downloaded cache file and expect the change to survive the next update. Nor should you sync a device’s network interface name, absolute paths, or local listening address to every device. Operating systems and clients differ in data directories, permissions, and supported fields.
# Local field snippet; follow the client documentation for merge behavior
mixed-port: 7890
allow-lan: false
log-level: info
profile:
store-selected: true
This example shows local fields you may want to keep; it does not define how rules are merged. profile.store-selected saves proxy group selections. It is separate from the client’s setting for saving subscription files. If the client has a corresponding setting, check whether the interface-generated value or the override takes precedence. Maintaining the same field in multiple places can leave the editor and interface showing different values, making future troubleshooting harder.
Review the Final Config and Make Minimal Changes
Before editing, export or back up the working config and note the client, core type, and key settings. After editing, inspect the final runtime config: confirm the target fields are present, check whether another layer overrides them, and verify that referenced group names still exist. It is normal for the runtime config to change while the original subscription stays the same. If the original file changes but the runtime config does not, you may have edited the wrong config or not triggered regeneration.
Validate in four stages: check YAML syntax and core loading, confirm the local port is listening, test a specific proxy request, then inspect the matched rule and final outbound. Each stage provides different evidence. Valid syntax does not prove a node is reachable; a reachable node does not prove the system proxy is set; a working browser does not prove Terminal uses the proxy. Close the loop at each layer to avoid changing fields in the wrong part of the config.
mihomo -t -f ./config.yaml
lsof -nP -iTCP:7890 -sTCP:LISTEN
curl --proxy http://127.0.0.1:7890 -I https://example.com
Compare command-line tests with the client’s actual environment. A standalone core may use different working directories, rule caches, or permissions, so a successful standalone test does not rule out a problem with the client-generated config. After reloading, look for parse errors, missing objects, and listener failures in the logs. Fix the earliest clear error first. A long list of later connection failures may simply result from one earlier loading error, not a series of separate network issues.
Rollback, Sharing, and Common Questions
If a change breaks connectivity, restore the last working config, disable the new override, and reintroduce changes one at a time. Keep the original subscription and do not overwrite your only copy with a temporary test file. When syncing across devices, share only settings that are genuinely common. Keep local paths, network interfaces, and device-specific rules on each device; store subscription URLs and node passwords securely. For details, see how to sync Clash configs across devices.
Why does the client still use the old port after I edit the YAML?
Why did my custom rules disappear after a subscription update?
Can I use the same config in every Clash client?
Aim for a config where every field has a clear source, every rule has an explainable order, and every change has a rollback baseline. When something goes wrong, narrow the scope before adding complexity. Use the download page to reinstall or compare clients. To follow the import, mode selection, and connection checks in order, return to the quick-start guide rather than treating this reference as a checklist of fields that must all be enabled.