Clash Subscription Formats Explained: YAML, Base64 & Universal Format Conversion
How Clash subscription formats differ across clients, when you actually need format conversion, how it works under the hood, and pitfalls when self-hosting a converter.
What's Actually Behind a Subscription Link
A subscription link is essentially an HTTP(S) address that the client polls periodically — the actual configuration data lives in whatever the server returns. Different providers and panels don't return the same format. Three types show up most often: Clash's native YAML structure, a Base64-encoded universal node list, and custom JSON or plain-text formats used by a handful of panels. After fetching a subscription, the client first figures out which type it's dealing with, then parses the node info and routing rules into the local config accordingly. When this step fails, that's usually the root cause of "the subscription imported but nothing works."
You can't tell the format from the URL alone — plenty of subscription links don't end in .yaml or anything similar. What actually matters is the Content-Type response header and the real content of the response body. Client parsers typically try YAML first, fall back to Base64 decoding if that fails, and only throw a format error if neither works. That's also why the same subscription can behave differently across clients — parsers don't all have the same fallback order or format coverage.
YAML Format: Clash's Native Config Structure
Clash and Clash Meta (the mihomo core) both natively read YAML configs. At the top level you'll typically find proxies (the node list), proxy-groups (proxy groups), and rules (routing rules). The upside of this format is that it's complete and readable — group logic and rule-matching order are all right there in the text, so advanced users can open the config file and edit sections directly.
proxies:
- name: "hk-01"
type: ss
server: example.com
port: 443
cipher: aes-256-gcm
password: "your-password"
proxy-groups:
- name: "Auto Select"
type: url-test
proxies: ["hk-01"]
url: "http://www.gstatic.com/generate_204"
interval: 300
rules:
- DOMAIN-SUFFIX,github.com,Auto Select
- MATCH,DIRECT
One thing to watch: YAML is picky about indentation and the space after a colon. A single extra space or a missing colon during manual edits can break parsing for the entire file. If your provider gives you a direct YAML link, you usually don't need to touch this yourself — the client pulls and merges or overwrites the local config automatically. Syntax only matters when you're hand-building nodes or splicing rules yourself.
How Base64 and Universal Formats Stay Compatible
The Base64 format took off because it was compatible with early clients and easy to share online: the server strings each node's info into a protocol://parameters link (starting with ss://, vmess://, trojan://, etc.), joins all the links line by line, then Base64-encodes the whole block into a single unbroken string. After fetching it, the client decodes the Base64, gets back one node per line, parses each line's protocol type and parameters, and builds an internal node list from that.
The upside is broad compatibility — almost every mainstream client (not just Clash-family ones) understands this encoding, so the same subscription can feed multiple apps at once, which is handy for panels serving several client types. The downside is just as clear: universal Base64 format carries no proxy-group or routing-rule structure. Once the client gets the nodes, it can only apply its own built-in default grouping logic, so rule granularity is inherently weaker than a native YAML subscription. In many clients, importing a universal-format subscription just swaps out the nodes against a locally preset static rule template — the routing logic itself never changes.
| Format Type | Typical Content | Rule Info | Compatibility |
|---|---|---|---|
| YAML (Clash native) | Nodes + proxy groups + rules | Complete, customizable | Clash / Clash Meta family clients |
| Base64 universal | Node list only | Relies on client's local template | Virtually all mainstream clients |
| Custom JSON | Varies by panel | Partial grouping logic | Panel-specific companion clients |
When You Actually Need Format Conversion
In most cases, no manual conversion is needed — just paste the subscription link into the client's subscription manager and it'll detect and parse the format automatically. The scenarios where conversion actually matters boil down to a few:
- Your panel only offers a universal Base64 subscription, but you want custom routing rules and multi-layer proxy groups in Clash — in that case you need to convert the node info into YAML structure and add in the
rulesfield yourself. - You've got a pile of loose protocol links lying around (
ss://,vmess://, etc.) and want to merge them into a single client-readable subscription URL for easier management and auto-updates. - You're migrating from another client to a Clash-family client, and the old subscription is in a proprietary format — converting it to YAML is the only way to keep your existing group setup.
The mechanics of conversion aren't complicated: parse the original subscription to recover structured node parameters (server address, port, encryption method, password or key, etc.), then reassemble them according to the target format's syntax. For YAML as the target, the converter also has to generate proxy groups and rules — that part is filled in from preset templates by the conversion script rather than "extracted" from the original subscription, since universal formats simply don't carry that information.
A converted subscription is, in essence, a brand-new generated config — how accurate the node parameters are depends entirely on whether the conversion script fully parses every protocol field. If some nodes fail to connect after conversion, check first whether a required parameter got dropped during conversion before assuming the node itself is bad.
What to Watch for When Self-Hosting a Converter
If you have the setup and the need, you can self-host an open-source subscription converter to turn a universal Base64 subscription into a YAML config with custom rules, then serve a new subscription link for the client to pull. A few things worth keeping in mind when running your own converter:
- Keep the rule templates maintained. The proxy groups and routing rules a converter generates come from local template files — an outdated template means newly added domain categories won't match anything, so it needs regular upkeep.
- Lock down access to the conversion step. A converter typically handles your raw subscription content, so if it's deployed at a publicly reachable address, add an access token or restrict allowed sources to keep your subscription info from leaking to strangers.
- Match the output subscription's refresh rate to the source. Converters are usually triggered on demand or on a schedule that re-pulls the original subscription and regenerates the link — if that interval is too long, the node info the client sees will lag behind what's actually changed on the panel side.
- Cover protocol field parsing thoroughly. Different protocols (Shadowsocks, VMess, Trojan, Hysteria, etc.) have quite different parameter structures — if the conversion script only handles the common fields, nodes with plugin parameters or unusual transport configs are prone to parsing errors.
For most users, if the client already reads the subscription format correctly, there's no need to bring conversion into the picture at all. It's mainly a tool for panel operators or advanced users with specific rule requirements. For everyday use, check first whether your client and subscription format are already compatible before deciding whether conversion is even necessary.