Routing — sing-box
sing-box's route block holds rules, rule-sets, and a handful of default-interface / process-lookup toggles. Rules are polymorphic (default + logical) and carry an explicit action selecting one of seven behaviors.
Top-level options
| Field | Type | Default | Allowed values | Description |
|---|---|---|---|---|
geoip | *GeoIPOptions | (legacy) | GeoIPOptions | Legacy GeoIP database location and download settings. Deprecated in favor of rule-sets. |
geosite | *GeositeOptions | (legacy) | GeositeOptions | Legacy GeoSite database. Deprecated in favor of rule-sets. |
rules | []Rule | [] | [Rule] | Routing rules, evaluated in order. |
rule_set | []RuleSet | [] | [RuleSet] | Named rule-sets — referenced from rules via `rule_set` match keys. Three types: `inline`, `local`, `remote`. |
final | string | (unset) | <outbound tag> | Default outbound when no rule matches. When unset, the first outbound in `outbounds` is used. |
find_process | bool | false | true | false | Look up the originating process for every connection. Required by `process_name` / `process_path` rules. |
auto_detect_interface | bool | false | true | false | Auto-discover the system's default outbound interface — used by Direct outbounds without `bind_interface`. |
override_android_vpn | bool | false | true | false | Android only — bypass the system VPN service for outbound dials. |
default_interface | string | (auto) | <interface> | Override the default outbound interface. Overrides `auto_detect_interface`. |
default_mark | FwMark | 0 | <uint32> | Linux SO_MARK applied to outbound sockets. |
default_domain_resolver | *DomainResolveOptions | (none) | DomainResolveOptions | Default resolver for destination domains when no rule specifies one. |
default_network_strategy | *NetworkStrategy | (unset) | NetworkStrategy | Default network-strategy used by Happy-Eyeballs / cellular-vs-wifi dial races. |
default_network_type | badoption.Listable[InterfaceType] | [] | <InterfaceType> | Preferred network types for the default outbound. |
default_fallback_network_type | badoption.Listable[InterfaceType] | [] | <InterfaceType> | Fallback network types when the preferred one fails. |
default_fallback_delay | badoption.Duration | 0 | <duration> | Delay before switching to a fallback network. |
Source: option/route.go:5-21 · pinned at v1.13.11 (553cfa1)
Rules
Each entry in rules[] is a polymorphic Rule object. The type field decides the shape:
type: "default"(or omitted) — flatRawDefaultRulewith match fields + aRuleAction.type: "logical"— boolean combinator over nested rules.
Default rule — match fields
RawDefaultRule has 41 fields, all optional and AND-combined when multiple are set. The most-used:
| Field | Type | Description |
|---|---|---|
inbound | []string | Match by inbound tag. |
network | []string | tcp, udp, or tcp,udp. |
protocol | []string | Sniffed application protocol. |
domain / domain_suffix / domain_keyword / domain_regex | []string | Domain matchers. |
geosite | []string | GeoSite category — read from rule-set in modern configs. |
geoip / source_geoip | []string | GeoIP category. |
ip_cidr / source_ip_cidr | []string | CIDR match. |
ip_is_private / source_ip_is_private | bool | Match RFC1918 / link-local / loopback. |
port / source_port | []uint16 | Discrete-port match. |
port_range / source_port_range | []string | Port-range match (80:90, 1024:, …). |
process_name / process_path / process_path_regex | []string | Process match (needs find_process: true). |
package_name | []string | Android package name (UID resolved via the system API). |
user / user_id | []string / []int32 | Local user / UID. |
clash_mode | string | Match only when the runtime mode (controlled via the Clash API) matches this string. |
wifi_ssid / wifi_bssid | []string | Wifi-aware routing (mobile-only). |
network_is_expensive / network_is_constrained | bool | iOS/macOS network-type flags. |
rule_set | []string | Match if any of the named rule-sets matches. |
invert | bool | Invert the entire rule's match result. |
Logical rule
{
"type": "logical",
"mode": "and",
"rules": [ <Rule>, <Rule>, … ],
"invert": false,
"action": "..."
}mode is and (default) or or. Nested rules can themselves be logical.
Rule action
Every rule carries an action that decides what happens on match. Eight action values:
| Action | Meaning |
|---|---|
route (default) | Send to outbound. Extra fields: override_address, override_port, network_strategy, udp_*, tls_fragment*. |
route-options | Apply route options to subsequent matching without leaving the rule chain. |
direct | Direct dial — bypass outbounds entirely (uses default_interface etc.). |
bypass | Same shape as route, deliberately distinct for logging. |
reject | Drop the connection. With method: "drop" or method: "default". |
hijack-dns | Hijack the connection as if it were DNS, routing to the DNS engine. |
sniff | Run protocol sniffing on the connection. |
resolve | Resolve the destination domain via the named DNS server before further rules run. |
Rule-sets
| Field | Type | Default | Allowed values | Description |
|---|---|---|---|---|
type | string | inline | inline | local | remote | Where the rule set lives. `inline` holds the rules right in this config; `local` reads from a file path; `remote` downloads from a URL. |
tag | string | (required) | <string> | Reference name used by rules' `rule_set` match key. |
format | string | (inferred) | source | binary | File format. `source` is JSON; `binary` is the compiled `.srs` format. Inferred from the file extension when unset. |
Source: option/rule_set.go:20-27 · pinned at v1.13.11 (553cfa1)
Local rule-set
{ "type": "local", "tag": "cn", "format": "binary", "path": "geosite-cn.srs" }Remote rule-set
{
"type": "remote",
"tag": "cn",
"format": "binary",
"url": "https://example.com/geosite-cn.srs",
"download_detour": "direct",
"update_interval": "168h"
}Inline rule-set
{
"type": "inline",
"tag": "block",
"rules": [
{ "domain_keyword": ["ads", "tracker"] }
]
}The inline form's rules are HeadlessRule — structurally identical to routing rules but without the action field (the action is whatever the referencing rule does).
Examples
CN-direct + everything else through proxy:
{
"route": {
"rule_set": [
{ "type": "remote", "tag": "geoip-cn", "format": "binary",
"url": "https://github.com/SagerNet/sing-geoip/raw/rule-set/geoip-cn.srs" },
{ "type": "remote", "tag": "geosite-cn", "format": "binary",
"url": "https://github.com/SagerNet/sing-geosite/raw/rule-set/geosite-cn.srs" }
],
"rules": [
{ "ip_is_private": true, "outbound": "direct" },
{ "rule_set": ["geoip-cn", "geosite-cn"], "outbound": "direct" },
{ "action": "sniff" },
{ "protocol": "dns", "action": "hijack-dns" }
],
"final": "proxy",
"find_process": false,
"auto_detect_interface": true
}
}Reject ads with an inline rule-set:
{
"route": {
"rule_set": [
{
"type": "inline",
"tag": "ads",
"rules": [
{ "domain_keyword": ["doubleclick", "googlesyndication"] }
]
}
],
"rules": [
{ "rule_set": "ads", "action": "reject" }
]
}
}Logical OR rule:
{
"type": "logical",
"mode": "or",
"rules": [
{ "domain_suffix": [".onion"] },
{ "geoip": ["tor-exit"] }
],
"outbound": "tor"
}Notes
geoipandgeositetop-level options are legacy. The modern workflow is to load equivalent data viarule_set(remote.srsfiles) and reference it through the rule'srule_setmatch field.rule_set_ip_cidr_match_source(snake_case in the struct) controls whether a rule-set's IP-CIDR rules match source or destination. The older spellingrule_set_ipcidr_match_sourceis deprecated.- The
sniffandresolverule actions are typically used at the head of the rule list to ensure later rules see useful metadata. The DNS engine relies onhijack-dnsto capture DNS queries the routing engine wants to handle. clash_modeonly takes effect if the Clash API is enabled — that's where the mode comes from.
Cross-core notes
- Xray-core uses a single polymorphic rule shape with camelCase field names and a much smaller match-key set. There is no
actionenum — every rule routes to anoutboundTagorbalancerTag. See Routing — Xray-core. - mihomo uses compact one-line string rules (
DOMAIN-SUFFIX,example.com,proxy) and a separaterule-providers:mechanism for remote rule lists. See Routing — mihomo.
Source: option/route.go:5-21 · v1.13.11 (553cfa1)
