Compare — choosing a core
The three cores cover overlapping feature sets but with very different design philosophies. This page summarizes the differences in a single place so you can pick the right tool and migrate between them.
Feature support at a glance
| Feature | Xray-core | sing-box | mihomo |
|---|---|---|---|
| Config format | JSON | JSON | YAML |
| VLESS | ✓ | ✓ | ✓ |
| VMess | ✓ (AEAD only) | ✓ | ✓ |
| Trojan | ✓ (no flow) | ✓ | ✓ |
| Shadowsocks (incl. 2022) | ✓ | ✓ | ✓ |
| ShadowsocksR | — | ✓ | ✓ |
| Hysteria2 | ✓ (split config) | ✓ | ✓ |
| TUIC | — | ✓ (v5) | ✓ (v4 + v5) |
| WireGuard | outbound | endpoint | outbound |
| Naive | — | ✓ | — |
| AnyTLS | — | ✓ | ✓ |
| SSH | — | ✓ | ✓ |
| Tor | — | ✓ | — |
| HTTP / SOCKS | ✓ | ✓ (incl. mixed) | ✓ (incl. mixed) |
| Dokodemo / port-forward | dedicated | via Direct | dedicated |
| TUN inbound | minimal | full | full |
| Redirect / TProxy | dokodemo + sockopt | dedicated | shortcut + listener |
| TLS / uTLS / REALITY / ECH | ✓ | ✓ | ✓ |
| Routing | JSON rules + balancer | structured rules + actions | compact strings |
| DNS | server URL list | typed servers | URL list + policy map |
| Rule providers | — (built-in geo only) | rule-set | rule-providers |
| Proxy groups | balancer (4 strategies) | selector / urltest | select / url-test / fallback / load-balance |
| Stats / Prometheus | gRPC + metrics | clash_api + v2ray_api | Clash API |
Field-name divergences (the same feature, three names)
VLESS / VMess user list
| Concept | Xray | sing-box | mihomo |
|---|---|---|---|
| User UUID field | clients[].id | users[].uuid | uuid |
| User name field | clients[].email | users[].name | username |
| Per-user flow | clients[].flow | users[].flow | flow |
Shadowsocks cipher
- Xray / sing-box:
method - mihomo:
cipher
Server / port pair
- Xray inbounds:
listen+port - Xray outbounds:
address+port(simplified) orservers[].address+servers[].port - sing-box inbounds:
listen+listen_port - sing-box outbounds:
server+server_port - mihomo:
listen+port(inbound listener) /server+port(outbound)
Skip cert verify
- Xray:
tlsSettings.allowInsecure - sing-box:
tls.insecure - mihomo: per-adapter
skip-cert-verify
uTLS fingerprint
- Xray:
tlsSettings.fingerprint - sing-box:
tls.utls: { enabled, fingerprint } - mihomo: per-adapter
client-fingerprint(or top-levelglobal-client-fingerprint)
Multiplex (mux)
- Xray:
streamSettings.sockopt(limited) - sing-box:
multiplex: { ... }on inbound/outbound - mihomo:
mux-optionon inbound listener (sing-style mux)
Migration cookbook
From Xray VLESS to sing-box VLESS
Xray:
json
{
"outbounds": [{
"protocol": "vless",
"settings": {
"vnext": [{
"address": "example.com",
"port": 443,
"users": [{ "id": "abc...", "flow": "xtls-rprx-vision" }]
}]
},
"streamSettings": {
"security": "reality",
"realitySettings": { "publicKey": "...", "shortId": "...", "serverName": "cdn.com" }
}
}]
}sing-box equivalent:
json
{
"outbounds": [{
"type": "vless",
"server": "example.com",
"server_port": 443,
"uuid": "abc...",
"flow": "xtls-rprx-vision",
"tls": {
"enabled": true,
"server_name": "cdn.com",
"utls": { "enabled": true, "fingerprint": "chrome" },
"reality": { "enabled": true, "public_key": "...", "short_id": "..." }
}
}]
}Key differences:
clients[].id→users[].uuidon inbound; outbound uses flatuuid.streamSettings.realitySettings→tls.realitysub-block.streamSettings.security: "reality"→tls.enabled: trueplustls.reality.enabled: true.- Xray's implicit chrome fingerprint becomes explicit
tls.utls: { enabled, fingerprint }.
From sing-box to mihomo (same VLESS)
yaml
proxies:
- name: vless-reality
type: vless
server: example.com
port: 443
uuid: abc...
flow: xtls-rprx-vision
tls: true
servername: cdn.com
client-fingerprint: chrome
reality-opts:
public-key: ...
short-id: ...Key differences:
- All TLS fields move to the proxy root (
tls,servername,client-fingerprint). No nestedtls:block. reality:becomesreality-opts:.
From Hysteria2 (Xray's split form) to sing-box
Xray splits the config; sing-box keeps everything in one block:
yaml
# Xray (two blocks)
outbounds:
- protocol: hysteria
settings: { version: 2, address: example.com, port: 443 }
streamSettings:
hysteriaSettings: { version: 2, auth: pw, up: 100mbps, down: 300mbps }json
// sing-box (one block, integer Mbps)
{
"type": "hysteria2",
"server": "example.com",
"server_port": 443,
"password": "pw",
"up_mbps": 100,
"down_mbps": 300,
"tls": { "enabled": true }
}Routing rules
Xray (JSON):
json
{ "type": "field", "domain": ["geosite:cn"], "outboundTag": "direct" }sing-box (JSON):
json
{ "rule_set": ["geosite-cn"], "outbound": "direct" }mihomo (string):
GEOSITE,cn,DIRECT