# XTLS-Vision vs XTLS-Reality in Xray-core: Architecture, Configuration, and Use Cases

> Compare XTLS-Vision vs XTLS-Reality in Xray-core. Understand their architecture, configuration, and use cases to enhance your traffic obfuscation and security.

- Repository: [Project X Community, Not Porn-jet X Hub/Xray-core](https://github.com/XTLS/Xray-core)
- Tags: deep-dive
- Published: 2026-04-21

---

**XTLS-Vision is a VLESS protocol flow that adds post-handshake traffic obfuscation on top of standard TLS, while XTLS-Reality is a transport-layer security replacement that substitutes the entire TLS handshake with a fingerprint-mimicking protocol.**

Both modes serve to evade deep packet inspection (DPI), but they operate at fundamentally different layers of the Xray-core network stack. Understanding their architectural differences is essential for selecting the right protection strategy for your proxy deployment.

## Where Each Mode Lives in the Stack

### XTLS-Vision: Application-Layer Flow

XTLS-Vision operates as a **VLESS flow** (`xtls-rprx-vision`), configured per-user rather than per-transport. The mode is activated by setting `Flow: vless.XRV` in a VLESS account configuration.

In [`proxy/vless/vless.go`](https://github.com/XTLS/Xray-core/blob/main/proxy/vless/vless.go), the flow constant is defined:

```go
const (
    XRV = "xtls-rprx-vision"
    // ... other flow constants
)

```

The actual traffic manipulation happens in [`proxy/proxy.go`](https://github.com/XTLS/Xray-core/blob/main/proxy/proxy.go) through `VisionReader` and `VisionWriter`. These wrappers:

- Add randomized padding to TLS records
- Monitor handshake completion via `TrafficState`
- Switch to **raw copy mode** (zero-copy) once the TLS handshake finishes

The VLESS inbound handler in [`proxy/vless/inbound/inbound.go`](https://github.com/XTLS/Xray-core/blob/main/proxy/vless/inbound/inbound.go) (around line 615) and outbound handler in [`proxy/vless/outbound/outbound.go`](https://github.com/XTLS/Xray-core/blob/main/proxy/vless/outbound/outbound.go) (around line 392) inject these wrappers into the connection pipeline.

### XTLS-Reality: Transport-Layer Replacement

XTLS-Reality replaces TLS entirely at the **transport security layer**. It is activated by setting `SecurityType` to `reality.Config` in `StreamSettings`, making it applicable to any proxy protocol (VLESS, Trojan, etc.).

The configuration structure is defined in [`transport/internet/reality/config.pb.go`](https://github.com/XTLS/Xray-core/blob/main/transport/internet/reality/config.pb.go) as a protobuf message:

```go
type Config struct {
    Show        bool
    Fingerprint string
    ServerName  string
    PublicKey   []byte
    PrivateKey  []byte
    ShortId     []byte
    ShortIds    [][]byte
    Type        string
    Dest        string
    // ... additional fields
}

```

Core handshake logic resides in [`transport/internet/reality/reality.go`](https://github.com/XTLS/Xray-core/blob/main/transport/internet/reality/reality.go), implementing:

- **uTLS fingerprinting** to mimic popular browser TLS handshakes
- **X25519-ML-KEM** for key exchange
- Optional **ML-DSA-65** certificate verification
- **Short ID** derivation for server authentication

The TCP transport layer integrates Reality in [`transport/internet/tcp/hub.go`](https://github.com/XTLS/Xray-core/blob/main/transport/internet/tcp/hub.go) (server) and [`transport/internet/tcp/dialer.go`](https://github.com/XTLS/Xray-core/blob/main/transport/internet/tcp/dialer.go) (client), which check `SecurityType` and wrap connections with Reality's `Conn` type.

## Configuration Comparison

### Enabling XTLS-Vision

Vision requires VLESS specifically and is configured per-user:

```go
// VLESS inbound user with Vision flow
user := &protocol.User{
    Account: serial.ToTypedMessage(&vless.Account{
        Id:   "YOUR-UUID-HERE",
        Flow: vless.XRV,  // "xtls-rprx-vision"
    }),
}

```

The underlying transport still uses standard TLS (`security: tls` in JSON configuration). Vision adds its obfuscation layer after the TLS handshake completes.

### Enabling XTLS-Reality

Reality operates at the transport layer and replaces TLS entirely:

```go
// StreamSettings for Reality transport
stream := &internet.StreamConfig{
    ProtocolName: "tcp",
    SecurityType: serial.GetMessageType(&reality.Config{}), // Activates Reality
    SecuritySettings: []*serial.TypedMessage{
        serial.ToTypedMessage(&reality.Config{
            Show:        true,                    // Debug logging
            ServerName:  "www.google.com",        // SNI for handshake
            PublicKey:   publicKeyBytes,          // X25519 public key
            ShortId:     []byte{0x01,0x02,0x03,0x04},
            Fingerprint: "chrome",                // uTLS fingerprint
        }),
    },
}

```

### Combining Both: Vision over Reality

The test suite in [`testing/scenarios/vless_test.go`](https://github.com/XTLS/Xray-core/blob/main/testing/scenarios/vless_test.go) demonstrates combining both modes:

```go
inbound := &core.InboundHandlerConfig{
    ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
        PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(443)}},
        StreamSettings: &internet.StreamConfig{
            ProtocolName: "tcp",
            SecurityType: serial.GetMessageType(&reality.Config{}), // Reality transport
            SecuritySettings: []*serial.TypedMessage{
                serial.ToTypedMessage(&reality.Config{
                    Show:        true,
                    Dest:        "www.google.com:443",
                    ServerNames: []string{"www.google.com"},
                    PrivateKey:  privateKey,
                    ShortIds:    shortIds,
                    Type:        "tcp",
                }),
            },
        },
    }),
    ProxySettings: serial.ToTypedMessage(&inbound.Config{
        Clients: []*protocol.User{
            {
                Account: serial.ToTypedMessage(&vless.Account{
                    Id:   userID.String(),
                    Flow: vless.XRV, // Vision flow on top of Reality
                }),
            },
        },
    }),
}

```

This configuration stacks Vision's post-handshake obfuscation on top of Reality's handshake replacement.

## Key Implementation Files

| File | Purpose |
|------|---------|
| [`proxy/vless/vless.go`](https://github.com/XTLS/Xray-core/blob/main/proxy/vless/vless.go) | Defines `XRV` constant for Vision flow |
| [`proxy/proxy.go`](https://github.com/XTLS/Xray-core/blob/main/proxy/proxy.go) | Implements `VisionReader`/`VisionWriter` with padding logic |
| [`proxy/vless/inbound/inbound.go`](https://github.com/XTLS/Xray-core/blob/main/proxy/vless/inbound/inbound.go) | Injects Vision wrappers for incoming connections |
| [`proxy/vless/outbound/outbound.go`](https://github.com/XTLS/Xray-core/blob/main/proxy/vless/outbound/outbound.go) | Injects Vision wrappers for outgoing connections |
| [`transport/internet/reality/config.pb.go`](https://github.com/XTLS/Xray-core/blob/main/transport/internet/reality/config.pb.go) | Protobuf configuration for Reality |
| [`transport/internet/reality/reality.go`](https://github.com/XTLS/Xray-core/blob/main/transport/internet/reality/reality.go) | Core handshake: uTLS, X25519-ML-KEM, ML-DSA-65 |
| [`transport/internet/tcp/hub.go`](https://github.com/XTLS/Xray-core/blob/main/transport/internet/tcp/hub.go) | Server-side Reality integration |
| [`transport/internet/tcp/dialer.go`](https://github.com/XTLS/Xray-core/blob/main/transport/internet/tcp/dialer.go) | Client-side Reality integration |
| [`testing/scenarios/vless_test.go`](https://github.com/XTLS/Xray-core/blob/main/testing/scenarios/vless_test.go) | End-to-end tests: `TestVlessXtlsVision`, `TestVlessXtlsVisionReality` |

## Summary

- **XTLS-Vision** operates at the **VLESS protocol layer**, adding post-handshake traffic padding and raw-copy optimization. It requires VLESS and standard TLS underneath.

- **XTLS-Reality** operates at the **transport layer**, completely replacing TLS with a handshake that mimics browser fingerprints and uses modern cryptographic primitives (X25519-ML-KEM, optional ML-DSA-65).

- Both modes can be **combined** (Vision flow over Reality transport) for defense-in-depth, as demonstrated in the Xray-core test suite.

- Configuration differs fundamentally: Vision is set per-user via `Flow: "xtls-rprx-vision"`, while Reality is set per-stream via `SecurityType: reality.Config`.

## Frequently Asked Questions

### Can I use XTLS-Vision with protocols other than VLESS?

No. XTLS-Vision is implemented as a VLESS-specific flow constant (`vless.XRV` in [`proxy/vless/vless.go`](https://github.com/XTLS/Xray-core/blob/main/proxy/vless/vless.go)). The `VisionReader` and `VisionWriter` wrappers are injected by the VLESS inbound and outbound handlers. To use Vision-like features with other protocols, you would need to implement equivalent wrapping logic in those protocol handlers.

### Does XTLS-Reality require VLESS?

No. XTLS-Reality is a transport-layer security replacement that works with any proxy protocol. In [`transport/internet/tcp/hub.go`](https://github.com/XTLS/Xray-core/blob/main/transport/internet/tcp/hub.go) and [`dialer.go`](https://github.com/XTLS/Xray-core/blob/main/dialer.go), the Reality configuration is checked via `SecurityType` regardless of the underlying proxy protocol. The test suite demonstrates Reality with VLESS, but the same transport configuration applies to Trojan and other protocols.

### What happens when I combine XTLS-Vision with XTLS-Reality?

The two modes stack: Reality performs its custom handshake and fingerprint obfuscation at the transport layer, establishing an encrypted tunnel. Once established, the VLESS protocol activates Vision's `VisionReader`/`VisionWriter` wrappers, which add post-handshake padding and eventually switch to raw copy mode. This combination provides both handshake-level and traffic-level obfuscation, as validated in `TestVlessXtlsVisionReality` in [`testing/scenarios/vless_test.go`](https://github.com/XTLS/Xray-core/blob/main/testing/scenarios/vless_test.go).

### Which mode offers better protection against DPI detection?

XTLS-Reality generally provides stronger protection against modern DPI systems because it eliminates the standard TLS handshake entirely, replacing it with a browser-fingerprinted handshake that appears as normal HTTPS traffic to passive observers. XTLS-Vision assumes the TLS handshake completes normally and only obfuscates subsequent traffic, which may still reveal proxy usage through handshake characteristics. However, Vision adds meaningful protection against traffic analysis attacks that examine payload sizes and timing patterns after the handshake completes.