Inside the client, a subscription is a local cache of remote data. Every update refetches the remote content and regenerates the config file from it. Nothing you typed into that file takes part in the process, so nothing you typed comes out the other side. You only get burned once; the remaining question is how to route around it.
Your edits belong on top of the subscription, not inside it
Clash Verge Rev splits “what the subscription said” and “what you changed” into two layers. The subscription copy stays read-only and your changes live separately as an extended config. Every time the client builds the effective config it takes the subscription output and lays your layer over it. The subscription can change however it likes; your layer is still there afterwards. Other clients have the same thing under other names — override, mixin, pre-processing — but the shape is identical.
SponsoredWhere does the subscription link come from?Our partner provider gives you 1 GB of high-speed Hong Kong data at signup — import it in one click.Get high-speed nodesTwo kinds of extension: a piece of YAML, a piece of JS
- Merge — a YAML fragment merged into the generated config. Right for fixed content: a handful of rules, a dns block, a changed port.
- Script — JavaScript. The entry function receives the whole config object, you modify it and return it. Right for anything conditional; overkill for anything static.
- The order is fixed: subscription output → Merge → Script → effective config. Script sees the result of Merge, so with both attached, Script has the last word.
The Merge trap: lists are replaced, not appended
Keys of the same name overwrite, which matches intuition. Lists do not. Put a rules key in your merge fragment and the default behaviour is that your handful of lines replaces the subscription's several hundred, so everything except what you wrote is gone. It shows up as most of the internet suddenly going direct, or suddenly going through a node. To add to a list, use the dedicated keys: prepend-rules puts entries at the front, append-rules at the back, and matching prepend and append forms exist for proxy-groups and proxies. Rules are order-sensitive, so your own almost always want prepend.
prepend-rules:
- DOMAIN-SUFFIX,internal.example.com,DIRECT
- PROCESS-NAME,Telegram.exe,PROXY
append-rules:
- DST-PORT,25,REJECT
dns:
enable: true
nameserver:
- 223.5.5.5
What Script can do that Merge cannot
The entry point is a function that takes the parsed config object and returns the new one. That lets you act on conditions instead of hard-coding results: strip out the fake entries whose names carry expiry dates and remaining-traffic counters, put a consistent prefix on every node name, or push everything matching a pattern into one group. Merge cannot express any of that, because you have no idea in advance what the subscription will contain.
function main(config) {
config.proxies = config.proxies.filter(function (p) {
return p.name.indexOf('Expire') === -1;
});
config.rules.unshift('DOMAIN-SUFFIX,example.com,DIRECT');
return config;
}
Do not guess, look at what came out
When an extended config is wrong, the symptoms are unhelpful. Either it fails to load outright, or it loads fine and an entire section has quietly disappeared — half the node list, or a rules list holding nothing but the two lines you wrote. Clients generally offer a way to view the effective config, in a profile's context menu or its detail view, sometimes labelled view and sometimes export. Look at the merged result the moment you change something: confirm your addition is there and the original is still there. Far quicker than reasoning backwards from symptoms.
proxies section. Nodes are the subscription's job, and taking that job over throws away the entire point of automatic updates — the day the provider moves a server, you get to chase it by hand. How to write the rules themselves, and where in the list they have to sit, is a separate subject; this piece only covers keeping them from being erased.