Syntax
Mihomo uses YAML as its config file format. Here's a rundown of the syntax rules you'll need when writing your config, including comments, objects/arrays, anchors and references, domain wildcards, and port range syntax.
Basic Rules
YAML is case-sensitive and uses indentation to represent hierarchy. Indentation must use spaces, not tabs — the exact number of spaces doesn't matter, as long as elements at the same level are aligned.
If your editor shows an "indentation looks right but doesn't match" error, chances are a tab character snuck in somewhere — double-check your indentation.
Comments
Everything from # to the end of the line is a comment. The # must be at the start of the line or preceded by a space, otherwise it isn't treated as a comment (e.g. a # inside a URL is unaffected).
port: 7890 # HTTP proxy port socks-port: 7891 # SOCKS proxy port
Objects & Arrays
Objects are written as key: value, with a space required after the colon. Since YAML is a superset of JSON, you can also write JSON-style syntax directly — all four forms below are exactly equivalent:
tun: enable: true stack: system auto-route: true auto-detect-interface: true
tun: { enable: true, stack: system, auto-route: true, auto-detect-interface: true }
Arrays are written as lines starting with -, and also support the single-line JSON format a: [b, c, d], which is equivalent to the multi-line array:
a: - b - c - d
Anchors & References
& tags a block of config with an anchor, * references that anchor, and << merges the anchor's content into the current object. When writing multiple proxy providers or rule providers, you can write shared fields once and reuse them via anchors, saving a lot of repeated code.
p: &p type: http interval: 3600 health-check: enable: true url: https://www.gstatic.com/generate_204 interval: 300 proxy-providers: provider1: <<: *p url: "" path: ./proxy_providers/provider1.yaml provider2: <<: *p type: file path: ./proxy_providers/provider2.yaml
This is equivalent to copying the p anchor's content into both provider1 and provider2. Note that if a field is duplicated during the merge (e.g. provider2 redefines type), your own value takes precedence and won't be overridden by the anchor. Also note that the key name p itself isn't a valid mihomo field — it's only there to hold the anchor, and gets ignored during parsing.
Domain Wildcards
The wildcards described here are specifically for fields like fake-ip-filter and nameserver-policy — they're not the same as DOMAIN-WILDCARD used in routing rules, and the syntax isn't interchangeable.
| Wildcard | Matches | Example |
|---|---|---|
* | Matches only a single subdomain level | *.baidu.com matches tieba.baidu.com, but not 123.tieba.baidu.com or baidu.com |
+ | Matches any number of levels (prefix form, similar to DOMAIN-SUFFIX) | +.baidu.com matches baidu.com, tieba.baidu.com, and 123.tieba.baidu.com all at once |
. | Matches any number of levels, but not the bare domain itself | .baidu.com matches tieba.baidu.com, but not baidu.com |
It's a good idea to wrap wildcards in quotes to avoid YAML parsing them as another type:
fake-ip-filter: - ".lan" - "xbox.*.microsoft.com" - "+.xboxlive.com" - localhost.ptlogin2.qq.com
Importing Domain Sets
Some fields (like fake-ip-filter) support importing a rule-set or geosite set directly, using the syntax type:set-name:
The rule-set option here only supports rule providers with a domain or classical behavior.
fake-ip-filter: - "rule-set:xxx" - "geosite:xxx"
Port Ranges
Use - for a port range, and / or , to separate multiple ports/ranges — these can be mixed:
# Matches the ranges 114-514 and 810-1919, plus port 65530 on its own 114-514/810-1919,65530