Skip to content

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 ​

FeatureXray-coresing-boxmihomo
Config formatJSONJSONYAML
VLESS✓✓✓
VMess✓ (AEAD only)✓✓
Trojan✓ (no flow)✓✓
Shadowsocks (incl. 2022)✓✓✓
ShadowsocksR——✓
Hysteria2✓ (split config)✓✓
TUIC—✓ (v5)✓ (v4 + v5)
WireGuardoutboundendpointoutbound
Naive—✓—
AnyTLS—✓✓
SSH—✓✓
Tor—✓—
Snell—✓ (v4–v6)✓ (v1–v5)
OpenVPN—endpointoutbound
HTTP / SOCKS✓✓ (incl. mixed)✓ (incl. mixed)
Dokodemo / port-forwarddedicatedvia Directdedicated
TUN inboundminimalfullfull
Redirect / TProxydokodemo + sockoptdedicatedshortcut + listener
TLS / uTLS / REALITY / ECH✓✓✓
RoutingJSON rules + balancerstructured rules + actionscompact strings
DNSserver URL listtyped serversURL list + policy map
Rule providers— (built-in geo only)rule-setrule-providers
Proxy groupsbalancer (4 strategies)selector / urltestselect / url-test / fallback / load-balance
Stats / PrometheusgRPC + metricsclash_api + v2ray_api + api serviceClash API

Field-name divergences (the same feature, three names) ​

VLESS / VMess user list ​

ConceptXraysing-boxmihomo
User UUID fieldclients[].idusers[].uuiduuid
User name fieldclients[].emailusers[].nameusername
Per-user flowclients[].flowusers[].flowflow

Shadowsocks cipher ​

  • Xray / sing-box: method
  • mihomo: cipher

Server / port pair ​

  • Xray inbounds: listen + port
  • Xray outbounds: address + port (simplified) or servers[].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-level global-client-fingerprint)

Multiplex (mux) ​

  • Xray: streamSettings.sockopt (limited)
  • sing-box: multiplex: { ... } on inbound/outbound
  • mihomo: mux-option on 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[].uuid on inbound; outbound uses flat uuid.
  • streamSettings.realitySettings → tls.reality sub-block.
  • streamSettings.security: "reality" → tls.enabled: true plus tls.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 nested tls: block.
  • reality: becomes reality-opts:.

From Hysteria2 (Xray's split form) to sing-box ​

Xray splits the config; sing-box keeps everything in one block:

yaml
# Xray (split across blocks)
outbounds:
  - protocol: hysteria
    settings: { version: 2, address: example.com, port: 443 }
    streamSettings:
      hysteriaSettings: { version: 2, auth: pw }
      finalmask:
        quicParams: { brutalUp: 100mbps, brutalDown: 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

Core Tutorial by Argsment