mihomo Config File Basics: Understanding the YAML Structure
On this page
Everything mihomo does is driven by a single file: config.yaml. Ports, routing rules, DNS behavior, the list of servers — it is all declared there in YAML, a human-readable format that mihomo inherited from Clash and extended. Most people never write this file from scratch, because a subscription generates it for them. But sooner or later you will want to read one: to fix a startup error, tweak a rule, or understand why traffic goes where it goes.
This guide covers the mihomo config file from the ground up: the YAML syntax rules that cause 90% of errors, what each top-level field does, a minimal configuration you can actually run, and how to validate a file before starting the core.
YAML syntax rules that actually matter
- Indent with spaces, never tabs. Two spaces per level is the convention. A single tab character anywhere will stop the file from parsing.
- Put a space after every colon.
mode: ruleis valid;mode:ruleis not. - Keep nesting consistent. Items in the same list or map must start at the same column.
- Quote values with special characters. Names containing
:,#or emoji are safest inside double quotes. - Beware invisible characters. Text copied from chat apps or web pages can carry full-width colons, smart quotes or non-breaking spaces that look identical but break parsing. Retype the character if a line refuses to work.
Top-level fields at a glance
| Field | What it does |
|---|---|
mixed-port | One local port that accepts both HTTP and SOCKS proxy connections |
mode | Outbound mode: rule, global or direct |
log-level | Verbosity of core logs: silent, error, warning, info, debug |
external-controller | Address of the control API used by dashboards and GUI clients |
dns | Built-in DNS resolver settings, including enhanced-mode |
proxies | The list of individual servers (nodes) |
proxy-groups | Groups that organize nodes for selection and automation |
rules | Routing rules that map traffic to groups or policies |
A minimal config you can run
The file below starts a local HTTP/SOCKS listener and sends all traffic out directly — no servers yet, but it parses, runs, and gives you a skeleton to extend:
mixed-port: 7890
mode: rule
log-level: info
external-controller: 127.0.0.1:9090
proxies: []
proxy-groups: []
rules:
- MATCH,DIRECT
Save it as config.yaml, run mihomo -d . in the same directory, and point a browser at 127.0.0.1:7890 to confirm the listener works. The port here is just an example value — in GUI clients, check the settings page for the actual mixed port (commonly 7890 or 7897).
How proxies, groups and rules fit together
The three big sections form a chain. proxies defines the raw endpoints. proxy-groups organizes them into named units — a manual selector, an auto-test group, a fallback chain — and each group type behaves differently. Finally, rules decides which traffic goes to which group, evaluated top to bottom; the rule types and matching order deserve their own article. A rule never points at a bare server directly in well-structured configs — it points at a group, which keeps everything switchable.
Validate before you run
mihomo has a built-in test mode that parses a config without starting anything:
mihomo -t -f config.yaml
On success it prints a test-passed message; on failure it names the problem and usually the line number. Run this after every manual edit — it takes a second and catches mistakes before they take your connection down.
Reading common error messages
- "found a tab character" or "mapping values are not allowed" — indentation problem. Go to the reported line and rebuild the whitespace with plain spaces.
- "already defined" / duplicate key — the same field appears twice at the same level, often after pasting a snippet. Delete one.
- "unmarshal errors" naming a field — the value has the wrong type, such as text where a number belongs (
mixed-port: "abc"). - A proxy or group "not found" — a rule or group references a name that does not exist; names must match exactly, including case and emoji.
Tip: when an error makes no sense, check the line above the reported one — YAML parsers often notice a mistake only on the following line.
Once the structure feels familiar, the next layer worth understanding is the resolver: the DNS section and its fake-ip mode explain much of mihomo's behavior that otherwise looks like magic.