# How SingboxConfigTemplateService Generates sing-box Configuration in v2rayN

> Discover how SingboxConfigTemplateService creates sing-box configurations in v2rayN by merging user templates with auto-generated node data, applying custom logic.

- Repository: [2dust/v2rayN](https://github.com/2dust/v2rayN)
- Tags: internals
- Published: 2026-02-27

---

**The SingboxConfigTemplateService merges user-defined JSON templates with auto-generated node configurations by deep-copying outbounds and endpoints into a customizable skeleton, applying detour logic and TUN-specific overrides.**

When v2rayN (2dust/v2rayN) generates client configurations for the sing-box core, it delegates template-based customization to the `SingboxConfigTemplateService`. This service operates as the second stage of a pipeline, allowing power users to inject custom DNS, routing, and global options while preserving automatic node-specific generation. The implementation relies on JSON parsing, deep-copy operations, and conditional logic to blend user templates with generated outbounds.

## Base Configuration Generation

Before template merging occurs, `CoreConfigSingboxService.GenerateClientConfigContent` constructs the foundation configuration. Located in [`v2rayN/ServiceLib/Services/CoreConfig/Singbox/CoreConfigSingboxService.cs`](https://github.com/2dust/v2rayN/blob/main/v2rayN/ServiceLib/Services/CoreConfig/Singbox/CoreConfigSingboxService.cs), this method validates the selected **ProfileItem** (rejecting unsupported transports like `kcp` or `xhttp`), loads the embedded `Global.SingboxSampleClient` resource, and deserializes it into a `SingboxConfig` object.

The service then populates critical sections through private helpers:

- **GenInbounds** – Configures SOCKS/HTTP inbound listeners.
- **GenOutbounds** – Builds proxy outbounds from the selected server nodes.
- **GenRouting** – Sets up routing rules and rule sets.
- **GenDns** – Configures DNS servers and rules.
- **GenExperimental** – Enables experimental features like cache file settings.

Once the base `_coreConfig` object is fully populated, the method invokes `SingboxConfigTemplateService.ApplyFullConfigTemplate` to perform the optional template merge.

## Template Merging Process

The `SingboxConfigTemplateService` resides in [`v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxConfigTemplateService.cs`](https://github.com/2dust/v2rayN/blob/main/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxConfigTemplateService.cs). Its entry point, `ApplyFullConfigTemplate`, accepts the generated configuration context and returns the final JSON string.

### Loading the FullConfigTemplate

The service retrieves the template definition from `context.FullConfigTemplate`, which maps to the `FullConfigTemplateItem` model stored in SQLite. According to the source code in [`v2rayN/ServiceLib/Models/FullConfigTemplateItem.cs`](https://github.com/2dust/v2rayN/blob/main/v2rayN/ServiceLib/Models/FullConfigTemplateItem.cs), this model contains:

- **Enabled** – Boolean toggle for the feature.
- **Config** – JSON string for standard proxy mode.
- **TunConfig** – JSON string for TUN mode.
- **AddProxyOnly** – When `true`, filters out `direct` and `block` outbounds.
- **ProxyDetour** – Label injected into outbounds lacking a detour value.

### Validation and Early Exit

The method performs strict validation before processing:

```csharp
if (fullConfigTemplate is not { Enabled: true }) 
    return JsonUtils.Serialize(_coreConfig);
    
if (fullConfigTemplateItem.IsNullOrEmpty()) 
    return JsonUtils.Serialize(_coreConfig);

var fullConfigTemplateNode = JsonNode.Parse(fullConfigTemplateItem);
if (fullConfigTemplateNode == null) 
    return JsonUtils.Serialize(_coreConfig);

```

If any check fails, the service returns the unmodified base configuration, ensuring stability when templates are disabled or malformed.

### TUN vs Standard Template Selection

The service selects the appropriate JSON template based on the connection mode:

```csharp
var fullConfigTemplateItem = context.IsTunEnabled
    ? fullConfigTemplate.TunConfig
    : fullConfigTemplate.Config;

```

When **TUN** mode is active, the `TunConfig` block provides interface-specific settings; otherwise, the generic `Config` block applies.

### Merging Outbounds and Endpoints

The core logic iterates through the base configuration's outbounds and injects them into the template's `outbounds` array. For each outbound, the service applies two critical transformations:

1. **Filtering** – If `AddProxyOnly` is enabled, `direct` and `block` type outbounds are skipped.
2. **Detour Injection** – If `ProxyDetour` is configured and the outbound lacks a detour, the service assigns the detour label **only** when the server is not a private address (verified via `Utils.IsPrivateNetwork`).

```csharp
foreach (var outbound in _coreConfig.outbounds)
{
    if (outbound.type.ToLower() is "direct" or "block")
    {
        if (fullConfigTemplate.AddProxyOnly == true) continue;
    }
    else if (outbound.detour.IsNullOrEmpty()
        && !fullConfigTemplate.ProxyDetour.IsNullOrEmpty()
        && !Utils.IsPrivateNetwork(outbound.server ?? string.Empty))
    {
        outbound.detour = fullConfigTemplate.ProxyDetour;
    }

    customOutboundsNode.Add(JsonUtils.DeepCopy(outbound));
}

```

The same logic applies to endpoints in `_coreConfig.endpoints`, ensuring custom wireguard or other endpoint configurations inherit the detour settings.

### Final Serialization

After merging, the modified `JsonNode` contains the user-defined template skeleton plus the deep-copied, processed outbounds and endpoints. The service finalizes the configuration with:

```csharp
return JsonUtils.Serialize(fullConfigTemplateNode);

```

This JSON string represents the complete sing-box configuration ready for export or execution.

## Practical Implementation Example

Below is a complete flow demonstrating how the services interact:

```csharp
// Initialize context with server profile and template
var context = new CoreConfigContext
{
    Node = profileItem,
    AppConfig = appConfig,
    FullConfigTemplate = await AppManager.Instance.GetFullConfigTemplateItem(ECoreType.sing_box),
    IsTunEnabled = true  // Activate TUN-specific template
};

// Generate base configuration
var singboxService = new CoreConfigSingboxService(context);
RetResult result = singboxService.GenerateClientConfigContent();

if (result.Success)
{
    // result.Data contains the final merged JSON
    File.WriteAllText("singbox_config.json", result.Data);
}

```

In this example, `AppManager.GetFullConfigTemplateItem` loads the stored template from the SQLite database, and the `SingboxConfigTemplateService` automatically applies the `TunConfig` variations.

## Summary

- **Two-stage pipeline** – `CoreConfigSingboxService` generates the base configuration, then `SingboxConfigTemplateService` applies user-defined templates.
- **Deep-copy merging** – Outbounds and endpoints are cloned into the template array to prevent reference conflicts.
- **Conditional detour injection** – The `ProxyDetour` setting only applies to public network servers, preserving private network direct connections.
- **Mode-aware selection** – Separate `Config` and `TunConfig` templates allow distinct settings for standard proxy versus system TUN modes.
- **Fail-safe design** – Invalid or disabled templates result in the base configuration being returned unchanged.

## Frequently Asked Questions

### What is the difference between Config and TunConfig in the template?

**Config** applies to standard proxy mode where applications connect to v2rayN's local SOCKS/HTTP ports, while **TunConfig** is used when TUN mode is enabled, requiring interface-specific settings like MTU, inet4_address, and auto_route. The `SingboxConfigTemplateService` selects between them based on `context.IsTunEnabled`.

### How does the ProxyDetour parameter modify outbound behavior?

**ProxyDetour** specifies a detour label (such as "proxy" or "chain-outbound") that the service injects into any generated outbound or endpoint that lacks an explicit detour, provided the target server is not a private IP address. This enables automatic routing chains without manual per-node configuration.

### What happens if the full-config template contains invalid JSON?

If `JsonNode.Parse` fails to deserialize the template string, or if the template is empty, the `ApplyFullConfigTemplate` method returns the **unmodified base configuration** generated by `CoreConfigSingboxService`. This ensures the application continues to function even with corrupted template data.

### Can the template override inbounds and routing rules from the base configuration?

**Yes**, because the template JSON serves as the structural skeleton into which generated outbounds are merged. Any inbounds, routing rules, DNS settings, or experimental fields defined in the user's template JSON remain intact and take precedence, while the service appends the auto-generated node outbounds to the existing arrays.