V2Ray Configuration File Structure Explained: What inbounds, outbounds, and routing Do

Break down a minimal V2Ray JSON configuration and learn what each field in inbounds, outbounds, and routing does, plus how the client UI maps to the config file.

Quick Overview

This guide is for users who can import nodes but are not yet comfortable reading core configuration or log fields. By the end, you will know which section handles local listening, remote connections, and traffic routing—and how to follow a tag from request entry to rule match to final outbound.

Start with the big picture: a config file is more than one node

V2Ray 5.x uses JSON to describe how the core runs. A complete client configuration usually includes more than a server address and user ID: it defines local traffic entry points, outbound connections, DNS behavior, log level, and routing rules. The “one node” shown in a graphical client mainly represents a set of server parameters in a proxy outbound, not the complete runtime configuration.

When reading a configuration, set protocol details aside and think of the data flow in three stages: an application sends a request to a local listening port, inbounds receives and identifies it, routing selects a destination based on the domain, IP, port, or protocol, and an outbounds entry sends it onward. Inbounds and outbounds are named with tag, and routing rules refer to those names.

Application requestInbound acceptsSniff domainMatch rulesSelect outboundSend to destination

Top-level fields do not have a required order. A JSON parser will not change the result just because routing appears before outbounds. Array order can matter, however: routing rules are usually checked from top to bottom, while traffic that matches no rule generally goes to the first outbound. When reading a config, check both the tag and the item’s position in its array.

inbounds

Direction
Application to core
Common protocols
SOCKS、HTTP
Key fields
listen、port、tag
Typical ports
10808

Determines which local addresses and ports can pass traffic to the core.

outbounds

Direction
Core to destination
Proxy protocols
VMess、VLESS
Auxiliary outbounds
freedom、blackhole
Identification
tag

Node server details, transport, and TLS parameters are mainly defined here.

routing

Rule type
field
Match target
Domain, IP, port
Result
outboundTag
Evaluation order
Top to bottom

Selects the outbound; it does not establish the remote protocol connection.

dns and log

dns
Resolution strategy
log
Log level
Common level
warning
Troubleshooting level
info

Not every configuration declares these explicitly, but they directly affect name resolution and troubleshooting.

inbounds: where traffic enters from the local machine

inbounds is an array in which each object represents a local entry point. Desktop clients commonly create both SOCKS and HTTP inbounds—for example, SOCKS on 127.0.0.1:10808 and HTTP on 127.0.0.1:10809. Once a browser, command-line tool, or system proxy sends a request to the relevant port, the core can process the connection.

listen sets the listening address. With 127.0.0.1, only local connections are accepted; with 0.0.0.0, every network interface is listened on, which may expose the port to devices on the local network. Unless a LAN proxy is explicitly needed, a loopback address is the safer choice for desktop use. port must be unused by other programs. A conflict commonly produces log messages such as bind or address already in use.

10808
Example SOCKS port
10809
Example HTTP port
127.0.0.1
Listen locally only
53
Standard DNS port

protocol identifies the inbound protocol, not the remote node protocol. A SOCKS inbound can send requests to a VLESS or VMess outbound; the two protocols do not need to match. settings stores parameters specific to that inbound protocol. For a SOCKS inbound, udp: true commonly means that UDP requests are accepted.

sniffing recovers the destination domain from connection contents. An application may resolve a domain to an IP first and then connect to the local proxy; if the core sees only the IP, domain-based routing rules cannot match. With sniffing enabled and destOverride configured, the core can identify domains in applicable HTTP and TLS traffic before passing them to routing.

{
  "tag": "socks-in",
  "listen": "127.0.0.1",
  "port": 10808,
  "protocol": "socks",
  "settings": {
    "auth": "noauth",
    "udp": true
  },
  "sniffing": {
    "enabled": true,
    "destOverride": ["http", "tls"]
  }
}

outbounds: proxy nodes, direct access, and blocked traffic

outbounds is also an array. A proxy node is usually just one entry; the client typically creates a direct outbound and a blocking outbound as well. A proxy outbound connects to a remote service using protocols such as VMess or VLESS; freedom lets the core access the destination directly, while blackhole terminates connections selected by a rule.

A proxy outbound can be understood in two layers. settings describes the protocol identity and server port, such as a VMess address, port, user ID, and security parameters. streamSettings describes the underlying transport and security layer, such as TCP, WebSocket, TLS, or Reality. Even with correct protocol fields, a mismatched transport path, SNI, or security layer will still cause the connection to fail.

VMess + WebSocket + TLS

protocol
vmess
network
ws
security
tls
Remote port
443
Path
/v2ray

User identity goes in settings; the transport path and TLS settings go in streamSettings.

VLESS + TCP + Reality

protocol
vless
network
tcp
security
reality
flow
xtls-rprx-vision
Fingerprint
chrome

Reality parameters must match the server; simply renaming the security field is not enough.

Direct outbound

tag
direct
protocol
freedom
Remote node
Not required
Purpose
Local and direct-access rules

After direct is selected, the local network connects to the destination directly.

Blocking outbound

tag
block
protocol
blackhole
Remote connection
Not established
Purpose
Block selected traffic

When a routing rule refers to block, the request is not sent on to its destination.

An outbound tag is the most important index when troubleshooting a configuration. If a routing rule contains "outboundTag": "direct", return to outbounds and find the object whose tag is direct. If a rule references a nonexistent tag, the core will usually report a configuration error during startup instead of guessing an outbound.

A subscription usually provides node connection parameters, not the complete set of local ports, log levels, and routing rules. After importing a subscription, v2rayN, v2rayNG, or v2flyNG combines the node fields with its own settings and generates the runtime configuration for the core. As a result, the complete JSON generated from the same subscription may differ between clients.

Takeaway: troubleshoot outbound errors layer by layer

For authentication failures, first verify the address, port, and user information in settings. For TLS, Reality, or WebSocket handshake failures, check streamSettings next. Mixing the two layers while editing is the easiest way to end up with a seemingly complete configuration that still times out.

routing: send requests to the right outbound in order

routing.rules is an array of rules. The commonly used field rule can match conditions such as domain, ip, port, network, protocol, and inboundTag. A rule does not forward data itself; it uses outboundTag to specify which outbound should handle the request.

Rule order changes the result. If the first rule sends a particular domain to the proxy and the second sends a broader domain set direct, the first rule wins and matching stops. Put more specific blocking or forced-proxy rules first, followed by broad direct rules and the final fallback.

Match field Match target Typical use Result
domain Full domain, suffix, or domain set Route traffic by site category Send to the specified outboundTag
ip Single IP, CIDR, or IP set Route LAN and target subnets separately Direct, proxy, or block
port Single port or port range Control traffic for a specific service Select the corresponding outbound
network tcp, udp, or both Final fallback rule Cover remaining connections
inboundTag One or more inbound tags Use different outbounds for different local entry points Implement entry-point-based routing

domainStrategy determines when the router resolves a domain to an IP. AsIs prioritizes the original domain and does not actively resolve it for IP rules; IPIfNonMatch checks domain rules first, then resolves the IP and tries IP rules if nothing matches; IPOnDemand triggers resolution earlier when a rule may require an IP. The right choice depends on the rule design—not on choosing the most aggressive option.

If no rule matches, V2Ray typically uses the first outbound. To avoid relying on implicit order, add a final fallback rule covering both TCP and UDP and explicitly set its outboundTag. Reordering outbounds then will not unexpectedly change the direction of default traffic.

{
  "domainStrategy": "IPIfNonMatch",
  "rules": [
    {
      "type": "field",
      "protocol": ["bittorrent"],
      "outboundTag": "block"
    },
    {
      "type": "field",
      "ip": ["geoip:private"],
      "outboundTag": "direct"
    },
    {
      "type": "field",
      "domain": ["geosite:cn"],
      "outboundTag": "direct"
    },
    {
      "type": "field",
      "network": "tcp,udp",
      "outboundTag": "proxy"
    }
  ]
}

Takeaway: start routing troubleshooting with the first rule

First confirm which rule actually matched the destination domain or IP, then inspect the outboundTag referenced by that rule. If the node is reachable but traffic takes the wrong path, the usual causes are rule order, domain sniffing, or DNS results—not a broken proxy protocol.

A readable minimal client configuration

The example below puts logging, one SOCKS inbound, three outbounds, and four routing rules in a single file. The address and user ID are for structure only and cannot be used as a real node. The configuration uses standard JSON: keys and strings require double quotes, trailing commas are not allowed, and comments cannot be inserted directly.

From the data-flow perspective, the application first connects to 127.0.0.1:10808. The core checks routing: BitTorrent traffic goes to block, private addresses and the specified domain set go to direct, and all other TCP and UDP requests go to proxy. proxy then connects to the example server’s port 443 using VMess, WebSocket, and TLS.

{
  "log": {
    "loglevel": "warning"
  },
  "inbounds": [
    {
      "tag": "socks-in",
      "listen": "127.0.0.1",
      "port": 10808,
      "protocol": "socks",
      "settings": {
        "auth": "noauth",
        "udp": true
      },
      "sniffing": {
        "enabled": true,
        "destOverride": ["http", "tls"]
      }
    }
  ],
  "outbounds": [
    {
      "tag": "proxy",
      "protocol": "vmess",
      "settings": {
        "vnext": [
          {
            "address": "server.example.com",
            "port": 443,
            "users": [
              {
                "id": "00000000-0000-4000-8000-000000000000",
                "alterId": 0,
                "security": "auto"
              }
            ]
          }
        ]
      },
      "streamSettings": {
        "network": "ws",
        "security": "tls",
        "tlsSettings": {
          "serverName": "server.example.com"
        },
        "wsSettings": {
          "path": "/v2ray"
        }
      }
    },
    {
      "tag": "direct",
      "protocol": "freedom",
      "settings": {}
    },
    {
      "tag": "block",
      "protocol": "blackhole",
      "settings": {}
    }
  ],
  "routing": {
    "domainStrategy": "IPIfNonMatch",
    "rules": [
      {
        "type": "field",
        "protocol": ["bittorrent"],
        "outboundTag": "block"
      },
      {
        "type": "field",
        "ip": ["geoip:private"],
        "outboundTag": "direct"
      },
      {
        "type": "field",
        "domain": ["geosite:cn"],
        "outboundTag": "direct"
      },
      {
        "type": "field",
        "network": "tcp,udp",
        "outboundTag": "proxy"
      }
    ]
  }
}
  1. First validate the JSON syntax, especially whether double quotes, commas, and square brackets are properly paired.
  2. Then verify that every tag is unique and that each outboundTag referenced by routing actually exists.
  3. Make sure the inbound port is not in use, and point the system proxy or application to the same port.
  4. Verify that the proxy outbound’s protocol, server port, transport, and security layer match as a complete set.
  5. Finally, check rule order and confirm that the fallback rule comes after more specific rules.

How the graphical client maps to core JSON

v2rayN, v2rayNG, and v2flyNG expose common fields as form controls. The address, port, user ID, transport, and security settings on the node editor mainly map to the proxy outbound; the local SOCKS port and LAN access options map to inbounds; routing modes, rule sets, and custom rules map to routing.

In v2rayN, local ports and basic behavior are typically adjusted under Settings → Parameter Settings, while node parameters are edited in the server editor. When the client starts the core, it combines node data, global parameters, and routing settings into a runtime configuration. Direct edits to a temporary core JSON may be overwritten the next time you switch nodes, update a subscription, or restart the core.

v2rayNG and v2flyNG on Android use a similar layered model, but their cores differ: v2rayNG uses the Xray core, while v2flyNG uses the v2fly core. Some advanced fields and defaults differ, so a complete configuration exported by one client cannot be used unchanged as the other client’s UI configuration file.

Why does the UI show one node while the runtime config has three outbounds?

The node corresponds only to the proxy outbound. The client also creates direct and block for direct-access and blocking rules, so the number of outbounds is usually greater than the number of nodes.

Why does the generated JSON revert after a restart?

The generated file is a runtime artifact. Change the source data under Settings → Parameter Settings, in the node editor, or in routing settings, then restart the core to verify the result.

Why didn’t the local port change after importing a subscription?

A subscription mainly provides node connection parameters; the local listening port belongs to the client settings. Check whether the SOCKS port is still 10808 and update the system proxy accordingly.

Why is traffic still using the wrong outbound when the routing rule contains a domain?

First enable applicable domain sniffing, then check domainStrategy, DNS results, and rule order. Temporarily set the log level to info to observe the actual destination and outbound tag.

Troubleshoot startup and routing errors by following the logs

Configuration problems fall into startup and runtime stages. Startup failures usually involve JSON syntax, field types, duplicate ports, or invalid tags; the core may not even start listening on an inbound. Runtime problems are more often related to node parameters, DNS, rule matches, and the destination network.

When troubleshooting, do not change multiple sections at once. Temporarily change loglevel from warning to info, reproduce the issue once, and record the time. Determine whether the inbound is not listening, the wrong outbound was selected, or the proxy outbound failed to connect, then edit the relevant section. Restore warning afterward to reduce routine log volume.

{
  "log": {
    "loglevel": "info"
  }
}

The inbound tag, destination address, and outbound tag in the logs can be linked into a complete path. For example, if a request enters through socks-in, shows a particular domain as its destination, and ultimately selects direct, the node was not involved in that connection. If proxying was expected, inspect routing instead of repeatedly changing VMess or VLESS identity parameters.

Conversely, if the logs already show that the rule selected proxy and a TLS handshake or connection timeout occurs afterward, routing has essentially done its job. Focus next on the proxy outbound’s address, port, SNI, transport path, system time, and reachability of the remote service.

Takeaway: trace the entire path with tags

Use this troubleshooting sequence: “inbound tag → destination domain or IP → matched rule → outbound tag → transport connection.” Each step maps to one configuration section, helping separate port conflicts, routing mistakes, and node handshake failures.

Download v2rayN View Windows, macOS, Android, and Linux clients