REF-00 · CONFIG.YAML · FIELD MANUAL

Clash Config Field Reference

This page is a field-level lookup manual for config.yaml: starting with the file's overall structure, then breaking down general runtime fields, the DNS module, proxies, proxy groups, and rule syntax, and finishing with the override and merge mechanism used with subscriptions. Each section comes with a runnable YAML snippet and a parameter table. If you haven't finished installing the client and importing a subscription yet, work through the main steps in the usage guide first, then come back here for reference; installers are on the downloads page.

SEC-01

How to Read This Page

Everything a Clash-family client does is driven by a single YAML config file: which port it listens on, how DNS resolves, what proxies exist, and which rules route traffic. The switches and dropdowns in a GUI client are essentially a visual editor for this file — understanding the fields themselves is what lets you get unstuck when the UI options run out, or when a subscription needs manual tweaking.

This site divides config-related content deliberately: the usage guide covers the shortest path from download to a working connection without dwelling on field details; FAQ collects standalone Q&As searchable by symptom; this page is a systematic field reference, organized in the top-to-bottom order fields appear in the config file — good for a full read-through to build a mental model, and equally good for jumping straight to a section via the table of contents above.

Field semantics here are based on the mihomo kernel. Since the original Clash kernel was archived, mainstream GUI clients — including our top pick Clash Plus, plus Clash Verge Rev, FlClash, and Clash Nyanpasu — have all switched to mihomo, and the fields described here apply across them; a handful of mihomo-only extensions won't work on very old kernels, and those are flagged inline. Platform coverage and download links are on the downloads page; for how these projects relate to each other, see "How Clash, mihomo, and Verge Rev Relate to Each Other".

NOTE

If you use a subscription-based service: the subscription link itself returns a complete config.yaml, with proxies and rules maintained by your provider. Reading this page helps you understand what's in it, but editing the subscription file directly gets overwritten on the next update. See Section 8, "Override & Merge," for the correct way to make persistent changes.

↑ Back to top
SEC-02

YAML Structure Overview

Top-Level Structure: A Minimal Working Skeleton

config.yaml is a mapping made up of several top-level keys. Stripped of every optional field, a minimal runnable config needs just five parts: runtime settings, DNS, the proxy list, the proxy group list, and the rule list. Here's the skeleton, with each part expanded in the sections below:

mixed-port: 7890
allow-lan: false
mode: rule
log-level: info
external-controller: 127.0.0.1:9090

dns:
  enable: true
  enhanced-mode: fake-ip
  nameserver:
    - https://223.5.5.5/dns-query

proxies:
  - name: "HK-01"
    type: ss
    server: hk01.example.com
    port: 8388
    cipher: aes-256-gcm
    password: "your-password"

proxy-groups:
  - name: "PROXY"
    type: select
    proxies:
      - HK-01
      - DIRECT

rules:
  - DOMAIN-SUFFIX,example.com,PROXY
  - GEOIP,CN,DIRECT
  - MATCH,PROXY

Top-level keys have no required loading order — the kernel just reads whichever keys exist — but convention places them as "runtime settings → dns → proxies → proxy-groups → rules," matching the logical order traffic is processed in, which makes reading and troubleshooting easier. The table below lists common top-level keys and their types:

Top-level keyTypePurposeRequired
mixed-port and other port keysIntegerLocal listening portAt least one
modeEnum stringRouting mode (rule/global/direct)Recommended to declare explicitly
dnsMappingBuilt-in DNS moduleRequired for TUN/transparent proxy
proxiesArrayProxy definitionsYes
proxy-groupsArrayProxy group definitionsYes
rulesString arrayRouting rules, matched top-downRequired in rule mode
proxy-providersMappingExternal proxy sets (split subscriptions)No
rule-providersMappingExternal rule setsNo
tunMappingVirtual network adapter parametersNo

Formatting Rules: Indentation, Quoting, and Common Typos

YAML is format-sensitive, and a large share of config errors trace back to formatting, not incorrect fields. Three hard rules: first, indentation must use spaces only — two spaces consistently; tabs cause an outright parse failure, and the reported line number is often far from the actual mistake, making it hard to locate; second, a colon must be followed by a space — port:7890 is invalid; third, array items start with "dash + space," and the dash's indentation level determines which key it belongs to.

Strings don't need quotes by default, but three situations require them: the value contains a colon, hash, or other special character; the value is purely numeric but should be treated as a string; or it's a sensitive value like a password or UUID that might start with a special character — quoting everything with double quotes is the low-effort habit to adopt. Also watch for a YAML 1.1 legacy trap: unquoted yes, no, on, and off get parsed as booleans by some parsers — quote them if a proxy name happens to match one of these words.

WARN

Copying a config snippet from a webpage can leave rich-text editors replacing regular spaces with non-breaking spaces (U+00A0), which are invisible to the eye but cause a "found character that cannot start any token" parse error. Paste into a plain-text editor, or select-all and re-indent after pasting.

↑ Back to top
SEC-03

General Fields

The Port Family: mixed-port, port, and socks-port

Port fields determine how local apps hand traffic to the kernel. mixed-port is the current recommended setting: a single port accepts both HTTP and SOCKS5 inbound traffic, so the system proxy only needs to point at this one port — this is what most clients generate by default, conventionally set to 7890. The legacy port (HTTP only) and socks-port (SOCKS5 only) fields still work and can coexist with mixed-port, listening on separate ports — useful for debugging scenarios where you need to distinguish protocol entry points.

There are also redir-port and tproxy-port, aimed at Linux transparent proxying (paired with iptables/nftables forwarding); everyday desktop use doesn't need these. All ports share one constraint: they can't conflict with another process on the machine. A startup error reading bind: address already in use means the port is taken — for the full diagnosis and fix, see "What to Do When Clash Reports Port In Use".

allow-lan and bind-address

allow-lan controls whether the client accepts inbound connections from other devices on the local network; it defaults to false (listening only on 127.0.0.1). Set it to true and phones or streaming boxes on the same Wi-Fi can point their proxy settings at this machine's LAN IP and port, effectively sharing one connection across the household. The companion bind-address field restricts which network interface is used for listening: the default "*" means all interfaces, and on multi-NIC setups you can supply a specific interface address to narrow the entry point. Turning on allow-lan means any device on the local network can route traffic through your exit node — keep it off on public networks like offices or hotels.

mode: Three Routing Modes

mode accepts three values. rule is rule mode, where every connection is checked against the rules list one by one — the everyday standard; global is global mode, skipping rules and sending all traffic to a single global exit (typically shown in the UI as picking one proxy directly); direct is direct mode, where all traffic bypasses the proxy entirely — effectively pausing routing while keeping the kernel running. When trying to figure out "which rule is this site actually hitting," toggling between global and rule mode is a quick way to tell whether the problem lies in the rules or in the proxy itself.

Logging and the External Controller

log-level controls how verbose kernel logs are, from quietest to loudest: silent, error, warning, info, debug. Info is fine for daily use; switch to debug when troubleshooting to see exactly which rule and DNS resolution path each connection hits, then switch back once things are stable to avoid bloating log files. external-controller declares the listen address for the RESTful control API (conventionally 127.0.0.1:9090), which GUI clients and web dashboards use to read state and switch proxies; the companion secret field sets an access token for that API — required whenever the controller listens on 0.0.0.0 or is exposed to the LAN, e.g. secret: "your-secret".

Other Common Switches

ipv6 defaults to false; enabling it lets the kernel resolve and connect via AAAA records, which can actually cause timeouts on some sites if IPv6 isn't properly supported locally or on the proxy side — confirm your path supports it before turning this on. unified-delay (a mihomo extension) subtracts handshake overhead from latency tests, making latency numbers more comparable across different protocols. Under the profile block, store-selected: true remembers each group's last-selected proxy across restarts or subscription updates, so you don't have to re-pick — nearly every client template enables this by default.

↑ Back to top
SEC-04

DNS Fields

Why Built-In DNS Matters

Routing depends on knowing where a connection is headed, and domain resolution is exactly the step most prone to tampering or leakage: if resolution is handed off to an untrusted upstream, the returned IP might be wrong; if every lookup goes through your local ISP, your browsing history is fully exposed. The dns module lets the kernel take over resolution, working with the rule system to decide which domains use which DNS servers and how results get handed back to applications. Under TUN mode or transparent proxying, the dns module is required; with system proxy mode alone it's optional, but enabling it noticeably improves routing accuracy.

dns:
  enable: true
  listen: 0.0.0.0:1053
  enhanced-mode: fake-ip
  fake-ip-range: 198.18.0.1/16
  fake-ip-filter:
    - "*.lan"
    - "+.local"
    - "time.*.com"
  default-nameserver:
    - 223.5.5.5
    - 119.29.29.29
  nameserver:
    - https://223.5.5.5/dns-query
    - https://doh.pub/dns-query
  fallback:
    - https://1.1.1.1/dns-query
  fallback-filter:
    geoip: true
    geoip-code: CN

enhanced-mode: fake-ip vs. redir-host

This is the highest-impact field in the dns block. In fake-ip mode, the kernel returns a fake address from a reserved range (defined by fake-ip-range, defaulting to 198.18.0.0/16) for each domain; the application connects using that fake IP while the kernel maintains the mapping between fake IP and real domain. The upside: applications skip real resolution entirely, rules can match directly on domain names, connections establish quickly, and there's no resolution leakage; the downside is that a handful of programs relying on real IPs — LAN discovery, some game matchmaking, NTP sync — will misbehave, and those domains need to go into the fake-ip-filter allowlist, which falls back to real resolution for matches. redir-host mode always returns real IPs, giving the best compatibility, but domain information gets lost on some paths, so both rule hit rate and resolution speed lag behind fake-ip. Desktop client templates generally default to fake-ip and add filter entries only when a specific app misbehaves.

Comparisonfake-ipredir-host
IP seen by the appFake address from reserved rangeReal resolved result
Connection setup speedFast (skips waiting for resolution)Affected by upstream resolution time
Domain rule hit rateStableSome cases degrade to IP-based matching
Compatibility riskPrograms needing real IPs must be allowlistedEssentially none

Three Upstream Groups: default-nameserver, nameserver, and fallback

These three lists have distinct jobs. default-nameserver does exactly one thing: resolve the domain names of the DoH/DoT servers listed in the other two groups, so it must be plain IPs — otherwise you get a deadlock where "the resolver's own domain has nothing to resolve it." nameserver is the primary upstream, handling everyday resolution; it's best set to encrypted-protocol addresses (DoH starting with https:// or DoT starting with tls://), avoiding plaintext port 53, which can be tampered with in transit. fallback is the backup upstream, working alongside fallback-filter: when nameserver's result matches the filter condition (typically geoip: true with geoip-code: CN, meaning "the result isn't a mainland China IP"), the fallback result is used instead — this counters DNS tampering, giving overseas domains a clean resolution. If you don't need this mechanism, keeping just nameserver is simpler.

NOTE

After changing the dns block, flush your system DNS cache before testing (ipconfig /flushdns on Windows, sudo killall -HUP mDNSResponder on macOS) — otherwise a stale cache can make the new config look like it "didn't take effect."

↑ Back to top
SEC-05

Proxy Fields

Four Fields Shared by Every Protocol

Each element in the proxies array defines one proxy. Regardless of protocol, four fields are required: name (must be unique across the whole file — proxy groups and rules reference proxies by name, and duplicates cause a load failure), type (protocol type), server (server hostname or IP), and port (server port). The optional udp field declares whether the proxy forwards UDP traffic — worth enabling for gaming and real-time calls, provided the server supports it. mihomo supports a broad set of protocols: ss, vmess, trojan, vless, hysteria2, tuic, wireguard, socks5, http, and more can all be used as the type value. Below are the three most common, expanded.

Shadowsocks (type: ss)

proxies:
  - name: "HK-01"
    type: ss
    server: hk01.example.com
    port: 8388
    cipher: aes-256-gcm
    password: "your-password"
    udp: true

The core is the encryption parameters: cipher and password must exactly match the server. Common ciphers include aes-256-gcm, chacha20-ietf-poly1305, and the newer 2022-blake3-aes-256-gcm (which requires a Base64-encoded fixed-length key as the password, not an arbitrary string). Mismatched encryption parameters typically show up as an immediate disconnect with a decryption error in the logs. If the server has a plugin enabled (such as obfs), you'll also need the plugin and plugin-opts fields.

VMess (type: vmess)

  - name: "JP-01"
    type: vmess
    server: jp01.example.com
    port: 443
    uuid: 23ad6b10-8d1a-40f7-8ad0-e3e35cd38297
    alterId: 0
    cipher: auto
    tls: true
    network: ws
    ws-opts:
      path: /ray
      headers:
        Host: jp01.example.com

The credential here is uuid, issued by the server and copied verbatim. alterId is fixed at 0 for modern deployments (enabling AEAD). network determines the transport layer: tcp connects directly, ws uses WebSocket (often paired with a CDN in front), and grpc uses gRPC; choosing ws means supplying path and Host header in ws-opts — any mismatch with the server on these three values causes the handshake to fail. When tls: true, servername can set the SNI independently (useful when server is an IP but the certificate is issued for a domain).

Trojan (type: trojan)

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

Trojan runs natively over TLS, disguising itself as ordinary HTTPS traffic. sni should match the server certificate's domain; skip-cert-verify controls whether certificate validation is skipped, and leaving it at false is a hard baseline — setting it to true means giving up on verifying the server's identity, letting any man-in-the-middle impersonate the proxy. Only a self-signed test environment is ever a legitimate reason to flip this temporarily. For the causes and diagnosis of certificate errors behind a proxy, see "Common Causes of HTTPS Certificate Errors Behind a Proxy".

WARN

Some subscriptions bulk-set skip-cert-verify: true on every proxy to "reduce errors." Once you understand this section, consider flipping it back to false in your override layer; if a proxy genuinely fails to connect because of this, question that proxy's certificate setup rather than disabling verification.

↑ Back to top
SEC-06

Proxy Group Fields

What a Proxy Group Is

proxy-groups adds a layer of abstraction between proxies and rules: rules don't point directly at a specific proxy but at a group, and the group decides the actual exit based on its policy (manual selection, auto latency testing, failover, and so on). The benefit is obvious — switching proxies only means switching within the group, leaving hundreds of rules untouched; when a subscription update renames proxies, only the group's member list is affected. A group's proxies members can be a proxy name, the built-in DIRECT (direct connection) or REJECT (block) policies, or the name of another group, letting you build a hierarchy like "region groups → main exit group"; the only restriction is no circular references.

proxy-groups:
  - name: "PROXY"
    type: select
    proxies:
      - AUTO
      - HK-01
      - JP-01
      - DIRECT

  - name: "AUTO"
    type: url-test
    url: https://www.gstatic.com/generate_204
    interval: 300
    tolerance: 50
    lazy: true
    proxies:
      - HK-01
      - JP-01
      - SG-01

Five Group Types, Explained

typeBehaviorTypical use
selectManual selection, holds the choice until the user changes itMain exit; scenarios needing manual control
url-testPeriodic latency test, auto-picks the lowest-latency memberAuto-optimizing among multiple proxies in the same region
fallbackTakes the first available member in list orderPrimary/backup failover, switches back once primary recovers
load-balanceSpreads connections across multiple membersAvoiding a single proxy's rate limit, boosting concurrent throughput
relayChains members in sequence to form multi-hop forwardingMulti-hop exits (each hop adds latency)

Auto-type groups (url-test/fallback/load-balance) rely on three test parameters: url is the probe address, typically a lightweight endpoint that returns an empty 204 response; interval is the probe period in seconds — 300 is a common balance, and setting it too low generates constant test traffic; tolerance is used only by url-test, meaning "only switch if the latency gap between the current best and a new candidate exceeds this many milliseconds," which suppresses flapping between two proxies with similar latency. lazy: true (a mihomo extension) pauses probing when a group isn't in use, noticeably cutting background requests when there are many proxies. load-balance also has a strategy field: consistent-hashing tries to keep the same destination site routed through the same proxy (friendly to logged-in sessions), while round-robin strictly alternates.

Organizing Your Groups

In practice, a three-layer structure works well: a single top-level select group as the main exit (which most rules point to); a middle layer of one url-test auto group per region; and the proxies themselves at the bottom. For services with region requirements — streaming, AI services — set up a dedicated select group whose members reference the region groups. This way, day-to-day operation needs zero intervention (auto latency testing takes over), specific services can be manually pinned to a region, and the impact of subscription updates stays contained within the region groups.

↑ Back to top
SEC-07

Rule Syntax

Basic Format and Matching Order

Each element in the rules array is a single string in the form TYPE,VALUE,POLICY, comma-separated; the policy segment can be a group name, a proxy name, or the built-in DIRECT/REJECT. For every new connection, the kernel checks rules top-to-bottom and stops at the first match — this single fact governs everything: specific rules (exact domains) must come before broad rules (suffixes, keywords, GEOIP), or they'll never get a chance to match; the list ends with a MATCH catch-all that absorbs anything unmatched. The number of rules barely affects performance (domain rules use a prefix-tree index), but ordering mistakes cause routing errors that are hard to spot — verify hit behavior against the log after each change.

rules:
  - DOMAIN,api.example.com,DIRECT
  - DOMAIN-SUFFIX,example.com,PROXY
  - DOMAIN-KEYWORD,tracker,REJECT
  - IP-CIDR,192.168.0.0/16,DIRECT,no-resolve
  - GEOSITE,category-ads-all,REJECT
  - GEOIP,CN,DIRECT
  - MATCH,PROXY

Rule Type Reference

TypeMatches onExample
DOMAINExact full domain matchDOMAIN,api.example.com,DIRECT
DOMAIN-SUFFIXA domain and all its subdomainsDOMAIN-SUFFIX,example.com,PROXY
DOMAIN-KEYWORDDomain containing a given substringDOMAIN-KEYWORD,google,PROXY
IP-CIDR / IP-CIDR6Destination IP falls within a rangeIP-CIDR,10.0.0.0/8,DIRECT,no-resolve
GEOIPGeographic origin of destination IPGEOIP,CN,DIRECT
GEOSITECommunity-maintained domain setsGEOSITE,github,PROXY
PROCESS-NAMEName of the process making the connection (desktop only)PROCESS-NAME,steam.exe,DIRECT
RULE-SETReferences a rule-providers setRULE-SET,streaming,PROXY
MATCHUnconditional catch-allMATCH,PROXY

no-resolve and the Interaction Between Domain and IP Rules

IP-based rules (IP-CIDR/GEOIP) have an easily overlooked side effect: when the connection target is still a domain, matching against an IP requires resolving it first — that resolution can leak through local DNS and also slows matching down. Appending a fourth field, no-resolve, to an IP rule means "only match if the target is already an IP; skip this rule if it's a domain" — LAN range rules should always carry this. The overall ordering rule of thumb: domain rules first, IP rules next, MATCH last; ad-blocking (REJECT) entries go at the very front of their category. For the full topic of writing rules — including whether custom rules should be inserted before or after subscription rules — see "How to Write Custom Clash Rules".

rule-providers: Externalizing Rules

rule-providers:
  streaming:
    type: http
    behavior: classical
    format: yaml
    url: https://example.com/rules/streaming.yaml
    path: ./rules/streaming.yaml
    interval: 86400

rules:
  - RULE-SET,streaming,PROXY

Cramming thousands of rules into the main file is hard to maintain and hard to share, so rule-providers lets you load rule sets from an external URL or local file, refreshed on an interval of seconds. behavior declares the set's content shape: domain (plain domain list), ipcidr (plain range list), or classical (full three-field entries like rules). A mismatch between behavior and the file's actual content causes the set to silently fail — the number one reason an externalized rule set "looks loaded but doesn't work."

↑ Back to top
SEC-08

Override & Merge

Why You Shouldn't Edit a Subscription File Directly

Subscription users face a structural conflict: the config file is generated by the provider, and every time the subscription updates, the entire file gets re-downloaded and overwritten — any rule you hand-added or port you changed only survives until the next update. The correct approach is to keep "the provider's base config" and "your own changes" stored separately, merged into a final config by the client at load time. Different clients call this mechanism by different names — Override, Merge, extended config — the principle is the same.

Basic Merge Semantics

The merge/override config is itself a YAML file that only contains what you want to change. Semantics fall into two categories: scalar and mapping fields get replaced outright — writing mixed-port: 7891 in the override makes 7891 the final port, and writing a full dns: block replaces the entire base dns block; array fields support prepending and appending — most clients use a prepend- prefix to insert at the start of a base array and an append- prefix to add at the end, which matters a great deal for rules: prepended rules take priority over subscription rules, while appended rules can only act as a fallback. A typical override:

mixed-port: 7891
log-level: warning

prepend-rules:
  - DOMAIN-SUFFIX,internal.example.com,DIRECT
  - PROCESS-NAME,steam.exe,DIRECT

append-proxies:
  - name: "SELF-01"
    type: ss
    server: my.example.com
    port: 8388
    cipher: aes-256-gcm
    password: "your-password"
NOTE

The exact key names and supported scope for prepend/append vary slightly by client implementation: Clash Verge Rev offers a "global extended config" plus a two-tier Merge/Script override per subscription, while Clash Plus provides an override editor within subscription details. Follow your specific client's documentation for exact syntax — what's given here is the general semantics.

Script Overrides and proxy-providers

When declarative merging isn't enough — say, batch-filtering proxies by name, or inserting a member into every group at once — some clients (like Verge Rev) support JavaScript script overrides: the script receives the parsed config object and returns a modified one, offering maximum flexibility at the cost of the whole config failing to load if the script errors, so change it in small steps and verify each time. Another approach flips the model: instead of using the provider's entire config, reference only the subscription's proxy list via proxy-providers, while building proxy groups and rules entirely yourself. This way subscription updates only affect the proxy pool, and the main config stays yours — a good fit once you've worked through this manual and are willing to maintain your own rule set:

proxy-providers:
  airport:
    type: http
    url: https://example.com/subscribe?token=xxxx
    path: ./providers/airport.yaml
    interval: 43200
    health-check:
      enable: true
      url: https://www.gstatic.com/generate_204
      interval: 600

proxy-groups:
  - name: "PROXY"
    type: select
    use:
      - airport

Note that a group references a provider via the use field (not proxies) — the two can be combined; health-check lets proxies inside a provider also be probed for availability.

↑ Back to top
SEC-09

Validation & Troubleshooting

Before Loading: Static Validation

Don't just restart and hope after editing a config. If you have the mihomo kernel binary available, one command runs a pure syntax and semantics check without starting any listener:

mihomo -d . -t -f config.yaml

-t is test mode, -d specifies the working directory (where resources like GeoIP data are found), and -f specifies the file to check. Output reading configuration file ... test is successful means it passed; error messages give a line number and cause, with common ones being: indentation errors (yaml: line N), duplicate proxy names (proxy N: name duplicated), a group referencing a nonexistent member (proxy group ... proxy not found), and typos in a rule's policy field. GUI clients run the same validation on import, and the error dialog's message matches the command-line output — just trace back to that line number in the file.

After Loading: Verifying Routing Behaves as Expected

A config loading successfully doesn't mean it behaves correctly. A three-step verification approach: first, check the logs — temporarily set log-level to debug, visit the target site, and the log will print which rule this connection hit and its final exit, the only authoritative way to know "which rule actually matched"; second, check the connections panel — a GUI client's connections page lists active connections in real time along with their target, matched rule, and exit group, good for observing overall traffic distribution; third, do an external check — visit an IP-detection service both directly and through the proxy, confirming the exit address actually changes with policy. If routing looks correct but a specific app isn't going through the proxy, suspect first that the app is bypassing the system proxy setting — the Windows Store app loopback restriction is a classic example; see "Why Windows Store Apps Don't Use the Proxy" for the fix.

Common Issues, Quick Reference

SymptomLikely causeRelevant section
Startup fails with bind: address already in usePort is occupied by another processSection 3 · Port family
Load fails with yaml: line NIndentation/tabs/missing space after a colonSection 2 · Formatting rules
All proxies time out but the subscription updates fineProxy credentials or transport parameters don't match the serverSection 5 · Proxy fields
Domain rules aren't taking effectDomain lost under redir-host, or a broad rule matched firstSections 4/7
A change disappears after the subscription updatesYou edited the subscription file directlySection 8 · Override & merge
LAN devices can't connect to the shared proxyallow-lan is off, or a firewall is blocking inbound connectionsSection 3 · allow-lan

More symptom-organized Q&As are on the FAQ page; if you suspect the client itself rather than the config is at fault, try a different client from the downloads page for cross-checking — Clash Plus is our top pick across all platforms, and comparing the same config's behavior across clients often quickly narrows down where the problem sits.

↑ Back to top