Advanced 2026-04-22 · ~21 min read

Clash Meta Mixin Overrides: Inject Custom Rules Without Losing Them on Subscription Updates

If your provider only gives a remote subscription URL, it is tempting to open the downloaded YAML and append ad-blocking lists, GEOIP DIRECT rows, or a custom proxy-groups tree by hand. That works until the next refresh: many clients overwrite the cached remote body, silently discarding inline edits. Clash Meta (the Mihomo core) solves this with a mixin layer and disciplined profile layout—local fragments merge after the base profile loads, so subscription updates refresh nodes while your overrides stay in a separate file or GUI field the client never replaces wholesale.

Why “editing the subscription file” is the wrong layer

Commercial dashboards usually emit a complete Clash document: proxies, groups, rules, sometimes rule-providers URLs, and even DNS snippets. When your GUI stores that document behind a single “profile from URL,” the update pipeline is roughly: download → validate → write cache → reload core. Any bytes you added between download and write live in the same artifact the updater is allowed to replace. That is not malice; it is how reproducible imports stay reproducible.

The fix is architectural. You want the remote artifact to remain a pure upstream snapshot while your personal policy lives in a second source the merge pipeline always reapplies. In Mihomo terminology, that second source is commonly the mixin configuration: a structured YAML fragment the core deep-merges on top of whatever came from the profile URL, local file bundle, or provider composition your client assembled. GUI forks expose the same idea under names like “Merge,” “Patch,” “Extend,” or “Script,” but the durable mental model is identical: base from the airport, overlay from you.

Do not rely on “I will remember to paste again”

Manual re-paste fails under auto-update schedules, silent background refreshes, and multi-device sync. Treat anything you care about as code that belongs in mixin or an equivalent client override slot—not inside the remote cache file.

What mixin does in Clash Meta / Mihomo

Mihomo loads your primary profile first, then applies mixin as an overlay. For mapping-style sections—think dns, sniffer, nested maps inside clash-for-android style tuning—the overlay typically performs a recursive merge: keys you specify in mixin win or extend nested maps. For list-like sections such as rules, behavior deserves extra caution: depending on client packaging and version, list merging may append mixin entries, replace an entire list, or expose explicit prepend/append hooks in the GUI. When in doubt, do not guess from memory; inspect the effective runtime config your controller exposes after reload.

Practical takeaway: keep mixin small and declarative. Prefer referencing stable upstream constructs by name—your provider’s main selection group, their auto url-test group—rather than cloning fifty proxy definitions you must diff every week. Add rule-providers for blocklists and domestic lists in mixin, wire them with RULE-SET rows, and leave the bulky node list to the remote provider file where it belongs. Our rule-providers download path guide walks cache directories and refresh intervals; combine that hygiene with mixin so both remote lists and your overlays stay predictable across reboots.

Merge order mantra

Think remote base → local mixin → (optional) GUI-only patches. Subscription refresh touches the base; mixin survives because it is stored and merged from a different path than the overwritten cache blob.

Designing the profile so the airport YAML stays pristine

Two common patterns cover most readers who “only have a subscription link.”

Pattern A — Full remote profile URL + mixin overlay (simplest mentally). You still point the client at the provider’s HTTPS YAML, accept that the downloaded file is volatile, and move every personal tweak into mixin or the client’s merge field. This is the fastest migration if you already imported the link and just need durability for edits.

Pattern B — Split nodes and rules (most maintainable long term). Use Subconverter (or another converter) so the subscription URL becomes a proxy-providers HTTP source or a trimmed artifact that only carries proxies, while your local profile (plus mixin) owns proxy-groups, rules, and rule-providers. Pattern B costs more setup time but shrinks surprise collisions: you are no longer fighting the provider’s opinionated rules array every time they rename a group.

Either pattern honors the user constraint “do not edit the airport YAML body” in the operational sense: you never rely on mutating their canonical text on disk. Pattern A respects their bytes literally; Pattern B respects their intent while isolating structure. Pick A for speed, B when you maintain a large personal ruleset or multiple providers.

Step-by-step: add mixin rules that survive refresh

Step 1 — Inventory names you must reference

Open the merged profile (or remote YAML in a browser) and write down the exact proxy-groups names your rules already target—examples might be 🔰 Proxy or ♻️ Auto. Your mixin rules must spell those names identically; otherwise connections fall through to DIRECT or MATCH in ways that look like “Clash broke.”

Step 2 — Create a dedicated mixin fragment

In headless setups this is often ~/.config/mihomo/mixin.yaml referenced from the main file; GUI clients may expose an editor that writes the same structure behind the scenes. Start with one rule-providers entry for a domestic or adblock list and two or three RULE-SET lines—prove the pipeline before you import thousands of lines.

Step 3 — Control precedence inside rules

Place high-confidence domestic and LAN bypass rows above broad GEOIP or provider MATCH rules. If mixin appends by default in your build, use the client’s prepend mode (if available) or relocate provider rules via Pattern B so your domestic directives still win.

Step 4 — Reload and diff

Trigger a subscription update intentionally, then fetch the runtime config from the external controller or export from the GUI. Confirm mixin-added providers still appear and that critical RULE-SET lines exist in the effective list.

YAML sketches: adblock list + domestic DIRECT

The following snippets are illustrative; replace provider URLs, paths, and policy group names with values that match your merged profile. Comments are omitted in real YAML—here they only clarify intent.

# mixin.yaml (illustrative) — merge on top of remote profile
rule-providers:
  ads:
    type: http
    behavior: domain
    format: yaml
    url: "https://example.com/rules/ads.yaml"
    path: ./ruleset/ads.yaml
    interval: 86400
  cn:
    type: http
    behavior: classical
    format: yaml
    url: "https://example.com/rules/cn.yaml"
    path: ./ruleset/cn.yaml
    interval: 86400

rules:
  - RULE-SET,ads,REJECT
  - RULE-SET,cn,DIRECT

If you also need a custom policy group that bundles several provider groups for a work VPN, define that group in mixin alongside rule-providers, then reference the new group name from added rules. When the remote profile already declares a conflicting group name, rename yours rather than expecting silent merges—duplicate map keys usually mean last writer wins, which is painful to debug under subscription churn.

For automatic selection among nodes, see the Clash Meta url-test and fallback guide; mixin is where you add the extra proxy-groups entry without touching the downloaded provider YAML.

Merge semantics at a glance

Section Typical merge feel What to verify after refresh
proxy-providers / remote cache Re-fetched; node names may change if provider reorders Rules still reference surviving group and node names
mixin maps (dns, sniffer) Recursive overlay on keys you set DNS server list matches your expectations
rules lists Implementation-specific; treat as high risk Export merged rules and read order top to bottom
rule-providers you own Declared in mixin survive independently of airport body Files under path exist and intervals succeed

Verification that survived a refresh

Assume nothing after the first successful load. Build a tiny checklist each time you change providers or bump client versions.

  1. Before refresh: query /configs (or your GUI’s equivalent) and save the effective rules tail around your custom RULE-SET lines.
  2. Trigger refresh: use the client button that re-downloads subscriptions—same code path as scheduled updates.
  3. After refresh: re-query the runtime config. Mixin-backed providers and rules should still exist; only upstream proxy lists should move.
  4. Traffic spot-check: hit a domain you expect in the ads list and confirm it returns REJECT in the log; hit a mainland site that should bypass and confirm DIRECT.

If logs show your domestic rows disappeared while mixin file on disk is unchanged, you are probably editing the wrong layer—double-check that the client actually enables mixin merge for the active profile, not merely stores an unused file beside it.

How GUI clients surface the same idea

Clash Verge–class applications usually expose Profile settings separate from Merge / Mixin editors. On macOS, complete baseline permissions before debugging merge issues—follow Clash Verge Rev on macOS. On Windows, if you are migrating from older Clash for Windows workflows, map “Parsers” mental models to “post-merge transforms,” but prefer native Mihomo mixin when available because it is closer to what the core documents.

Regardless of skin, the invariant is: the field that stores your personal YAML must not be the same file the subscription updater truncates. If your UI only offers one text area tied to the remote URL, switch to a client that supports split sources or move to Pattern B with Subconverter output you host or fetch.

Pitfalls that look like “mixin stopped working”

  • Name drift: the provider renames proxy-groups; your mixin rules still point at the old label.
  • Path collisions: mixin and remote both set the same rule-providers.foo.path; refresh downloads into a path your mixin thought it owned.
  • Over-broad REJECT: aggressive ad lists break login flows; isolate failures by disabling one RULE-SET at a time.
  • DNS interactions: domestic IP rules behave differently under fake-ip; pair this article with the DNS and fake-ip walkthrough when domestic DIRECT looks correct yet browsers stall.

FAQ

Is mixin the same as “parsers” in older clients?

Conceptually similar—both mutate config after fetch—but parsers were often regex transforms tied to legacy stacks. Mihomo mixin is structured YAML merge. Prefer mixin when your client supports it; fall back to documented parser hooks only when required.

Yes with Pattern A: keep the link as-is, never hand-edit the cached download, and place all personal material in mixin or GUI merge fields. Pattern B remains cleaner if you outgrow that.

My domestic DIRECT rules never run

Check merged order: another RULE-SET or GEOIP row may sit above them. Export the effective list and read top-down exactly as the core evaluates it.

Maintenance checklist

  1. Remote subscription URL points to provider YAML you do not manually edit.
  2. Personal rules, lists, and extra groups live in mixin or equivalent.
  3. Provider group names referenced by mixin rules are tracked when the airport updates.
  4. After each provider change, run the refresh → export → spot-check trio.
  5. Back up mixin separately (git or notes) so reinstalling the client does not wipe your only copy.

Keep overrides under version control

Once mixin separates your intent from the airport’s volatile body, treat it like source code: small commits, meaningful filenames, and occasional diffs when providers rename groups. Clash becomes boring in the best way—subscription updates refresh nodes, your policy stays yours.

Download Clash for free and experience the difference

Own your rules layer

Use Clash Meta mixin so subscription refresh never deletes ad-block, domestic DIRECT, or custom groups again.

Download Clash