# How Immich Ensures Data Integrity and Security via StorageService

> Discover how Immich ensures data integrity and security with its StorageService. Learn about mount point validation, permission checks, and media path migration for robust data protection.

- Repository: [Immich/immich](https://github.com/immich-app/immich)
- Tags: internals
- Published: 2026-02-27

---

**Immich guarantees data integrity and security by validating storage mount points at startup, verifying read/write permissions through hidden marker files, automatically migrating media paths when locations change, and executing resilient background deletion jobs—all orchestrated through the centralized `StorageService`.**

The `StorageService` in the [immich-app/immich](https://github.com/immich-app/immich) repository serves as the trust anchor for the entire media pipeline. Located at [`server/src/services/storage.service.ts`](https://github.com/immich-app/immich/blob/main/server/src/services/storage.service.ts), this service implements a defense-in-depth strategy that combines environment-driven configuration with runtime verification to prevent data loss and permission errors before the system accepts user requests.

## Detecting and Configuring the Media Location

When the Immich server boots, `StorageService` determines the canonical media root through a cascading detection strategy implemented in the `detectMediaLocation` method.

### Environment-Driven Configuration

The service first checks for the `IMMICH_STORAGE_MEDIA_LOCATION` environment variable (lines 23–28). If present, this path is immediately adopted as the authoritative media location:

```bash

# .env

IMMICH_STORAGE_MEDIA_LOCATION=/custom/media/path

```

### Fallback Directory Probing

If the environment variable is absent, the service probes a hardcoded list of candidate directories—`/data` and `/usr/src/app/upload`—selecting the first existing path (lines 30–40). The resolved location is then propagated globally via `StorageCore.setMediaLocation()` invoked during `onBootstrap` (line 48), ensuring all downstream services reference the same base path.

## Verifying Mount-Folder Integrity at Runtime

Immich verifies that every required storage folder remains present and writable on every startup. This prevents scenarios where Docker volumes fail to mount or permission changes render media directories read-only.

### The Hidden Mount File Mechanism

For each folder defined in the `StorageFolder` enum (enumerated at line 65), the service creates a hidden `.immich` file via `createMountFile()` (lines 68–69). This marker file serves as proof that the process can both create files in the directory and subsequently locate them.

### Explicit Read and Write Verification

The service performs two distinct validation checks for every folder:

- **Read verification**: `verifyReadAccess()` attempts to read the hidden `.immich` file (line 71). Failure throws an `ImmichStartupError` with a detailed message pointing to Immich documentation.
- **Write verification**: `verifyWriteAccess()` overwrites the marker file with a current timestamp (line 72), confirming the process retains write permissions.

If either check fails, the service emits an error referencing the `docsMessage` constant (line 19) to guide administrators toward remediation:

```typescript
throw new ImmichStartupError(`Failed to read: "${externalPath} (${internalPath}) - ${docsMessage}"`);

```

### Persistent Check Results

Successful validations are persisted to the `systemMetadataRepository` (lines 80–83), storing flags under `mountChecks` to avoid redundant work on subsequent boots. For environments where these checks must be bypassed—such as specific NAS configurations—operators can set `storage.ignoreMountCheckErrors` (lines 87–93), though this constitutes an explicit opt-in security trade-off.

## Automatic Media Location Migration

When administrators relocate the media storage mount point, `StorageService` detects the drift and orchestrates an atomic database migration to maintain referential integrity.

### Detection via Asset Sampling

During `onBootstrap`, the service retrieves sample assets via `assetRepository.getFileSamples()` (lines 99–104) to infer the current filesystem location. If the detected path diverges from the previously stored `MediaLocation`, the service validates that all existing files still reside under the previous root.

### Atomic Path Rewriting

Once validated, the service invokes `databaseRepository.migrateFilePaths(previous, current)` (line 124) to rewrite every file path record in the database. This ensures that database entries remain synchronized with the physical file locations, preventing broken asset links and orphaned records.

## Resilient File Deletion and Cleanup

The background job `FileDelete` (handled by `handleDeleteFiles`) removes orphaned files safely without risking system stability.

The method iterates over the supplied file list (line 40), wrapping each deletion attempt in a `try…catch` block (lines 45–49). This design ensures that a single corrupt path or permission error logs a warning but does not abort the entire cleanup job, preventing denial-of-service conditions caused by malformed filenames or transient filesystem issues.

## Security-First Design Patterns

The `StorageService` implements several security-focused architectural decisions:

- **Mount point proof via `.immich` files**: Guarantees that a directory is not only reachable but owned by the Immich process, detecting volume mount failures immediately.
- **Startup-time permission verification**: Catches permission misconfigurations before the API begins serving requests, reducing the attack surface for privilege escalation.
- **Graceful degradation options**: The `storage.ignoreMountCheckErrors` flag provides a controlled escape hatch for exotic storage configurations while requiring explicit operator acknowledgment of risk.
- **Centralized error documentation**: All mount errors include documentation links, ensuring rapid remediation and reducing mean-time-to-repair for configuration errors.

## Summary

- **Centralized detection**: `detectMediaLocation` resolves the media root from environment variables or fallback paths, storing it in `StorageCore` for global access.
- **Runtime verification**: Every startup validates all `StorageFolder` directories via hidden `.immich` marker files, confirming read and write permissions through `verifyReadAccess` and `verifyWriteAccess`.
- **Automatic migration**: When storage locations change, `migrateFilePaths` atomically updates database records to match the new filesystem layout.
- **Fault-tolerant cleanup**: The `handleDeleteFiles` background job logs individual deletion failures without halting the entire cleanup process.
- **Explicit security trade-offs**: The `ignoreMountCheckErrors` configuration allows intentional bypassing of mount checks only when operators explicitly accept the risk.

## Frequently Asked Questions

### How does Immich detect if a storage folder is properly mounted?

Immich creates a hidden `.immich` file in each required folder during startup using `createMountFile()`, then attempts to read and overwrite this file via `verifyReadAccess()` and `verifyWriteAccess()`. If either operation fails, the service throws an `ImmichStartupError` and halts initialization to prevent operations on potentially unmounted or read-only volumes.

### What happens if I move my Immich media directory to a new location?

When `StorageService` detects a mismatch between the configured `MediaLocation` and the actual filesystem paths found in asset samples, it triggers `databaseRepository.migrateFilePaths()`. This updates all database records from the old path prefix to the new one, ensuring asset links remain valid after the move.

### Can I disable the mount verification checks?

Yes, by setting `storage.ignoreMountCheckErrors` in your environment configuration. However, this is an explicit opt-in that bypasses the startup-time integrity checks in `onBootstrap` (lines 87–93). Disabling these checks is only recommended for specific NAS or bind-mount configurations where the verification logic produces false negatives.

### How does Immich handle errors during background file deletion?

The `handleDeleteFiles` method processes deletions inside individual `try…catch` blocks for each file. This ensures that a single corrupted filename, permission error, or missing file logs a warning without aborting the entire batch, maintaining system availability during cleanup operations.