# How ChatMCP Handles Cross-Platform Data Storage on macOS, Windows, Linux, iOS, and Android

> Discover how ChatMCP ensures seamless cross-platform data storage on macOS Windows Linux iOS and Android using platform-specific directories and SQLite implementations for consistent database access.

- Repository: [刀刀/chatmcp](https://github.com/daodao97/chatmcp)
- Tags: how-to-guide
- Published: 2026-02-28

---

**ChatMCP uses a platform-detection utility to automatically select appropriate user data directories—such as XDG directories on Linux, %APPDATA% on Windows, and Application Support on macOS—while using platform-specific SQLite implementations (FFI for desktop, native for mobile) to ensure consistent database storage across all supported operating systems.**

ChatMCP, an open-source Flutter-based chat client available at `daodao97/chatmcp`, implements a unified data persistence layer that adapts automatically to desktop and mobile environments. The implementation abstracts file system complexities through three core utility files that handle runtime platform detection, directory selection, and SQLite initialization without requiring manual user configuration.

## Platform Detection at Runtime

ChatMCP determines the host operating system using constants defined in `lib/utils/platform.dart`. These boolean flags are derived from `dart:io` and `flutter/foundation` to categorize devices into desktop, mobile, or web environments:

- `kIsDesktop` — matches Linux, Windows, or macOS
- `kIsMobile` — matches Android or iOS
- `kIsWeb` — fallback for browser environments

These constants enable conditional logic throughout the storage layer, ensuring that code paths for file system access remain platform-appropriate without compile-time directives.

## Adaptive Storage Directory Selection

The `StorageManager` class in `lib/utils/storage_manager.dart` centralizes directory selection through the `getAppDataDirectory()` method. This function returns a platform-specific path where application data—including the SQLite database—resides.

### Linux: XDG Base Directory Compliance

On Linux systems, ChatMCP follows the XDG Base Directory specification. The implementation checks for the `$XDG_DATA_HOME` environment variable first, defaulting to `$HOME/.local/share` when the variable is unset. This ensures compliance with modern Linux standards while maintaining compatibility with sandboxed environments like Flatpak or Snap.

### Windows: Application Data Roaming

For Windows platforms, the storage manager reads the `$APPDATA` environment variable to locate the user's roaming application data folder. This places ChatMCP data in the standard `%APPDATA%` directory, typically resolving to `C:\Users\<username>\AppData\Roaming`.

### macOS: Application Support Directory

On macOS, ChatMCP stores data under `$HOME/Library/Application Support`, the canonical location for application-specific files that should persist across updates but remain user-specific. This avoids cluttering the Documents folder while ensuring Time Machine backups capture the data.

### iOS and Android: Application Documents

Mobile platforms use the `path_provider` Flutter package to retrieve the application documents directory. If the primary documents folder is unavailable, the implementation falls back to a temporary directory to prevent crashes during initialization. This approach respects mobile sandboxing restrictions while ensuring data persists between app sessions.

### Fallback Mechanisms

For unsupported platforms or when `path_provider` fails, the system attempts to use any available application directory from the Flutter framework, ultimately falling back to the system's temporary directory. This guarantees the app remains functional even in unusual environments.

## SQLite Database Initialization

Database handling is implemented in `lib/dao/init_db.dart`, where the `DatabaseHelper` class manages SQLite backend selection and file path resolution.

### Platform-Specific SQLite Backends

The `_initializeSqlite()` method selects the appropriate database implementation based on the platform constants:

- **Desktop (Linux/Windows/macOS)** — initializes `sqflite_ffi` via `sqfliteFfiInit()` and uses `databaseFactoryFfi` for native library access
- **Mobile (iOS/Android)** — uses the standard `sqflite` package with `sqflite.databaseFactory` for optimized mobile performance
- **Web** — falls back to `sqflite_ffi_web` using `databaseFactoryFfiWeb` for browser compatibility

### Database File Path Resolution

The `getDatabasePath()` method in `StorageManager` concatenates the platform-specific directory from `getAppDataDirectory()` with the filename `chatmcp.db`. Before opening the database, the implementation ensures the parent directory exists by calling `Directory(...).create(recursive: true)`, preventing "file not found" errors on first run.

After path resolution, `DatabaseHelper` opens the database, applies versioned migrations, and validates schema integrity, completing the storage initialization pipeline.

## End-to-End Implementation Example

The following Dart code demonstrates how ChatMCP initializes its storage layer across platforms:

```dart
import 'package:chatmcp/utils/storage_manager.dart';
import 'package:chatmcp/dao/init_db.dart';

// Retrieve the platform-specific data directory
Future<void> printAppDataDir() async {
  final dir = await StorageManager.getAppDataDirectory();
  print('ChatMCP data directory -> $dir');
}

// Get the full SQLite file path
Future<void> printDbPath() async {
  final dbPath = await StorageManager.getDatabasePath();
  print('SQLite DB stored at -> $dbPath');
}

// Initialize the database (runs platform-specific logic internally)
Future<void> initialiseDatabase() async {
  await initDb();  // Calls DatabaseHelper._initializeSqlite() under the hood
  print('Database ready');
}

void main() async {
  await printAppDataDir();
  await printDbPath();
  await initialiseDatabase();
}

```

Running this code on **macOS**, **Windows**, **Linux**, **iOS**, or **Android** automatically resolves to the correct storage location and SQLite driver without platform-specific conditional code in the consumer.

## Summary

- **Platform abstraction** — `lib/utils/platform.dart` provides runtime detection via `kIsDesktop`, `kIsMobile`, and `kIsWeb` constants
- **Directory selection** — `StorageManager.getAppDataDirectory()` in `lib/utils/storage_manager.dart` implements XDG, %APPDATA%, Application Support, and mobile documents directory logic
- **Database paths** — `StorageManager.getDatabasePath()` combines the platform directory with `chatmcp.db` and ensures parent directories exist
- **SQLite backends** — `lib/dao/init_db.dart` selects `sqflite_ffi` for desktop, standard `sqflite` for mobile, and `sqflite_ffi_web` for web environments
- **Automatic initialization** — The `initDb()` function orchestrates the entire flow, running migrations after establishing the platform-appropriate connection

## Frequently Asked Questions

### Where does ChatMCP store data on Linux systems?

ChatMCP follows the XDG Base Directory specification on Linux. It checks the `$XDG_DATA_HOME` environment variable first, defaulting to `$HOME/.local/share` if the variable is not set. This ensures compatibility with standard Linux conventions and sandboxed distribution formats.

### How does ChatMCP handle SQLite on desktop versus mobile platforms?

According to the source code in `lib/dao/init_db.dart`, ChatMCP uses `sqflite_ffi` with `databaseFactoryFfi` on desktop platforms (Linux, Windows, macOS) to access native SQLite libraries, while mobile platforms (iOS, Android) use the standard `sqflite` package optimized for mobile architectures. Web platforms use `sqflite_ffi_web` as a fallback.

### What happens if the application documents directory is unavailable on mobile devices?

If `path_provider` fails to return a valid application documents directory on iOS or Android, the `StorageManager` implementation falls back to a temporary directory provided by the system. This ensures the app remains functional even when encountering permission issues or storage constraints, though data persistence depends on the temporary directory's retention policy.

### Is the database file name consistent across all platforms?

Yes. The `getDatabasePath()` method in `lib/utils/storage_manager.dart` consistently appends `chatmcp.db` to the platform-specific application data directory. This uniform naming convention simplifies backup, migration, and debugging across different operating systems.