diff --git a/mobile/lib/domain/interfaces/store.interface.dart b/mobile/lib/domain/interfaces/store.interface.dart
index a2d248e801..7a45f9dbe0 100644
--- a/mobile/lib/domain/interfaces/store.interface.dart
+++ b/mobile/lib/domain/interfaces/store.interface.dart
@@ -1,6 +1,7 @@
+import 'package:immich_mobile/domain/interfaces/db.interface.dart';
 import 'package:immich_mobile/domain/models/store.model.dart';
 
-abstract interface class IStoreRepository {
+abstract interface class IStoreRepository implements IDatabaseRepository {
   Future<bool> insert<T>(StoreKey<T> key, T value);
 
   Future<T?> tryGet<T>(StoreKey<T> key);
diff --git a/mobile/lib/domain/models/store.model.dart b/mobile/lib/domain/models/store.model.dart
index 4aca207c6f..06b946b3f6 100644
--- a/mobile/lib/domain/models/store.model.dart
+++ b/mobile/lib/domain/models/store.model.dart
@@ -77,4 +77,23 @@ class StoreUpdateEvent<T> {
   final T? value;
 
   const StoreUpdateEvent(this.key, this.value);
+
+  @override
+  String toString() {
+    return '''
+StoreUpdateEvent: {
+  key: $key,
+  value: ${value ?? '<NA>'},
+}''';
+  }
+
+  @override
+  bool operator ==(covariant StoreUpdateEvent<T> other) {
+    if (identical(this, other)) return true;
+
+    return other.key == key && other.value == value;
+  }
+
+  @override
+  int get hashCode => key.hashCode ^ value.hashCode;
 }
diff --git a/mobile/lib/infrastructure/repositories/store.repository.dart b/mobile/lib/infrastructure/repositories/store.repository.dart
index f22f0f987e..5cf6838ee1 100644
--- a/mobile/lib/infrastructure/repositories/store.repository.dart
+++ b/mobile/lib/infrastructure/repositories/store.repository.dart
@@ -21,7 +21,7 @@ class IsarStoreRepository extends IsarDatabaseRepository
 
   @override
   Stream<StoreUpdateEvent> watchAll() {
-    return _db.storeValues.where().watch().asyncExpand(
+    return _db.storeValues.where().watch(fireImmediately: true).asyncExpand(
           (entities) =>
               Stream.fromFutures(entities.map((e) async => _toUpdateEvent(e))),
         );
@@ -86,17 +86,11 @@ class IsarStoreRepository extends IsarDatabaseRepository
     final (int? intValue, String? strValue) = switch (key.type) {
       const (int) => (value as int, null),
       const (String) => (null, value as String),
-      const (bool) => (
-          (value as bool) ? 1 : 0,
-          null,
-        ),
-      const (DateTime) => (
-          (value as DateTime).millisecondsSinceEpoch,
-          null,
-        ),
+      const (bool) => ((value as bool) ? 1 : 0, null),
+      const (DateTime) => ((value as DateTime).millisecondsSinceEpoch, null),
       const (User) => (
           (await UserRepository(_db).update(value as User)).isarId,
-          null
+          null,
         ),
       _ => throw UnsupportedError(
           "Unsupported primitive type: ${key.type} for key: ${key.name}",
diff --git a/mobile/test/domain/services/store_service_test.dart b/mobile/test/domain/services/store_service_test.dart
new file mode 100644
index 0000000000..554ca73500
--- /dev/null
+++ b/mobile/test/domain/services/store_service_test.dart
@@ -0,0 +1,184 @@
+// ignore_for_file: avoid-dynamic
+
+import 'dart:async';
+
+import 'package:flutter_test/flutter_test.dart';
+import 'package:immich_mobile/domain/interfaces/store.interface.dart';
+import 'package:immich_mobile/domain/models/store.model.dart';
+import 'package:immich_mobile/domain/services/store.service.dart';
+import 'package:mocktail/mocktail.dart';
+
+import '../../infrastructure/repository.mock.dart';
+
+const _kAccessToken = '#ThisIsAToken';
+const _kBackgroundBackup = false;
+const _kGroupAssetsBy = 2;
+final _kBackupFailedSince = DateTime.utc(2023);
+
+void main() {
+  late StoreService sut;
+  late IStoreRepository mockStoreRepo;
+  late StreamController<StoreUpdateEvent> controller;
+
+  setUp(() async {
+    controller = StreamController<StoreUpdateEvent>.broadcast();
+    mockStoreRepo = MockStoreRepository();
+    // For generics, we need to provide fallback to each concrete type to avoid runtime errors
+    registerFallbackValue(StoreKey.accessToken);
+    registerFallbackValue(StoreKey.backupTriggerDelay);
+    registerFallbackValue(StoreKey.backgroundBackup);
+    registerFallbackValue(StoreKey.backupFailedSince);
+
+    when(() => mockStoreRepo.tryGet(any<StoreKey<dynamic>>()))
+        .thenAnswer((invocation) async {
+      final key = invocation.positionalArguments.firstOrNull as StoreKey;
+      return switch (key) {
+        StoreKey.accessToken => _kAccessToken,
+        StoreKey.backgroundBackup => _kBackgroundBackup,
+        StoreKey.groupAssetsBy => _kGroupAssetsBy,
+        StoreKey.backupFailedSince => _kBackupFailedSince,
+        // ignore: avoid-wildcard-cases-with-enums
+        _ => null,
+      };
+    });
+    when(() => mockStoreRepo.watchAll()).thenAnswer((_) => controller.stream);
+
+    sut = await StoreService.create(storeRepository: mockStoreRepo);
+  });
+
+  tearDown(() async {
+    sut.dispose();
+    await controller.close();
+  });
+
+  group("Store Service Init:", () {
+    test('Populates the internal cache on init', () {
+      verify(() => mockStoreRepo.tryGet(any<StoreKey<dynamic>>()))
+          .called(equals(StoreKey.values.length));
+      expect(sut.tryGet(StoreKey.accessToken), _kAccessToken);
+      expect(sut.tryGet(StoreKey.backgroundBackup), _kBackgroundBackup);
+      expect(sut.tryGet(StoreKey.groupAssetsBy), _kGroupAssetsBy);
+      expect(sut.tryGet(StoreKey.backupFailedSince), _kBackupFailedSince);
+      // Other keys should be null
+      expect(sut.tryGet(StoreKey.currentUser), isNull);
+    });
+
+    test('Listens to stream of store updates', () async {
+      final event =
+          StoreUpdateEvent(StoreKey.accessToken, _kAccessToken.toUpperCase());
+      controller.add(event);
+
+      await pumpEventQueue();
+
+      verify(() => mockStoreRepo.watchAll()).called(1);
+      expect(sut.tryGet(StoreKey.accessToken), _kAccessToken.toUpperCase());
+    });
+  });
+
+  group('Store Service get:', () {
+    test('Returns the stored value for the given key', () {
+      expect(sut.get(StoreKey.accessToken), _kAccessToken);
+    });
+
+    test('Throws StoreKeyNotFoundException for nonexistent keys', () {
+      expect(
+        () => sut.get(StoreKey.currentUser),
+        throwsA(isA<StoreKeyNotFoundException>()),
+      );
+    });
+
+    test('Returns the stored value for the given key or the defaultValue', () {
+      expect(sut.get(StoreKey.currentUser, 5), 5);
+    });
+  });
+
+  group('Store Service put:', () {
+    setUp(() {
+      when(() => mockStoreRepo.insert<String>(any<StoreKey<String>>(), any()))
+          .thenAnswer((_) async => true);
+    });
+
+    test('Skip insert when value is not modified', () async {
+      await sut.put(StoreKey.accessToken, _kAccessToken);
+      verifyNever(
+        () => mockStoreRepo.insert<String>(StoreKey.accessToken, any()),
+      );
+    });
+
+    test('Insert value when modified', () async {
+      final newAccessToken = _kAccessToken.toUpperCase();
+      await sut.put(StoreKey.accessToken, newAccessToken);
+      verify(
+        () =>
+            mockStoreRepo.insert<String>(StoreKey.accessToken, newAccessToken),
+      ).called(1);
+      expect(sut.tryGet(StoreKey.accessToken), newAccessToken);
+    });
+  });
+
+  group('Store Service watch:', () {
+    late StreamController<String?> valueController;
+
+    setUp(() {
+      valueController = StreamController<String?>.broadcast();
+      when(() => mockStoreRepo.watch<String>(any<StoreKey<String>>()))
+          .thenAnswer((_) => valueController.stream);
+    });
+
+    tearDown(() async {
+      await valueController.close();
+    });
+
+    test('Watches a specific key for changes', () async {
+      final stream = sut.watch(StoreKey.accessToken);
+      final events = <String?>[
+        _kAccessToken,
+        _kAccessToken.toUpperCase(),
+        null,
+        _kAccessToken.toLowerCase(),
+      ];
+
+      expectLater(stream, emitsInOrder(events));
+
+      for (final event in events) {
+        valueController.add(event);
+      }
+
+      await pumpEventQueue();
+      verify(() => mockStoreRepo.watch<String>(StoreKey.accessToken)).called(1);
+    });
+  });
+
+  group('Store Service delete:', () {
+    setUp(() {
+      when(() => mockStoreRepo.delete<String>(any<StoreKey<String>>()))
+          .thenAnswer((_) async => true);
+    });
+
+    test('Removes the value from the DB', () async {
+      await sut.delete(StoreKey.accessToken);
+      verify(() => mockStoreRepo.delete<String>(StoreKey.accessToken))
+          .called(1);
+    });
+
+    test('Removes the value from the cache', () async {
+      await sut.delete(StoreKey.accessToken);
+      expect(sut.tryGet(StoreKey.accessToken), isNull);
+    });
+  });
+
+  group('Store Service clear:', () {
+    setUp(() {
+      when(() => mockStoreRepo.deleteAll()).thenAnswer((_) async => true);
+    });
+
+    test('Clears all values from the store', () async {
+      await sut.clear();
+      verify(() => mockStoreRepo.deleteAll()).called(1);
+      expect(sut.tryGet(StoreKey.accessToken), isNull);
+      expect(sut.tryGet(StoreKey.backgroundBackup), isNull);
+      expect(sut.tryGet(StoreKey.groupAssetsBy), isNull);
+      expect(sut.tryGet(StoreKey.backupFailedSince), isNull);
+    });
+  });
+}
diff --git a/mobile/test/infrastructure/repositories/store_repository_test.dart b/mobile/test/infrastructure/repositories/store_repository_test.dart
new file mode 100644
index 0000000000..6fd3d3963a
--- /dev/null
+++ b/mobile/test/infrastructure/repositories/store_repository_test.dart
@@ -0,0 +1,181 @@
+// ignore_for_file: avoid-dynamic
+
+import 'package:flutter_test/flutter_test.dart';
+import 'package:immich_mobile/domain/interfaces/store.interface.dart';
+import 'package:immich_mobile/domain/models/store.model.dart';
+import 'package:immich_mobile/entities/user.entity.dart';
+import 'package:immich_mobile/infrastructure/entities/store.entity.dart';
+import 'package:immich_mobile/infrastructure/repositories/store.repository.dart';
+import 'package:isar/isar.dart';
+
+import '../../fixtures/user.stub.dart';
+import '../../test_utils.dart';
+
+const _kTestAccessToken = "#TestToken";
+final _kTestBackupFailed = DateTime(2025, 2, 20, 11, 45);
+const _kTestVersion = 10;
+const _kTestColorfulInterface = false;
+final _kTestUser = UserStub.admin;
+
+Future<void> _addIntStoreValue(Isar db, StoreKey key, int? value) async {
+  await db.storeValues.put(StoreValue(key.id, intValue: value, strValue: null));
+}
+
+Future<void> _addStrStoreValue(Isar db, StoreKey key, String? value) async {
+  await db.storeValues.put(StoreValue(key.id, intValue: null, strValue: value));
+}
+
+Future<void> _populateStore(Isar db) async {
+  await db.writeTxn(() async {
+    await _addIntStoreValue(
+      db,
+      StoreKey.colorfulInterface,
+      _kTestColorfulInterface ? 1 : 0,
+    );
+    await _addIntStoreValue(
+      db,
+      StoreKey.backupFailedSince,
+      _kTestBackupFailed.millisecondsSinceEpoch,
+    );
+    await _addStrStoreValue(db, StoreKey.accessToken, _kTestAccessToken);
+    await _addIntStoreValue(db, StoreKey.version, _kTestVersion);
+  });
+}
+
+void main() {
+  late Isar db;
+  late IStoreRepository sut;
+
+  setUp(() async {
+    db = await TestUtils.initIsar();
+    sut = IsarStoreRepository(db);
+  });
+
+  group('Store Repository converters:', () {
+    test('converts int', () async {
+      int? version = await sut.tryGet(StoreKey.version);
+      expect(version, isNull);
+      await sut.insert(StoreKey.version, _kTestVersion);
+      version = await sut.tryGet(StoreKey.version);
+      expect(version, _kTestVersion);
+    });
+
+    test('converts string', () async {
+      String? accessToken = await sut.tryGet(StoreKey.accessToken);
+      expect(accessToken, isNull);
+      await sut.insert(StoreKey.accessToken, _kTestAccessToken);
+      accessToken = await sut.tryGet(StoreKey.accessToken);
+      expect(accessToken, _kTestAccessToken);
+    });
+
+    test('converts datetime', () async {
+      DateTime? backupFailedSince =
+          await sut.tryGet(StoreKey.backupFailedSince);
+      expect(backupFailedSince, isNull);
+      await sut.insert(StoreKey.backupFailedSince, _kTestBackupFailed);
+      backupFailedSince = await sut.tryGet(StoreKey.backupFailedSince);
+      expect(backupFailedSince, _kTestBackupFailed);
+    });
+
+    test('converts bool', () async {
+      bool? colorfulInterface = await sut.tryGet(StoreKey.colorfulInterface);
+      expect(colorfulInterface, isNull);
+      await sut.insert(StoreKey.colorfulInterface, _kTestColorfulInterface);
+      colorfulInterface = await sut.tryGet(StoreKey.colorfulInterface);
+      expect(colorfulInterface, _kTestColorfulInterface);
+    });
+
+    test('converts user', () async {
+      User? user = await sut.tryGet(StoreKey.currentUser);
+      expect(user, isNull);
+      await sut.insert(StoreKey.currentUser, _kTestUser);
+      user = await sut.tryGet(StoreKey.currentUser);
+      expect(user, _kTestUser);
+    });
+  });
+
+  group('Store Repository Deletes:', () {
+    setUp(() async {
+      await _populateStore(db);
+    });
+
+    test('delete()', () async {
+      bool? isColorful = await sut.tryGet(StoreKey.colorfulInterface);
+      expect(isColorful, isFalse);
+      await sut.delete(StoreKey.colorfulInterface);
+      isColorful = await sut.tryGet(StoreKey.colorfulInterface);
+      expect(isColorful, isNull);
+    });
+
+    test('deleteAll()', () async {
+      final count = await db.storeValues.count();
+      expect(count, isNot(isZero));
+      await sut.deleteAll();
+      expectLater(await db.storeValues.count(), isZero);
+    });
+  });
+
+  group('Store Repository Updates:', () {
+    setUp(() async {
+      await _populateStore(db);
+    });
+
+    test('update()', () async {
+      int? version = await sut.tryGet(StoreKey.version);
+      expect(version, _kTestVersion);
+      await sut.update(StoreKey.version, _kTestVersion + 10);
+      version = await sut.tryGet(StoreKey.version);
+      expect(version, _kTestVersion + 10);
+    });
+  });
+
+  group('Store Repository Watchers:', () {
+    setUp(() async {
+      await _populateStore(db);
+    });
+
+    test('watch()', () async {
+      final stream = sut.watch(StoreKey.version);
+      expectLater(stream, emitsInOrder([_kTestVersion, _kTestVersion + 10]));
+      await pumpEventQueue();
+      await sut.update(StoreKey.version, _kTestVersion + 10);
+    });
+
+    test('watchAll()', () async {
+      final stream = sut.watchAll();
+      expectLater(
+        stream,
+        emitsInAnyOrder([
+          emits(
+            const StoreUpdateEvent<dynamic>(StoreKey.version, _kTestVersion),
+          ),
+          emits(
+            StoreUpdateEvent<dynamic>(
+              StoreKey.backupFailedSince,
+              _kTestBackupFailed,
+            ),
+          ),
+          emits(
+            const StoreUpdateEvent<dynamic>(
+              StoreKey.accessToken,
+              _kTestAccessToken,
+            ),
+          ),
+          emits(
+            const StoreUpdateEvent<dynamic>(
+              StoreKey.colorfulInterface,
+              _kTestColorfulInterface,
+            ),
+          ),
+          emits(
+            const StoreUpdateEvent<dynamic>(
+              StoreKey.version,
+              _kTestVersion + 10,
+            ),
+          ),
+        ]),
+      );
+      await sut.update(StoreKey.version, _kTestVersion + 10);
+    });
+  });
+}
diff --git a/mobile/test/infrastructure/repository.mock.dart b/mobile/test/infrastructure/repository.mock.dart
new file mode 100644
index 0000000000..ff25bdac9d
--- /dev/null
+++ b/mobile/test/infrastructure/repository.mock.dart
@@ -0,0 +1,4 @@
+import 'package:immich_mobile/domain/interfaces/store.interface.dart';
+import 'package:mocktail/mocktail.dart';
+
+class MockStoreRepository extends Mock implements IStoreRepository {}
diff --git a/mobile/test/test_utils.dart b/mobile/test/test_utils.dart
index 39837b6e56..35ab1fb0aa 100644
--- a/mobile/test/test_utils.dart
+++ b/mobile/test/test_utils.dart
@@ -21,10 +21,11 @@ import 'mock_http_override.dart';
 
 // Listener Mock to test when a provider notifies its listeners
 class ListenerMock<T> extends Mock {
+  // ignore: avoid-declaring-call-method
   void call(T? previous, T next);
 }
 
-final class TestUtils {
+abstract final class TestUtils {
   const TestUtils._();
 
   /// Downloads Isar binaries (if required) and initializes a new Isar db
@@ -50,13 +51,14 @@ final class TestUtils {
         AndroidDeviceAssetSchema,
         IOSDeviceAssetSchema,
       ],
-      maxSizeMiB: 1024,
       directory: "test/",
+      maxSizeMiB: 1024,
+      inspector: false,
     );
 
     // Clear and close db on test end
     addTearDown(() async {
-      await db.writeTxn(() => db.clear());
+      await db.writeTxn(() async => await db.clear());
       await db.close();
     });
     return db;