MIHOMO / CONFIGURATION REFERENCE

Clash Configuration Reference

Look up config.yaml by field and dependency. Covers inbound listeners, proxy exits, policy selection, rule matching, DNS resolution, and client overrides.

For your first install or subscription import, start with the guide. This page explains the config structure, how to edit individual settings, and how to check the final runtime config. Examples use mihomo fields; actual support depends on the core bundled with your client.

YAML Structure and Config Dependencies

Read the top-level map to understand the config

A Clash config is not a script that runs line by line; it is a map describing the desired runtime state. Top-level mixed-port, mode, and log-level are scalars; dns is a nested map; and proxies, proxy-groups, and rules are lists. Indentation defines parent-child relationships, so field placement matters just as much as field values. For example, indenting rules under dns does not create special DNS routing rules. It changes the structure and may cause an error or be ignored.

When reading a full config, trace four dependencies: listeners pass connections to the core; rules route connections to a target; proxy groups map target names to proxies or other groups; and DNS resolves domain names. Providers supply proxy or rule data, but do not automatically become an egress route. A provider's resources are used only when a proxy group references a proxy provider or a rule references a rule provider. Once you understand these relationships, troubleshooting is less about guessing line by line.

# Minimal direct-connection config to verify the file structure and listener
mixed-port: 7890
allow-lan: false
mode: rule
log-level: info

proxies: []

proxy-groups:
  - name: Select Exit
    type: select
    proxies:
      - DIRECT

rules:
  - MATCH,Select Exit

This minimal config uses only the built-in DIRECT target; it does not provide a remote proxy service. Use it to confirm that the core can read the file, start the listener, and switch to rule mode in the client. To add a proxy egress, define a real proxy and add its name to a proxy group. A structure example is not a working subscription: passing a syntax check only confirms the structure and some references, not that a remote server exists or your account can access it.

Common pitfalls with indentation, quotes, and lists

Use two spaces for indentation and never mix spaces with tabs. Short lists can use [DIRECT, Select Exit]; for longer object lists, put each item on its own line to make the hierarchy easier to read. Quote strings that contain a colon followed by a space, a hash, or text that looks like a boolean. Passwords, subscription URLs, and numeric-only names should also be quoted to prevent the parser from interpreting them as another type. Comments only work outside strings; never use them to store account details.

Do not define the same key more than once in a map. For example, adding one dns block at the beginning and another at the end is not a reliable way to merge settings. Parsers may reject duplicate keys or keep only one block. To add DNS fields, edit the same map. List items are not merged automatically by name, either: two proxy groups with the same name usually conflict rather than combine their candidates. As configs grow, keep each definition in one place and reference it elsewhere.

Separate source configs, resource files, and runtime configs

Clients often manage the original subscription, provider cache, override snippets, and runtime config passed to the core. The file shown in the interface may not be the final one, and edits to a cache may be overwritten at the next update. Before making changes, note the selected config name, export a structural backup with personal credentials removed, and confirm whether you are editing the original subscription or a persistent override. To install a client, start with Clash Plus, then check where to edit configs and view runtime logs on your platform.

Splitting files can make them easier to maintain, but YAML does not support arbitrary file imports by default. Do not add an include field and expect the core to load a directory. Use supported provider mechanisms to split proxies and rules; reuse of general settings depends on an explicit merge feature in the client. Relative paths are usually resolved from the working directory, not necessarily from the file being edited. When moving to another device, check resource paths, write permissions, and client-generated directories as well as the main config.

Listener Ports, Mode, and the Controller API

Inbound protocols and listen addresses

port provides an HTTP proxy listener, socks-port provides a SOCKS listener, and mixed-port accepts both HTTP and SOCKS on the same port. A single mixed port is usually enough; there is no need to enable every listener. An app must explicitly use the proxy address for its connections to reach these ports. Starting a listener alone does not capture system traffic. The client's system proxy toggle integrates with the operating system; TUN is a separate way to route traffic. Neither can be inferred just from whether a port is open.

FieldPurposeWhat to check
portHTTP proxy listenerWhether the app uses the HTTP proxy address
socks-portSOCKS proxy listenerUDP forwarding also depends on listener and app support
mixed-portShared HTTP and SOCKS listenerWhether another process is using the port
allow-lanAllow devices on the local network to connectCheck alongside the listen address and firewall
external-controllerExpose the controller APIProtect it separately from proxy listeners

allow-lan: false is suitable for local-only use. If you enable LAN access, also check whether bind-address, the OS firewall, and network isolation policies allow other devices to connect. A service bound to a loopback address cannot be reached from another device; binding to all addresses does not mean the firewall allows access. To troubleshoot one app, do not expose more of the device than necessary. First verify the listener locally, then open access gradually if needed.

mixed-port: 7890
allow-lan: false
bind-address: "127.0.0.1"
mode: rule
log-level: info
ipv6: false

# Bind the controller API to localhost; set credentials separately on your device
external-controller: "127.0.0.1:9090"

Runtime mode and log verbosity

mode: rule selects a target based on the rules list; global sends connections through the global policy; direct uses the direct route. If the client is in global mode, rules will not route traffic as expected, even if the rules file is correct. Some clients restore the last-used mode through the API, so the setting on disk may differ from the current UI state. If routing looks wrong, check the runtime mode first, then rule order. Do not immediately change every rule to use a proxy.

log-level controls log verbosity. Keep info for everyday use, and switch to debug temporarily when tracing parsing, connections, or resource loading. Detailed logs may include domains, destination addresses, and request context. Remove subscription URLs, account fields, and other personal data before sharing them. Restore the previous level after troubleshooting to avoid recording unnecessary activity. A connection in the logs only shows that traffic reached a processing stage; it does not prove the request completed successfully.

Controller API and runtime environment

The controller API can switch policies, inspect connections, and change runtime state, so its privileges differ from those of a regular proxy listener. Keep it bound to loopback for local client access. If remote management is essential, use separate credentials, restrict source addresses, and keep access within a trusted network boundary. Never put API credentials in a public repository or share screenshots showing the full controller URL. If the UI cannot connect, first check that its controller address matches the configured one, then check for port conflicts and whether the core is still running.

Port numbers have no special meaning on their own, so you can change the example values—but the app, system proxy, and client must all use the same settings. When multiple proxy tools run at once, common problems include port conflicts, competing system proxy settings, and virtual routing conflicts. Troubleshoot with one traffic-capture mechanism enabled at a time, confirm the connection path, then re-enable other tools. On Linux, also check the service user, working directory, and file permissions. A config that works in a desktop client may not have access to the same resources when run as a system service.

ipv6 is not simply a network speed toggle. Decide whether to enable it based on your local network, proxy egress, and DNS results. Disabling IPv6 in the core does not replace the OS firewall or explain every direct IPv6 connection. If an app bypasses the proxy listener, fix traffic capture first, then consider address-family settings. For common issues with system proxy settings, port conflicts, or LAN connections, see Troubleshooting.

Proxy Fields and Protocol Boundaries

The minimum fields for a proxy entry

Each object under proxies describes one egress. Every proxy needs a referenceable name; type determines the protocol; and server and port point to the server's listening address. Authentication, encryption, transport, and TLS settings depend on the protocol, so do not copy them blindly between protocols. The name is not a connection parameter, but it is the identifier used by proxy groups. When you rename a proxy, update every direct reference, especially in manually maintained groups and rule targets.

The example below uses Shadowsocks. The server uses a reserved example domain, and the password is a dummy value for illustration. Replace them with the corresponding details from your provider before connecting. Do not infer the password, encryption method, or transport from the port or protocol name alone. If a subscription already contains a complete proxy entry, preserve its upstream fields; make individual changes only when you know what they do. Removing a transport setting by mistake can turn a working subscription into a syntactically valid config that fails to establish a handshake.

proxies:
  - name: Example Proxy
    type: ss
    server: proxy.example.com
    port: 443
    cipher: chacha20-ietf-poly1305
    password: "your-password"
    udp: true

proxy-groups:
  - name: Select Exit
    type: select
    proxies:
      - Example Proxy
      - DIRECT

Transport and TLS fields are not interchangeable building blocks

Even protocols that use TLS may use different field names. Some proxies use servername to set the handshake name; others use sni. Check the core documentation for the protocol to confirm whether it needs a tls flag or supports a particular transport option. The server address can be a domain or an IP, but the certificate usually matches a domain. If you replace the domain with an IP without preserving the correct handshake name, the connection may fail due to a certificate name mismatch—not because the server is offline.

Transports such as WebSocket, HTTP/2, and gRPC may also require a path, host header, or service name. These are part of the server-side setup, not optional details to trim. Troubleshoot in order: protocol, address, port, authentication, transport, then certificate and network reachability. Disabling certificate verification is not a routine fix: it weakens server identity checks and cannot fix an incorrect password, wrong path, or a protocol the server does not support.

Field categoryTypical valuesGuidance
Reference namenameKeep it unique and update group references
Server addressserver、portUse the address provided by the server operator
Protocol authenticationPassword, user ID, encryption methodFollow the protocol requirements and use the correct value types
Handshake and transportTLS name, path, transport protocolClient and server settings must match

UDP, DNS, and proxy updates

udp: true allows UDP forwarding when the protocol supports it; it cannot add UDP support to a server that lacks it. The app must also reach the core through a UDP-capable listener, and the egress path must allow that traffic. If websites work but games or voice calls do not, check the inbound path, the proxy group selection, and remote server capabilities separately. Do not rely on HTTP tests alone. Conversely, if a proxy test passes but a particular site fails, the rule may be selecting the wrong egress rather than the proxy being unreachable.

When server is a domain, it must be resolved before the proxy can connect. This is a different stage from resolving a website's domain through the proxy. If the DNS request needed to resolve the proxy itself depends on a proxy that has not been established, startup can get stuck in a dependency loop. A dedicated resolver for proxy server domains can make the initial connection path clearer; see the DNS section below for the relevant fields. First confirm that the proxy server address resolves correctly, then investigate how destination websites are resolved.

Subscription updates can change proxy names and counts. If a manually configured group lists proxies one by one, upstream deletions or renames can leave broken references. For dynamic subscriptions, use a provider's use field to include the proxy set. If you need to inspect subscription content, export a single redacted proxy entry for comparison; never share the full subscription URL. A proxy list, full YAML config, and URI links are different input formats. See Subscription Formats and Conversion to avoid pasting encoded text directly into proxies.

Proxy Groups and Egress Selection

Stable group names, flexible proxy sets

Proxy groups decouple rules from individual proxies. Rules can keep pointing to Select Exit while you change proxies within the group, without editing every rule. Group names, proxy names, and built-in targets all belong to the reference namespace, so avoid duplicate names and names that could be confused with DIRECT or REJECT. In a group, proxies lists explicit targets, while use references proxy providers. These are different things; a provider name is not a proxy name.

With select, the user chooses an egress; url-test selects a candidate based on probe results; fallback checks candidates in order for one that is available; and load-balance distributes connections according to its strategy. Automatic selection does not compare every route for every request and pick the best one. A probe URL only reflects reachability to one destination at a particular time. Differences in destination, protocol, or server restrictions can make real-world performance differ from probe results.

# Use with the “Example Proxy” entry from the previous section
proxy-groups:
  - name: Select Exit
    type: select
    proxies:
      - Auto Select
      - Example Proxy
      - DIRECT

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

rules:
  - MATCH,Select Exit

Probe intervals, tolerance, and failover

interval sets the probe interval in seconds; tolerance sets the switching threshold in milliseconds for supported auto-select groups. A tolerance can reduce unnecessary switching due to minor fluctuations, but it cannot fix congestion on the remote end. Short intervals increase requests and wake-ups, which matters especially on mobile devices. Choose a probe URL that returns a predictable response reliably and does not require login. If the probe target is unreachable, every candidate may be incorrectly marked unavailable.

Candidate order in a failover group matters. The first target is preferred when it meets the availability criteria; it is not guaranteed to be the fastest. Load balancing usually distributes connections rather than splitting one download across several proxies to combine bandwidth. Use cross-egress distribution carefully for services that require persistent sessions or a stable source address. Check whether the service allows the address to change. Existing TCP connections usually do not move to a new egress when you change the rule target, so establish a new connection to test.

Group typeHow it selectsBest for
selectUser selects from candidatesFixed egress, manual troubleshooting, and a main entry point
url-testSelects based on periodic probesAutomatic comparison of candidate egresses
fallbackPicks the first available candidatePrimary/backup egress and failover
load-balanceDistributes connections according to a strategyWorkloads with explicit connection-distribution needs

Nested references and selection state

Proxy groups can reference other groups, but the resulting route must eventually reach an egress. If Group A references Group B and Group B references Group A, the dependency is circular. The client may allow you to save it, but the runtime may reject the config or fail to select a valid egress. Trace from the final rule target down to a proxy or built-in target, and make sure every branch terminates. Avoid excessive nesting: the first choice shown in the UI often does not explain the final route.

Clients may save manual selections and restore them after a restart or update, so the first item in a list is not necessarily the active egress. Persistence features such as profile.store-selected can affect restoration; some clients also store selections in their own state files. To check whether a group is working, inspect both its current selection and the full route in connection details—not just the YAML order. After renaming a group, verify the selection again because the old choice may no longer be valid.

An auto-select group cannot produce an egress from an empty proxy set. After adding a filter expression, check that candidates remain, especially if an upstream provider has changed its naming conventions. Whether to include a direct option in a manual group depends on the workload. For a service that must use a fixed proxy egress, do not treat DIRECT as an unverified fallback. Test rules, inspect policy selection, and verify the service separately to distinguish an empty candidate set, failed probes, restored selection state, and remote access restrictions.

Rule Syntax and Matching Order

The first matching rule determines the target

rules is an ordered list. The core checks rules from top to bottom and uses the target of the first match; it does not keep searching for a more specific rule. Put specific domains and exceptions before broader conditions, and leave MATCH as the catch-all at the end. Rules are not automatically sorted by longest prefix, and domain rules do not inherently take priority over address rules. The actual priority is the order in the file. A broad rule near the top can make every rule below it unreachable.

Most rules follow the pattern “type, match value, target.” DOMAIN matches an exact domain; DOMAIN-SUFFIX matches a domain and its subdomains; and DOMAIN-KEYWORD checks for a keyword in the domain. IP-CIDR and IP-CIDR6 match destination address ranges. GEOIP and GEOSITE depend on the relevant geolocation or site data. PROCESS-NAME requires process detection; do not assume it is available on every platform or through every inbound path.

rules:
  - DOMAIN,login.example.com,Select Exit
  - DOMAIN-SUFFIX,example.com,DIRECT
  - DOMAIN-KEYWORD,example,Select Exit
  - IP-CIDR,127.0.0.0/8,DIRECT,no-resolve
  - IP-CIDR,10.0.0.0/8,DIRECT,no-resolve
  - IP-CIDR,172.16.0.0/12,DIRECT,no-resolve
  - IP-CIDR,192.168.0.0/16,DIRECT,no-resolve
  - IP-CIDR6,::1/128,DIRECT,no-resolve
  - MATCH,Select Exit

The login domain above matches the proxy rule first; other domains with that suffix go direct. The keyword rule only handles cases not covered by the first two rules. The example domains demonstrate rule order, not recommended routing for any real service. The network-range rule uses no-resolve, which means it will not trigger a DNS lookup just for that address rule. If the connection already has a destination IP, it can still match. This is not a switch that disables all DNS requests, nor does it prevent later rules that rely on DNS.

Domains, IP addresses, and processes are not always available at the same time

Different inbound paths provide different information. An HTTP proxy request usually includes the destination hostname; some apps pass only the resolved IP, leaving the core without the original domain. TUN, fake-IP mappings, and sniffing can add context, but each has limitations. If a domain rule does not match, first check what information the core actually received in connection details. Then decide whether to adjust DNS or sniffing. Adding more domain rules will not help if the domain never enters the matching process.

Rule typeInformation requiredCommon misconception
DOMAIN-SUFFIXDomain contextCannot match a full URL path directly
IP-CIDRDestination IPAssuming IP rules take priority over domain rules
GEOSITESite database and domainMissing database category or outdated data
PROCESS-NAMELocal process informationMatching processes on other devices from a gateway
MATCHNo additional conditionsA rule placed first can shadow everything below it

Geodata rules and reject targets

For geodata rules, check the actual data format and file path being loaded. GEOSITE categories come from the database; they are not arbitrary labels. GEOIP results also depend on data updates and changes in address allocation. Do not equate an IP's registered location with the service owner's location or assume it determines where content is served from. Database load failures, missing categories, and rule-order issues are different problems. See How to Update GeoIP and GeoSite Databases for troubleshooting steps.

REJECT blocks connections and is useful for ranges you explicitly want to deny. Pointing a broad keyword rule at a reject target can also block login, CAPTCHA, or static asset requests. Start with a narrow match and inspect the results. A rule target can be a proxy or proxy group, but it must exist. Typos, trailing spaces, and renamed groups can all break references, so check more than just the rule's match expression.

To verify a change, pick a specific destination and record the mode, request domain, matched rule, and final egress. Change one thing, then establish a new connection. Browser connection pools, HTTP/2 reuse, and app keep-alive connections may continue using an old connection, so reloading a page may not trigger a new rule check. If needed, close the relevant connection before testing, but do not routinely automate closing all connections. Rules only process traffic that reaches the core. If the request is absent from the connection list, investigate the inbound path and traffic capture first.

DNS, fake-IP, and TUN Traffic Capture

Resolver roles and startup dependencies

dns.enable enables the core DNS module, and listen sets its listen address. nameserver lists regular resolvers; default-nameserver resolves domain names used by DNS servers themselves; and proxy-server-nameserver resolves proxy server domains. Each handles a different stage, so do not replace them all just because one address responds faster. In particular, encrypted DNS configured with a hostname needs a working bootstrap resolution path; otherwise, startup can hit a dependency loop.

enhanced-mode: fake-ip assigns a mapped address to a domain so the core can restore the domain context when the connection arrives. It is not the remote server's real address and does not mean a website is hosted in that address range. If an app bypasses the core and connects to the mapped address, the connection will usually fail. DNS responses and traffic capture must work together. For LAN discovery, device-specific protocols, or apps that inspect real addresses, configure fake-ip-filter as needed. Do not exclude every domain and still expect the same mapping behavior.

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"
    - "*.local"
    - "localhost"
  default-nameserver:
    - 1.1.1.1
  nameserver:
    - https://dns.cloudflare.com/dns-query
  proxy-server-nameserver:
    - https://dns.cloudflare.com/dns-query

DNS policy does not replace egress rules

nameserver-policy selects a resolver for specified domains. It determines where resolution happens, not which egress the resulting connection uses. fallback and fallback-filter provide backup resolution and filter results; they should not be reduced to “try the second resolver only if the first one fails.” Actual behavior depends on the filter conditions, so be clear about the results you expect before configuring them. DNS resolution, the egress used for DNS connections, and the destination app's egress are related but separate concerns. One DNS result alone cannot tell you how the full route works.

Encrypted DNS protects traffic between the client and resolver; using an HTTPS endpoint alone does not prove that no DNS leaks are possible. The OS, browser, and apps may use different resolvers. A browser's own encrypted DNS request may travel as ordinary HTTPS traffic without going through the core's DNS listener. Check which component initiated the request, whether it reached the core, and which policy handled it. For an explanation of the fields, see nameserver, fallback, and fake-IP explained.

TUN routing, permissions, and traffic capture

TUN receives traffic through a virtual network interface and is useful for apps that do not honor system proxy settings. It usually requires administrator privileges or equivalent system capabilities, as well as support from the routing setup, network interface, and core network stack. Enabling it does not mean every network activity is captured: virtual machines, containers, other VPNs, and apps bound to a specific interface may use separate routes. Do not start multiple automatic routing tools and hope for the best. Begin with one setup and check that the interface and routes were created successfully.

tun:
  enable: true
  stack: mixed
  auto-route: true
  auto-detect-interface: true
  dns-hijack:
    - any:53
    - tcp://any:53

dns-hijack sends matching traditional DNS requests within the captured traffic range to the core DNS module. It does not identify and decrypt all encrypted DNS traffic. The snippet above requires dns to be enabled, and actual support depends on the platform, routes, and firewall. auto-detect-interface attempts to select an outbound interface, but you should verify the result when using multiple network adapters, switching networks, or running other tunnels. A wrong default route can send proxy connections back into the virtual interface and create an unintended loop.

After changing fake-IP mode, mapping ranges, or DNS capture settings, the app or system may still have old results cached. Establish a new test connection, clear the relevant cache if needed, and confirm that the core's mappings survived a restart. If only some apps fail, LAN domains behave oddly, or connectivity breaks after waking from sleep, compare DNS resolution and route changes separately rather than permanently disabling the DNS module. Retest using the approach in DNS Leak Testing and Troubleshooting, and keep the before-and-after configs so you can roll back.

Proxy Subscriptions and Rule Providers

Declaring remote resources and referencing them

proxy-providers separates a set of proxies from the main config, which is useful for subscriptions that update regularly. A provider declares whether the resource comes from HTTP or a local file, where to store it, and how often to update it. A proxy group then includes that set using use. Declaring a provider without referencing it in a group does not make its proxies available to rules. Compared with subscribing to a full config, proxy providers let you keep local policies and rules while updating only upstream proxy data, reducing the scope of each update.

The URL below uses an example domain. Replace it locally with your own resource address before using it. A remote proxy file usually needs proxies as its top-level key, followed by a list of proxy entries. Do not paste in an arbitrary webpage, Base64 text, or an unconverted set of URIs. Some clients can convert formats, but that is a client feature; not every core accepts arbitrary formats. Identify what the URL returns before deciding whether to use a provider or import a full config.

proxy-providers:
  Upstream Proxies:
    type: http
    url: "https://example.com/proxies.yaml"
    path: ./providers/upstream.yaml
    interval: 3600
    health-check:
      enable: true
      url: https://www.gstatic.com/generate_204
      interval: 300

proxy-groups:
  - name: Select Exit
    type: select
    use:
      - Upstream Proxies
    proxies:
      - DIRECT

Rule provider behavior and formats

rule-providers manages rule sets, which the main rules list references with RULE-SET. behavior describes how to interpret a set: domain is for domain lists, ipcidr for address ranges, and classical can contain classic rules of different types. format describes how the resource is encoded, such as YAML or text. Behavior and format are separate dimensions. A YAML file extension does not necessarily mean the file contains full classical rules.

rule-providers:
  Local Direct Domains:
    type: file
    behavior: domain
    format: yaml
    path: ./rules/direct.yaml

rules:
  - RULE-SET,Local Direct Domains,DIRECT
  - MATCH,Select Exit

The corresponding rules/direct.yaml can use the structure below. In a domain set, +.example.com matches that domain and its subdomains; do not copy it directly as a complete rule in the main rules list. Classical rule sets usually contain match conditions without a target—the RULE-SET that references the set determines the egress. Mixing these syntaxes can cause load failures or make the actual match scope differ from what you intended.

# rules/direct.yaml
payload:
  - "+.example.com"
  - "localhost"

Update intervals, caches, and access paths

Resource update intervals and health-check intervals are independent. The first downloads new proxy or rule data; the second checks whether existing candidates are available. Changing an interval does not prove an update happened. Check resource timestamps, logs, and the current set. Downloads also depend on the initial network path. If a resource is only reachable through a proxy, but that proxy is included only in the resource that has not been downloaded yet, startup gets stuck. Keep a usable cache or specify a clear initial retrieval path instead of restarting repeatedly.

Set path to a writable working directory, and use a different file for each provider. If several providers share one cache path, they can overwrite one another. Moving from a desktop environment to a service can also change the working directory, making files appear to be missing. Check the current client and core logs to see whether stale cache data is used after a resource becomes unavailable; do not assume the previous copy is always preserved on failure. Keep a rollback copy of important rules so a temporary remote outage does not prevent the entire config from loading.

Subscription URLs often contain account identifiers and should be treated like personal access credentials. When sharing a config, redact the URL, authentication headers, and proxy credentials. Never post an address with query parameters in a public screenshot or support ticket. If an update returns an HTML page, check for a login redirect, expired URL, and response status before treating it as malformed YAML. Once you have confirmed the upstream format is correct, check the local provider fields, reference names, and cache paths. This avoids repeatedly changing the wrong layer.

Override Merging and Runtime Validation

Know what generates the final config

Overrides are client-side processing between the source config and runtime config, not a kernel syntax shared by every client. A common workflow reads a subscription, applies general settings and overrides or scripts, then generates a runtime file; confirm the exact order in your client. An override.yaml file does not take effect just because it is in a directory—it must be explicitly loaded by the client. If changes disappear after an update, check the editing entry point and processing order before repeatedly editing a generated file.

Replacing a scalar, recursively merging a map, and concatenating lists are three different operations. Changing mode from global to rule is usually a scalar replacement. Whether changing dns.nameserver preserves other DNS fields depends on whether the client performs a deep merge. Changing rules may replace the entire list or prepend or append entries. A client calling a feature “merge” does not guarantee the same algorithm for all three data types. Test with a small snippet before broadening the change.

# Client override input only; confirm merge behavior in the client
mode: rule
log-level: info

dns:
  enable: true
  enhanced-mode: fake-ip

profile:
  store-selected: true

Preserve the full meaning of list operations

Prepending rules and appending them have different effects. An exception appended after MATCH will never match; prepending a new catch-all can shadow the existing list. Proxy groups cannot be assumed to merge by name, either: adding a duplicate object may create a conflict, while replacing one may remove its existing provider reference. Before writing an override, state the exact intended change—for example, “insert a LAN exception just before the final catch-all”—then confirm that the client supports that operation. Do not start by assembling YAML that merely looks similar.

If your client supports script overrides, keep the script and a note about its changes locally; do not run processing code from an unknown source. Scripts can read or modify the entire config and have a wider impact than simple field overrides. A safer approach is to change only the necessary keys, handle missing objects and empty lists, and preserve all other fields. When moving to another client, migrate the intended result and data files first. Do not assume the original client's script API, variable names, or merge order will carry over unchanged.

From static checks to runtime validation

A standalone core can check config structure and references with a config test command. The command below uses the current directory as its working directory and reads config.yaml; adjust the executable name and directory to match your installation. Desktop clients usually provide a built-in validation or log view, so there is no need to start a second core and compete for the listening port. A successful test only means that the config passed that check. It does not validate account access, remote server status, system proxy settings, TUN permissions, or the traffic path used by every app.

mihomo -t -d . -f ./config.yaml

Save a working config before making changes. After applying them, check key fields in the runtime file, not just whether the source file was saved. Then create a new test connection and verify the inbound path, mode, matched rule, proxy group chain, and egress in order. For DNS changes, also check the resolution result and whether a cached response was used. Recording these checkpoints separately helps identify whether the problem is in config loading, resource retrieval, or the actual service request. “No internet” can have very different causes and fixes.

Observed resultCheck firstNext step
Config test failsIndentation, field types, duplicate keys, and referencesFix the complete structure around the reported location
Test passes, but startup failsPorts, permissions, resources, and working directoryRead the startup log; do not change rules yet
Core is running, but there are no connection entriesSystem proxy, app proxy settings, and TUN routesConfirm that traffic reaches the core
Connections appear, but the egress is wrongMode, first matching rule, and group selectionClose the old test connection and make a new request
Changes disappear after an updateOverride entry point and generation orderMove the change to a persistent override and inspect the final file

Rollback should account for both the config and runtime state. After restoring an older file, also check the current mode, manual group selection, DNS cache, and TUN routes for state left over from the newer setup. Change one type of behavior at a time and keep a brief change log; this makes issues easier to isolate than replacing proxies, DNS, and rules all at once. For your first setup, return to the quick-start guide and follow the main workflow. For a specific problem, see FAQ. This reference explains how fields relate; it is not a fixed set of settings for every network.