The Problem mixin Solves on One Machine
Power users rarely have exactly one network. The same laptop might sit on a trusted home LAN on Sunday, a corporate SSID on Monday, and a guest network on Wednesday. Each place imposes different constraints: at home you may want aggressive TUN with DNS hijack; at work you may need the tunnel off so an enterprise VPN can own routes; on public Wi-Fi you might tighten bind addresses so you never accidentally expose a mixed port. Meanwhile your airport subscription keeps refreshing proxies, proxy-groups, and remote rule providers you do not want to hand-merge every time the provider bumps a UUID.
The mixin: section in Clash Meta cores (the family many distributions label Mihomo) exists so you can keep the upstream “bundle” authoritative for nodes and large rule sets while you maintain a small, auditable local overlay for environment-specific knobs. Think of it as version control for the handful of lines you actually understand, sitting on top of the thousand lines you import. If you are still migrating from legacy cores, read the Clash Meta upgrade guide first so field names in your remote profile and your mixin speak the same dialect—nothing in this article fixes a YAML key your upstream never emitted.
Load Order: Remote Profile, Local Files, and mixin
Exact ordering is client-dependent, but the mental model that keeps people out of trouble is consistent: the core loads a base document (often downloaded from a subscription URL or opened from a large static file), then applies a patch document described by mixin: (and sometimes additional “prepend/append” hooks exposed in GUIs). The result is the effective configuration the runtime sees. When documentation says “deep merge,” it almost always means recursive merging for mapping nodes: if both base and mixin define a tun: map, the child keys combine, with mixin values winning on key collisions at the same depth.
That behavior is powerful and treacherous. It means you can set tun.enable in mixin without repeating the entire tun: block from the remote file—but it also means a forgotten child key in the base (for example an old dns-hijack list) may still be present unless your mixin replaces the parent structure in a way your client interprets as a full override. When routing complexity grows, keep rules and routing best practices nearby so you are not using mixin to paper over fundamental ordering mistakes in rules:.
Lists (rules:, proxies:, bare arrays under dns.nameserver, etc.) are the frequent surprise: many stacks treat a list in mixin as replacing the entire list from the base rather than appending individual elements. If you expected “add three prepend rules” but only see those three lines at runtime, you did not discover a bug—you learned how your merge layer handles sequences. Some GUI clients add dedicated “prepend” or “append” editors that translate into supported extension fields; when in doubt, inspect the effective config your client exports after merge.
mixin is a specific top-level key. Your GUI may label it Merge, Patch, or Profile Override, but the on-disk spelling must match what your core build expects.
The mixin: YAML Shape (Maps, Lists, Pitfalls)
At minimum, mixin: is a mapping of the same shape as the fragments you want to influence at the root of the profile. A conservative first experiment touches only listeners and logging—surface area small enough that mistakes are obvious. Once comfortable, grow into tun:, dns:, and selective rules replacements.
mixin:
mixed-port: 7890
bind-address: '127.0.0.1'
log-level: debug
When you need to adjust DNS without pasting the provider’s entire dns: block into your notes, override nested keys explicitly. Pair that work with the Clash Meta DNS step-by-step guide so you know which child fields interact with fake-ip and fallback filters—mixin cannot fix contradictory DNS policies hiding inside the remote base.
mixin:
dns:
enable: true
listen: '127.0.0.1:1053'
enhanced-mode: fake-ip
nameserver:
- https://1.1.1.1/dns-query
The example above may replace dns.nameserver entirely if your merge implementation treats lists that way. If the base carried four resilient resolvers and mixin supplies one, you have voluntarily downsized redundancy. When you need additive behavior, prefer features designed for it—rule-providers plus a slim set of local rules:, or GUI prepend slots—instead of hoping a list merge will magically union two arrays.
Multi-Environment Walkthrough: Home vs Office
A practical pattern keeps one remote profile and two tiny local files checked into your dotfiles repo: mixin-home.yaml and mixin-office.yaml. Your launcher script (or GUI profile switcher) points the client at the same subscription but selects which mixin fragment to embed or import for the day. Differences worth isolating include tun.enable, tun.stack, dns.listen, allow-lan, external-controller bind addresses, and lightweight rules that pin RFC1918 traffic to DIRECT when corporate split tunneling demands it.
At home you might enable TUN with auto-route and aggressive DNS hijack as described in the TUN mode deep dive. At the office you might disable TUN entirely so policy-based VPN software can install its own interface without fighting Clash for the routing table, relying instead on a conservative system proxy or application-level SOCKS. Mixin makes that swap a one-field change—if you actually reload the core after switching files. Many “it worked at home” reports are simply stale processes holding yesterday’s effective config.
Document each environment’s non-negotiables: split DNS domains for internal git hosts, HTTP proxies mandated by compliance, or split horizons that require DIRECT to a subnet. Put those lines in mixin, not in ephemeral GUI toggles you cannot reproduce next month. For subscription hygiene—rotating URLs, clearing bad caches—keep the subscription maintenance guide in the loop so mixin is not masking an expired remote.
Multiple Subscriptions Without Forking the Whole File
Some readers juggle two commercial providers—perhaps a low-latency group for gaming and a second account for streaming—or separate bundles for different jurisdictions. You can still avoid duplicating megabytes of YAML: keep both proxy-providers in the remote base if your generator supports multiple URLs, or add a second provider stanza through mixin if you control only the local side. Then expose both clusters inside proxy-groups the remote file already defines, or add a small group in mixin that references imported tag names.
The failure mode here is naming collisions. If mixin introduces proxy-groups[0].name: Auto and the remote already defined Auto, merge semantics decide whether you created a duplicate error or silently replaced the group—behavior varies by client validation. Prefer distinctive names for mixin-authored groups (LOCAL-AUTO, LAB-FALLBACK) until you confirm how your toolchain surfaces conflicts. For automated proxy failover semantics on the outbound side, revisit policy groups, url-test, and fallback; mixin edits will not help if the underlying group types are wrong.
GUI “Merge” Panels vs Hand-Edited config.yaml
Modern desktop clients often split concerns: a read-only or periodically refreshed “profile” pane shows the subscription bundle, while a “merge” or “patch” editor writes to a companion file that the runtime combines before starting the core. That is excellent UX as long as you remember which pane owns the truth for a given key. Editing the downloaded profile in place is fragile—your next refresh may stomp changes—while editing the merge pane is durable but sometimes laggy to visualize.
Export the effective YAML from your client when debugging. If the exporter shows your mixin stanza verbatim but not the expected child keys under tun:, you are looking at evidence about merge failure or unsupported fields, not a mystery gremlin. Choosing a transparent client matters here; the cross-platform client comparison calls out which ecosystems expose merge layers honestly versus hiding them behind toggles.
When you need REST or Web UI access for verification, align external-controller and secrets through mixin on machines where the remote profile binds to an unsafe default. The hardening steps in the external-controller and secret guide pair well with a small mixin block that pins listeners to loopback and rotates tokens per device.
profile.store-selected and What Survives a Reload
Mixin adjusts static YAML, but many users also rely on runtime state: last chosen node per group, cached rule-provider snapshots, GEOIP databases on disk. The profile: map is where Meta-class cores declare persistence policies. Setting store-selected: true tells the core to remember manual selections across restarts—convenient when mixin enables dozens of groups but you still pick a daily driver by hand.
Do not confuse that persistence with mixin itself. If you change mixin to rename a proxy group but the state database still references old names, you may see empty selections or surprising fallbacks until caches clear. After structural edits, plan for a one-time “cold restart” with cached state removed when your client documents safe cache paths—exact locations vary by OS packaging.
When Overrides Look Ignored: A Verification Checklist
Walk this list before opening a bug report. Each step isolates a common userland mistake:
- Confirm the running core restarted. Some GUIs hot-reload slices of config; others only re-merge on full stop/start. If in doubt, quit the app entirely.
- Export effective YAML and diff against mixin. If the exporter omits your keys, the merge never happened or the field name is invalid for your build.
- Validate indentation. YAML errors silently swallowed by a GUI editor often mean mixin never parsed—check the diagnostic console.
- Inspect list replacement. If
rules:in effective config shrank unexpectedly, mixin probably replaced the whole array; move additions into prepend channels or remote rule providers. - Check for duplicate keys inside mixin. The last duplicate wins in many parsers, producing “sometimes it sticks” confusion when you edit one copy but read another in the UI.
- Map cross-dependencies. Enabling TUN without matching DNS hijack settings may look like “mixin broke DNS” when the real issue is pipeline alignment—revisit TUN and DNS articles together.
A Worked Example You Can Paste and Trim
The snippet below is not a universal optimum; it demonstrates a home-friendly overlay that tightens listeners, enables TUN with explicit DNS hijack language, and keeps logging verbose during a debugging weekend. Trim secret, ports, and interface hints to match your machine; verify against your client’s documented tun vocabulary before production.
mixin:
mixed-port: 7890
bind-address: '127.0.0.1'
allow-lan: false
log-level: debug
external-controller: '127.0.0.1:9090'
secret: 'rotate-me'
profile:
store-selected: true
tun:
enable: true
stack: mixed
auto-route: true
auto-detect-interface: true
dns-hijack:
- 'any:53'
dns:
enable: true
listen: '127.0.0.1:1053'
ipv6: false
enhanced-mode: fake-ip
fake-ip-range: 198.18.0.1/16
rules:
- 'DOMAIN-SUFFIX,corp.example,DIRECT'
- 'IP-CIDR,10.0.0.0/8,DIRECT'
- 'MATCH,GLOBAL'
Notice the explicit rules: list: on many stacks this replaces the remote rule chain entirely. In real life you might delete that block from mixin until you understand the implications, or limit local edits to prepend-only channels your GUI provides. The example is intentionally provocative to force the question: do you truly want mixin authoring the final MATCH, or should the remote profile retain that responsibility?
Wrap-Up
Clash Meta mixin is the disciplined way to reuse a polished remote profile without surrendering local agency over listeners, tunnels, DNS shape, and environment-specific exceptions. Treat maps as cooperative overlays, treat lists as guilty until proven appendable, export effective YAML when in doubt, and restart deliberately after structural edits. Compared with forking a vendor’s thousand-line file every week, a twenty-line mixin file is easier to audit, safer to commit to git, and dramatically quicker to reason about when something misbehaves on just one network.
Compared with opaque one-click bundles, a transparent Meta-class client plus a small mixin layer trades a few minutes of setup for months of calmer debugging—especially when DNS, TUN, and routing policies interact. → Download Clash for free and experience the difference once your merge workflow matches how you actually move between networks—not just how you import nodes.