# How v2rayN Handles SQLite Database Storage for Profiles and Settings

> Discover how v2rayN stores profiles and settings in an SQLite database. Learn about its SQLiteHelper class simplifying CRUD operations and managing all user data.

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

---

**v2rayN uses a singleton `SQLiteHelper` class to manage a local SQLite database file named `guiNDB.db`, providing both synchronous and asynchronous CRUD operations for all user data including proxy profiles, subscriptions, routing rules, and traffic statistics.**

v2rayN persists all runtime user data in a lightweight SQLite database rather than flat files or the Windows registry. This design centralizes data management through a singleton helper pattern, ensuring thread-safe access and consistent data integrity across application restarts. The storage layer handles everything from proxy server configurations to real-time traffic statistics and custom routing rules.

## Database Architecture and File Location

The database layer centers on the `SQLiteHelper` singleton located in [`v2rayN/ServiceLib/Helper/SqliteHelper.cs`](https://github.com/2dust/v2rayN/blob/main/v2rayN/ServiceLib/Helper/SqliteHelper.cs). This helper encapsulates both a synchronous `SQLiteConnection` and an asynchronous `SQLiteAsyncConnection` pointing to **`guiNDB.db`** in the user's configuration folder.

The helper exposes standardized CRUD methods including `InsertAsync`, `InsertAllAsync`, `ReplaceAsync`, `UpdateAsync`, `UpdateAllAsync`, `DeleteAsync`, `ExecuteAsync`, `QueryAsync`, and `TableAsync`. This abstraction allows UI components and manager classes to interact with the database without handling low-level ADO.NET operations directly.

## Database Initialization and Table Creation

During application startup, `AppManager.InitApp()` in [`v2rayN/ServiceLib/Manager/AppManager.cs`](https://github.com/2dust/v2rayN/blob/main/v2rayN/ServiceLib/Manager/AppManager.cs) initializes the database schema by creating tables for all persistent entities:

```csharp
SQLiteHelper.Instance.CreateTable<SubItem>();
SQLiteHelper.Instance.CreateTable<ProfileItem>();
SQLiteHelper.Instance.CreateTable<ServerStatItem>();
SQLiteHelper.Instance.CreateTable<RoutingItem>();
SQLiteHelper.Instance.CreateTable<ProfileExItem>();
SQLiteHelper.Instance.CreateTable<DNSItem>();
SQLiteHelper.Instance.CreateTable<FullConfigTemplateItem>();
#pragma warning disable CS0618
SQLiteHelper.Instance.CreateTable<ProfileGroupItem>();
#pragma warning restore CS0618

```

This initialization runs every time the application starts, ensuring that new installations have all required tables while existing databases remain unaffected.

## Data Models and Entity Structure

v2rayN uses Plain Old CLR Objects (POCOs) decorated with SQLite attributes to define the schema. Each model maps to a specific table in `guiNDB.db`:

| Model | Purpose | Source File |
|-------|---------|-------------|
| `ProfileItem` | Proxy server configurations (address, port, protocol, security settings) | [`v2rayN/ServiceLib/Models/ProfileItem.cs`](https://github.com/2dust/v2rayN/blob/main/v2rayN/ServiceLib/Models/ProfileItem.cs) |
| `SubItem` | Subscription URLs and metadata | [`v2rayN/ServiceLib/Models/SubItem.cs`](https://github.com/2dust/v2rayN/blob/main/v2rayN/ServiceLib/Models/SubItem.cs) |
| `RoutingItem` | Custom routing rules and rule sets | [`v2rayN/ServiceLib/Models/RoutingItem.cs`](https://github.com/2dust/v2rayN/blob/main/v2rayN/ServiceLib/Models/RoutingItem.cs) |
| `DNSItem` | Custom DNS server configurations | [`v2rayN/ServiceLib/Models/DNSItem.cs`](https://github.com/2dust/v2rayN/blob/main/v2rayN/ServiceLib/Models/DNSItem.cs) |
| `ServerStatItem` | Traffic statistics per server | [`v2rayN/ServiceLib/Models/ServerStatItem.cs`](https://github.com/2dust/v2rayN/blob/main/v2rayN/ServiceLib/Models/ServerStatItem.cs) |
| `ProfileExItem` | Extended runtime data (latency, speed test results, UI sort order) | [`v2rayN/ServiceLib/Models/ProfileExItem.cs`](https://github.com/2dust/v2rayN/blob/main/v2rayN/ServiceLib/Models/ProfileExItem.cs) |
| `FullConfigTemplateItem` | Templates for full V2Ray configuration generation | [`v2rayN/ServiceLib/Models/FullConfigTemplateItem.cs`](https://github.com/2dust/v2rayN/blob/main/v2rayN/ServiceLib/Models/FullConfigTemplateItem.cs) |
| `ProfileGroupItem` | Legacy grouping for policy-based routing | [`v2rayN/ServiceLib/Models/ProfileGroupItem.cs`](https://github.com/2dust/v2rayN/blob/main/v2rayN/ServiceLib/Models/ProfileGroupItem.cs) |

Each entity uses `[PrimaryKey]` attributes for unique identifiers, typically using `IndexId` fields as string-based GUIDs.

## CRUD Operations and Data Flow

The `SQLiteHelper` provides a consistent async API for data manipulation. Here are the typical patterns used throughout the codebase:

**Creating a new proxy profile:**

```csharp
var profile = new ProfileItem
{
    IndexId = Guid.NewGuid().ToString(),
    Remarks = "My SS Server",
    ConfigType = EConfigType.Shadowsocks,
    Address = "example.com",
    Port = 8388,
    Password = "myPassword"
};

await SQLiteHelper.Instance.InsertAsync(profile);

```

**Reading all enabled subscriptions:**

```csharp
var subs = await SQLiteHelper.Instance.TableAsync<SubItem>()
               .Where(s => s.Enabled)
               .OrderBy(s => s.Sort)
               .ToListAsync();

```

**Updating traffic statistics in bulk:**

```csharp
// _lstServerStat is a List<ServerStatItem> with modified statistics
await SQLiteHelper.Instance.UpdateAllAsync(_lstServerStat);

```

**Executing raw SQL for maintenance:**

```csharp
await SQLiteHelper.Instance.ExecuteAsync(
    "DELETE FROM ProfileExItem WHERE indexId NOT IN (SELECT indexId FROM ProfileItem)");

```

## Database Migration and Schema Updates

When older database versions are detected, `AppManager.MigrateProfileExtra()` handles schema migrations using raw SQL queries. This method reads existing rows with `SQLiteHelper.Instance.QueryAsync<ProfileItem>(sql)`, transforms the data to match new `ProtocolExtraItem` structures, and persists changes using `UpdateAllAsync`.

This approach allows v2rayN to evolve its data model while preserving user data across application updates.

## Concurrency and Performance Optimization

The database layer handles concurrency through several mechanisms:

* **Async API**: Most UI interactions use `SQLiteAsyncConnection` methods to prevent blocking the main thread.
* **Batch Operations**: `ProfileExManager` implements a queue system (`_queIndexIds`) that batches changes and persists them in bulk using `InsertAllAsync` and `UpdateAllAsync`, reducing database write overhead.
* **Connection Management**: The singleton pattern ensures a single shared connection pool rather than repeatedly opening and closing connections.

## Application Lifecycle and Cleanup

During application shutdown, `AppManager.AppExitAsync` triggers cleanup routines that eventually call `SQLiteHelper.Instance.DisposeDbConnectionAsync()`. This method, referenced in `BackupAndRestoreViewModel`, safely closes both the synchronous and asynchronous database connections, ensuring data integrity and preventing corruption on exit.

## Summary

- v2rayN stores all user data in a single SQLite database file named `guiNDB.db` located in the user's configuration folder.
- The `SQLiteHelper` singleton in [`v2rayN/ServiceLib/Helper/SqliteHelper.cs`](https://github.com/2dust/v2rayN/blob/main/v2rayN/ServiceLib/Helper/SqliteHelper.cs) provides both synchronous and asynchronous CRUD operations.
- Tables are created automatically at startup in `AppManager.InitApp()` for entities like `ProfileItem`, `SubItem`, `RoutingItem`, and `ServerStatItem`.
- Raw SQL execution supports complex queries and database migrations, such as the `MigrateProfileExtra()` method for schema updates.
- Performance is optimized through async operations and batch processing in managers like `ProfileExManager`.
- Graceful shutdown is ensured by `DisposeDbConnectionAsync()` which closes connections safely.

## Frequently Asked Questions

### Where does v2rayN store its SQLite database file?

v2rayN stores the database in a file named `guiNDB.db` within the user's configuration directory. The exact path depends on the operating system and installation type, but the `SQLiteHelper` class constructs the connection string to point to this specific file in the application's data folder.

### How does v2rayN handle database schema updates when upgrading versions?

When the application detects an older database schema (for example, when `ConfigVersion` is less than 3), the `AppManager.MigrateProfileExtra()` method executes raw SQL queries to read existing data, transform it to match new structures like `ProtocolExtraItem`, and write it back using `UpdateAllAsync`. This ensures user data survives application updates.

### Is the database access thread-safe in v2rayN?

Yes, v2rayN uses a singleton `SQLiteHelper` that maintains both synchronous and asynchronous connections. The UI layer primarily uses the async API (`SQLiteAsyncConnection`) to avoid blocking the main thread. Additionally, managers like `ProfileExManager` use internal queues to batch operations, preventing concurrent write conflicts.

### What types of data are stored in the v2rayN SQLite database?

The database stores all persistent user configuration and runtime data, including proxy server profiles (`ProfileItem`), subscription URLs (`SubItem`), custom routing rules (`RoutingItem`), DNS configurations (`DNSItem`), traffic statistics (`ServerStatItem`), extended profile metadata like latency and speed test results (`ProfileExItem`), and configuration templates (`FullConfigTemplateItem`).