Know the difference between the client, core, and subscription config

A client that supports “Clash configs” does not necessarily support every Clash.Meta or mihomo field. The client handles the interface, subscription management, system proxy toggle, and service installation. The core listens on ports, resolves domains, matches rules, and establishes proxy connections. A subscription provides nodes or a complete config. These are separate layers with separate update cycles. If a subscription imports successfully but nodes won’t start, the core may lack the required capabilities—the import button may be working just fine.

For example, a graphical client may still use the Clash brand while running mihomo under the hood. Conversely, an older client that can import YAML may still bundle an early-generation core. To check compatibility, start by identifying the core and its version, then check the protocols and feature fields in the config. Don’t rely on the app’s name alone.

  • Client version: Usually listed under Settings → About. This identifies the version of the interface and service components.
  • Core version: Look in the client’s core information or at the start of its runtime log. To run the binary directly, use mihomo -v.
  • Active config: Check the client’s runtime config preview or the config path shown in its startup log. The original subscription may not match the file that actually gets loaded.

How the original Clash, Clash.Meta, and mihomo evolved

The original Clash had both open-source and Premium versions

The original Clash ecosystem included an open-source core and a Premium branch. They don’t share one universal feature set: capabilities such as TUN and rule providers were part of Premium’s feature scope. Older guides that say “Clash supports TUN” without naming the branch can leave open-source users searching for features their version doesn’t have.

After public development of the original Clash projects stopped in 2023, older binaries could still run on existing systems. That doesn’t mean they can recognize protocols or config options added later. Whether a new config loads depends on what the specific binary actually implements.

Clash.Meta is a fork; mihomo is its later name

Clash.Meta extended Clash with additional protocol, DNS, and routing capabilities. The project was later renamed mihomo. Clash.Meta and mihomo are therefore not two entirely separate config formats that require line-by-line conversion. Older guides, subscription buttons, and filenames may still say Meta while referring to configs for mihomo.

However, being part of the same development lineage doesn’t mean every historical version has the same features. Early Meta binaries may not support newer mihomo options. If a field triggers an error, check the documentation and release notes for your specific version rather than assuming that every Meta build supports it.

ProjectPrimary roleWhat to check when migrating
Original open-source ClashBasic proxies, groups, and rule-based routingDon’t assume support for Premium or Meta extensions
Clash PremiumExtension branch of the original Clash ecosystemFeatures such as script mode don’t map directly to equivalent mihomo capabilities
Clash.MetaBranch with expanded protocol and routing supportThe name remains widely used; specific features depend on the version
mihomoLater project name for MetaCheck new fields, how the client manages the core, and the active runtime config

Practical differences in protocols, rules, and TUN

Node protocol support determines whether a subscription will actually work

Common protocols in original Clash configs include Shadowsocks, VMess, Trojan, SOCKS5, and HTTP. mihomo adds protocols such as VLESS, Hysteria2, and TUIC, but each protocol’s transport, authentication parameters, and specific options may require a particular version. “Supports this protocol” doesn’t necessarily mean “supports every parameter used by every implementation.”

An older core usually can’t load a node with an unrecognized proxy type such as type: hysteria2. Some clients filter out unsupported nodes during conversion or import. If an updated subscription suddenly goes from 20 nodes to none, check the import log and protocol types first, then check whether the service has expired. There’s no need to change DNS right away.

Basic rules often carry over; check support for extensions

Basic rules such as DOMAIN, DOMAIN-SUFFIX, IP-CIDR, and MATCH are generally compatible. More complex logical rules, process matching, and rule-set formats require checks for core support, operating system capabilities, and data-file availability. Rules are still generally evaluated from top to bottom. Putting the catch-all MATCH rule first makes the rules below it ineffective.

Here’s a standalone rule snippet, not a complete config. It assumes your existing config has a proxy group named “Proxy Select.” The name must match exactly, or the reference will fail even if the YAML is valid.

rules:
  - DOMAIN-SUFFIX,example.com,Proxy Select
  - IP-CIDR,192.168.0.0/16,DIRECT,no-resolve
  - MATCH,Proxy Select

no-resolve means this IP rule won’t trigger a DNS lookup for a domain. It does not disable DNS across the core. 192.168.0.0/16 covers just one private network range, so this snippet is not a complete list of LAN bypass rules.

TUN is a traffic interception method, not a proxy protocol

The system proxy usually affects only apps that honor the system proxy settings. TUN routes traffic through a virtual network interface, covering more apps but requiring the right permissions, routes, and DNS setup. Both original Clash Premium and mihomo may support TUN, so a TUN toggle in the interface doesn’t tell you which core is running.

When migrating, don’t assume the old client’s virtual adapter, background service, or routes are required by the new client. Exit the old client and disable its traffic interception first, then let the new client install or enable its own service. Running two TUN setups at once can cause default-route conflicts, DNS loops, or LAN connectivity issues.

Migrating an old config to mihomo: what to keep and what to recheck

Don’t paste in the entire old config and turn on every feature at once. Back it up, then establish a minimal working baseline: connect to a node, select a proxy group, and verify rule matches. Add enhanced DNS and TUN last. That way, each step narrows down the possible cause of a problem.

Field or contentRecommendationWhat to check
proxies、proxy-groupsKeep the basic structureProtocol options are valid and proxy group references exist
rulesKeep the order, then verify each itemThe target policy exists and the catch-all rule is last
rule-providersCheck the source and formatbehavior matches the actual rule content
dns、tunRecheck for the new environmentNo conflicts with ports, network ranges, permissions, or routes
scriptDon’t copy it over as-isRewrite Premium script-based routing using supported rule logic
external-controller、secretCheck how the client manages trafficNo conflict on the controller port; don’t expose the access key in the config

Ports and local paths are especially easy to overlook

For example, the old config uses mixed-port: 7890 and the new client also listens on 7890. If the old process is still running, the port may already be in use. If the new client switches to 7897 but your terminal’s proxy environment variables still point to 127.0.0.1:7890, terminal requests will keep going to the old port. These numbers are common examples, not fixed defaults for every client.

Relative path values in rule and proxy providers are usually interpreted based on the core’s working directory. Moving the YAML file to another directory doesn’t guarantee that its cached files move with it. Have the new client refresh the providers and check the log to confirm the files were written successfully. Don’t rely only on old node names still showing in the interface.

Subscription updates can overwrite your changes

Some clients rebuild the config when updating a subscription, overwriting manual changes to dns or rules. Use the client’s supported override, merge, or extension config features where possible, then check the final runtime config. Whether merged rules are appended, replaced, or prepended depends on the client. You can’t infer their final order from the override file alone.

DNS and fake-ip: recheck the resolution path during migration

fake-ip assigns a virtual address to a domain, then lets the core associate that address with the domain when a connection is made. It’s not a proxy protocol, and it doesn’t guarantee that every DNS request goes through a specific resolver. System DNS, browser Secure DNS, in-app resolvers, and the scope of DNS interception in TUN all affect the final path.

This is a mihomo DNS config snippet that needs to be merged into an existing config. It listens on local port 1053 to avoid taking over the commonly used 53 port directly. But enabling a listener alone won’t make the operating system send DNS queries to it.

dns:
  enable: true
  listen: 127.0.0.1:1053
  enhanced-mode: fake-ip
  fake-ip-range: 198.18.0.1/16
  nameserver:
    - https://1.1.1.1/dns-query
  nameserver-policy:
    "+.example.com":
      - https://1.1.1.1/dns-query
  • Virtual IP range: 198.18.0.1/16 is in the address space reserved for testing. Resolve any conflicts first if your local test network already uses this range.
  • Per-domain resolution: nameserver-policy assigns a resolver to matching domains. It does not force connections to those domains through a particular proxy node.
  • Encrypted DNS: DoH protects the corresponding DNS requests in transit, but you still need to check whether the endpoint is reachable and how requests are routed.
  • Address mapping: After changing fake-ip settings, the system or browser may still have old addresses cached. Flush the cache or restart the test app, then check a new connection.

To have TUN intercept DNS, check dns-hijack in your existing TUN config. Common entries include any:53 and tcp://any:53, covering ordinary DNS over UDP and TCP respectively. The actual interception behavior also depends on the platform and routing implementation. DoH sent directly over HTTPS by an app doesn’t use regular DNS on port 53, so don’t expect this interception to rewrite it automatically.

Validate a migrated config: from syntax checks to TUN

Step 1: Check whether the config loads

If running the core directly, start with the command below. On Windows, replace the program name with the local mihomo.exe and run it from the directory containing the config file. With a graphical client, use its config-check feature first to avoid starting another process that could compete for ports already in use.

mihomo -v
mihomo -t -f ./config.yaml

A successful check only means the config meets the requirements for that load test. It doesn’t mean the node’s server is reachable or that every rule behaves as expected. If an error points to a specific line, check the indentation, colon, and list marker on the line above as well. Tabs for YAML indentation and duplicate top-level keys can both cause subtle problems.

Step 2: Test the proxy exit with just one node

  1. Exit the old client, temporarily turn off TUN in the new client, switch to rule mode, and select a known working node.
  2. Confirm the active mixed port. If the config uses 7890, use the command below to send a test request through that port explicitly.
  3. Check the connection log for the destination domain, matched rule, and selected node. Once the explicit proxy works, enable the system proxy to test regular apps.
  4. Enable TUN last. Test a browser, a terminal, and an app that ignores the system proxy, and make sure LAN access still works.
curl --proxy http://127.0.0.1:7890 --connect-timeout 10 --max-time 20 -I https://example.com

The 10-second connection timeout and 20-second total timeout control how long the test waits; they aren’t speed measurements. If the request can’t connect to the local port, check that something is listening. If the log shows a proxy handshake error, check node authentication, transport settings, or the connection instead of changing the local port again.

Step 3: Verify subscription updates and rollback

Manually update the subscription and rule providers once, then confirm that custom rules, DNS overrides, and proxy group selections are still there. Save a backup of the new client’s active config and keep an offline copy of the old one. To roll back, stop the new client from intercepting traffic first, then restore the old setup. This avoids both clients changing system proxy settings and routes at the same time.

Choosing a core: base the decision on config needs and maintenance status

If you want to keep using your existing Clash-style subscription and need newer protocols, rules, and DNS features, choose a client that explicitly includes mihomo and lets you check the core version and runtime logs. If your old config came from Premium, focus on script logic, providers, TUN, and DNS during migration—not just renaming the executable.

  • For basic routing: Get nodes, proxy groups, and basic rules working reliably first. There’s no need to enable every option just because it’s available.
  • For newer protocols: Check the exact core version and protocol fields. Prefer a config that the service provider explicitly says is compatible with Meta or mihomo.
  • For full-device traffic routing: Check platform permissions, the TUN service, and the DNS path. Test in this order: explicit proxy → system proxy → TUN.
  • For long-term maintenance: Keep an eye on both client and core updates. An interface update isn’t a core update; recheck key config settings after upgrading.

The relationship between the names Clash.Meta and mihomo is just the starting point. What actually determines whether a config can be migrated is the running core version, the active config, and the local ports, permissions, and DNS path. Keep track of each one so you know which layer to troubleshoot when something goes wrong.