Convert V2Ray Configs Between Protocols with SVM

If you run V2Ray-based proxy configs — whether for personal anti-censorship routing or managing a small fleet of relay nodes — you know the pain of manually rewriting JSON when switching protocols. SVM is a Rust-built tool that converts V2Ray configuration files between protocols (VLESS, VMess, Trojan, Shadowsocks) and formats in seconds. Here is how to put it to work.

Step 1 – Install SVM from Source

SVM is a Rust project, so the build path is straightforward if you have cargo available. Clone the repo and compile a release binary. On a fresh Linux or macOS machine this takes under a minute on modern hardware. The binary is self-contained — no runtime dependencies beyond what the Rust standard library ships. For production use, I drop the compiled binary into /usr/local/bin/ and call it from systemd units or cron-managed config sync jobs. The project has no external network calls during execution, which matters when you are processing sensitive proxy credentials.

git clone https://github.com/sinavm/SVM.git
cd SVM
cargo build --release
cp target/release/svm /usr/local/bin/

There is no package manager wrapper yet — no Homebrew tap, no AUR package, no Docker image. This is a deliberate choice by the author: a single static binary keeps the attack surface minimal. If you want containerized deployment, build your own image with a multi-stage Dockerfile. The binary is under 10 MB stripped, so it is trivial to distribute.

Step 2 – Prepare Your Source Config

SVM expects a valid V2Ray JSON config as input. If your config comes from a subscription link, decode it first — most subscription URIs are base64-encoded concatenations of individual proxy URIs. SVM works on the full config object, not on individual URI strings, so you need to assemble them into a proper V2Ray config.json structure first. I keep a template config with placeholder inbound/outbound sections and a scripts block that injects the converted rules. This template approach avoids repeated boilerplate and lets you version-control your base config in a private Git repo.

The input config must have a valid outbound section with the protocol you are converting from. SVM reads the protocol type from the outbound settings and maps the fields to the target protocol’s expected schema. If your config has multiple outbounds (common when running a mixed-proxy setup), you need to run SVM per outbound or extract the relevant section first with jq.

# Extract a single outbound for conversion
jq '.outbounds[0]' config.json > outbound-source.json
svm convert --in outbound-source.json --from vmess --to vless --out outbound-converted.json

Step 3 – Convert to the Target Protocol

The core command is svm convert. Specify the input file, the source protocol, and the target protocol. SVM handles the field mapping automatically — UUIDs carry over, alterId gets dropped when converting to VLESS (which does not use it), and network settings like ws or grpc transport are preserved when the target protocol supports them. The conversion is lossy in one direction only: you cannot recover alterId from a VLESS config because VLESS does not have that field. This is expected and correct.

SVM also supports batch conversion. Point it at a directory of configs and it will process each file, writing converted versions to an output directory with a -converted suffix. This is useful when you maintain configs for multiple nodes or protocols in a self-hosted infrastructure. I run this as a one-liner in a deployment script that regenerates configs whenever I update a upstream subscription.

# Single conversion
svm convert --in config.json --from vmess --to trojan --out config-trojan.json

# Batch conversion of a directory
svm convert --dir ./configs --from vmess --to vless --out ./converted/

Step 4 – Validate the Output

Do not deploy a converted config without validating it. SVM outputs valid JSON, but structural correctness does not guarantee protocol-level correctness. Use v2ray or xray itself to test the config: xray run -c config-converted.json will immediately report any schema errors or missing required fields. I also pipe the output through jq to sanity-check that critical fields — UUID, address, port, and TLS settings — survived the conversion intact. A mismatch in any of these fields means the proxy will fail to connect silently, which is worse than a loud error at startup.

For TLS configs specifically, verify that certificate paths and SNI values are preserved. SVM copies these as-is, but if your source config uses a self-signed cert and the target protocol expects a different certificate format, you will need to adjust that manually after conversion. This is the one case where SVM’s “copy everything” approach needs a human check.

# Validate with xray
xray run -c config-converted.json --test && echo "Config valid"

# Spot-check critical fields
jq '{uuid, address, port, tls}' config-converted.json

Step 5 – Deploy and Test Connectivity

Once the config passes structural validation, deploy it to your target node. I use a simple rsync pipeline from my local machine to the VPS — the converted config goes to /etc/v2ray/config.json (or wherever your Xray/V2Ray installation expects it), followed by a systemctl restart v2ray. Then the real test: connect a client, verify the proxy works, and check that traffic is routing through the expected outbound. A quick curl --proxy against an IP-leak service confirms the proxy is actually forwarding traffic and not just accepting connections.

Monitor the logs for the first few minutes after deployment. Xray and V2Ray both log connection errors at the warning level that will tell you immediately if the converted config has a field mismatch. If everything looks clean, you are done. The whole pipeline — convert, validate, deploy, test — takes under five minutes per config once you have the workflow established.

Next steps

SVM is a young project and the conversion coverage is growing. If you hit a protocol combination it does not support yet, open an issue on the GitHub repo — the author responds quickly and the codebase is small enough to contribute a converter module yourself. For production deployments, wrap SVM in a CI pipeline that pulls subscription configs from a secure source, runs conversion, validates with xray --test, and deploys only on passing validation. Pair this with a config checksum monitor so you catch drift between what you intend to deploy and what is actually running on your nodes.

Press Cmd K to search