diff --git a/server/src/interfaces/stack.interface.ts b/server/src/interfaces/stack.interface.ts
index 378f63fd95..a9fb8cec76 100644
--- a/server/src/interfaces/stack.interface.ts
+++ b/server/src/interfaces/stack.interface.ts
@@ -1,3 +1,4 @@
+import { Updateable } from 'kysely';
 import { StackEntity } from 'src/entities/stack.entity';
 
 export const IStackRepository = 'IStackRepository';
@@ -10,8 +11,8 @@ export interface StackSearch {
 export interface IStackRepository {
   search(query: StackSearch): Promise<StackEntity[]>;
   create(stack: { ownerId: string; assetIds: string[] }): Promise<StackEntity>;
-  update(stack: Pick<StackEntity, 'id'> & Partial<StackEntity>): Promise<StackEntity>;
+  update(id: string, entity: Updateable<StackEntity>): Promise<StackEntity>;
   delete(id: string): Promise<void>;
   deleteAll(ids: string[]): Promise<void>;
-  getById(id: string): Promise<StackEntity | null>;
+  getById(id: string): Promise<StackEntity | undefined>;
 }
diff --git a/server/src/queries/stack.repository.sql b/server/src/queries/stack.repository.sql
index f7da019f05..54f86c94af 100644
--- a/server/src/queries/stack.repository.sql
+++ b/server/src/queries/stack.repository.sql
@@ -1,257 +1,95 @@
 -- NOTE: This file is auto generated by ./sql-generator
 
 -- StackRepository.search
-SELECT
-  "StackEntity"."id" AS "StackEntity_id",
-  "StackEntity"."ownerId" AS "StackEntity_ownerId",
-  "StackEntity"."primaryAssetId" AS "StackEntity_primaryAssetId",
-  "StackEntity__StackEntity_assets"."id" AS "StackEntity__StackEntity_assets_id",
-  "StackEntity__StackEntity_assets"."deviceAssetId" AS "StackEntity__StackEntity_assets_deviceAssetId",
-  "StackEntity__StackEntity_assets"."ownerId" AS "StackEntity__StackEntity_assets_ownerId",
-  "StackEntity__StackEntity_assets"."libraryId" AS "StackEntity__StackEntity_assets_libraryId",
-  "StackEntity__StackEntity_assets"."deviceId" AS "StackEntity__StackEntity_assets_deviceId",
-  "StackEntity__StackEntity_assets"."type" AS "StackEntity__StackEntity_assets_type",
-  "StackEntity__StackEntity_assets"."status" AS "StackEntity__StackEntity_assets_status",
-  "StackEntity__StackEntity_assets"."originalPath" AS "StackEntity__StackEntity_assets_originalPath",
-  "StackEntity__StackEntity_assets"."thumbhash" AS "StackEntity__StackEntity_assets_thumbhash",
-  "StackEntity__StackEntity_assets"."encodedVideoPath" AS "StackEntity__StackEntity_assets_encodedVideoPath",
-  "StackEntity__StackEntity_assets"."createdAt" AS "StackEntity__StackEntity_assets_createdAt",
-  "StackEntity__StackEntity_assets"."updatedAt" AS "StackEntity__StackEntity_assets_updatedAt",
-  "StackEntity__StackEntity_assets"."deletedAt" AS "StackEntity__StackEntity_assets_deletedAt",
-  "StackEntity__StackEntity_assets"."fileCreatedAt" AS "StackEntity__StackEntity_assets_fileCreatedAt",
-  "StackEntity__StackEntity_assets"."localDateTime" AS "StackEntity__StackEntity_assets_localDateTime",
-  "StackEntity__StackEntity_assets"."fileModifiedAt" AS "StackEntity__StackEntity_assets_fileModifiedAt",
-  "StackEntity__StackEntity_assets"."isFavorite" AS "StackEntity__StackEntity_assets_isFavorite",
-  "StackEntity__StackEntity_assets"."isArchived" AS "StackEntity__StackEntity_assets_isArchived",
-  "StackEntity__StackEntity_assets"."isExternal" AS "StackEntity__StackEntity_assets_isExternal",
-  "StackEntity__StackEntity_assets"."isOffline" AS "StackEntity__StackEntity_assets_isOffline",
-  "StackEntity__StackEntity_assets"."checksum" AS "StackEntity__StackEntity_assets_checksum",
-  "StackEntity__StackEntity_assets"."duration" AS "StackEntity__StackEntity_assets_duration",
-  "StackEntity__StackEntity_assets"."isVisible" AS "StackEntity__StackEntity_assets_isVisible",
-  "StackEntity__StackEntity_assets"."livePhotoVideoId" AS "StackEntity__StackEntity_assets_livePhotoVideoId",
-  "StackEntity__StackEntity_assets"."originalFileName" AS "StackEntity__StackEntity_assets_originalFileName",
-  "StackEntity__StackEntity_assets"."sidecarPath" AS "StackEntity__StackEntity_assets_sidecarPath",
-  "StackEntity__StackEntity_assets"."stackId" AS "StackEntity__StackEntity_assets_stackId",
-  "StackEntity__StackEntity_assets"."duplicateId" AS "StackEntity__StackEntity_assets_duplicateId",
-  "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."assetId" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_assetId",
-  "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."description" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_description",
-  "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."exifImageWidth" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_exifImageWidth",
-  "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."exifImageHeight" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_exifImageHeight",
-  "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."fileSizeInByte" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_fileSizeInByte",
-  "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."orientation" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_orientation",
-  "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."dateTimeOriginal" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_dateTimeOriginal",
-  "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."modifyDate" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_modifyDate",
-  "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."timeZone" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_timeZone",
-  "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."latitude" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_latitude",
-  "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."longitude" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_longitude",
-  "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."projectionType" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_projectionType",
-  "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."city" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_city",
-  "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."livePhotoCID" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_livePhotoCID",
-  "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."autoStackId" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_autoStackId",
-  "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."state" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_state",
-  "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."country" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_country",
-  "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."make" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_make",
-  "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."model" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_model",
-  "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."lensModel" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_lensModel",
-  "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."fNumber" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_fNumber",
-  "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."focalLength" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_focalLength",
-  "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."iso" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_iso",
-  "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."exposureTime" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_exposureTime",
-  "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."profileDescription" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_profileDescription",
-  "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."colorspace" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_colorspace",
-  "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."bitsPerSample" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_bitsPerSample",
-  "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."rating" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_rating",
-  "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."fps" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_fps"
-FROM
-  "asset_stack" "StackEntity"
-  LEFT JOIN "assets" "StackEntity__StackEntity_assets" ON "StackEntity__StackEntity_assets"."stackId" = "StackEntity"."id"
-  AND (
-    "StackEntity__StackEntity_assets"."deletedAt" IS NULL
-  )
-  LEFT JOIN "exif" "01db479afeb88793eed8e0d1dde6ccfccf1698b9" ON "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."assetId" = "StackEntity__StackEntity_assets"."id"
-WHERE
-  (("StackEntity"."ownerId" = $1))
+select
+  "asset_stack".*,
+  (
+    select
+      coalesce(json_agg(agg), '[]')
+    from
+      (
+        select
+          *
+        from
+          "assets"
+        where
+          "assets"."deletedAt" is null
+          and "assets"."stackId" = "asset_stack"."id"
+      ) as agg
+  ) as "assets"
+from
+  "asset_stack"
+where
+  "asset_stack"."ownerId" = $1
 
 -- StackRepository.delete
-SELECT DISTINCT
-  "distinctAlias"."StackEntity_id" AS "ids_StackEntity_id",
-  "distinctAlias"."StackEntity__StackEntity_assets_fileCreatedAt"
-FROM
+select
+  *,
   (
-    SELECT
-      "StackEntity"."id" AS "StackEntity_id",
-      "StackEntity"."ownerId" AS "StackEntity_ownerId",
-      "StackEntity"."primaryAssetId" AS "StackEntity_primaryAssetId",
-      "StackEntity__StackEntity_assets"."id" AS "StackEntity__StackEntity_assets_id",
-      "StackEntity__StackEntity_assets"."deviceAssetId" AS "StackEntity__StackEntity_assets_deviceAssetId",
-      "StackEntity__StackEntity_assets"."ownerId" AS "StackEntity__StackEntity_assets_ownerId",
-      "StackEntity__StackEntity_assets"."libraryId" AS "StackEntity__StackEntity_assets_libraryId",
-      "StackEntity__StackEntity_assets"."deviceId" AS "StackEntity__StackEntity_assets_deviceId",
-      "StackEntity__StackEntity_assets"."type" AS "StackEntity__StackEntity_assets_type",
-      "StackEntity__StackEntity_assets"."status" AS "StackEntity__StackEntity_assets_status",
-      "StackEntity__StackEntity_assets"."originalPath" AS "StackEntity__StackEntity_assets_originalPath",
-      "StackEntity__StackEntity_assets"."thumbhash" AS "StackEntity__StackEntity_assets_thumbhash",
-      "StackEntity__StackEntity_assets"."encodedVideoPath" AS "StackEntity__StackEntity_assets_encodedVideoPath",
-      "StackEntity__StackEntity_assets"."createdAt" AS "StackEntity__StackEntity_assets_createdAt",
-      "StackEntity__StackEntity_assets"."updatedAt" AS "StackEntity__StackEntity_assets_updatedAt",
-      "StackEntity__StackEntity_assets"."deletedAt" AS "StackEntity__StackEntity_assets_deletedAt",
-      "StackEntity__StackEntity_assets"."fileCreatedAt" AS "StackEntity__StackEntity_assets_fileCreatedAt",
-      "StackEntity__StackEntity_assets"."localDateTime" AS "StackEntity__StackEntity_assets_localDateTime",
-      "StackEntity__StackEntity_assets"."fileModifiedAt" AS "StackEntity__StackEntity_assets_fileModifiedAt",
-      "StackEntity__StackEntity_assets"."isFavorite" AS "StackEntity__StackEntity_assets_isFavorite",
-      "StackEntity__StackEntity_assets"."isArchived" AS "StackEntity__StackEntity_assets_isArchived",
-      "StackEntity__StackEntity_assets"."isExternal" AS "StackEntity__StackEntity_assets_isExternal",
-      "StackEntity__StackEntity_assets"."isOffline" AS "StackEntity__StackEntity_assets_isOffline",
-      "StackEntity__StackEntity_assets"."checksum" AS "StackEntity__StackEntity_assets_checksum",
-      "StackEntity__StackEntity_assets"."duration" AS "StackEntity__StackEntity_assets_duration",
-      "StackEntity__StackEntity_assets"."isVisible" AS "StackEntity__StackEntity_assets_isVisible",
-      "StackEntity__StackEntity_assets"."livePhotoVideoId" AS "StackEntity__StackEntity_assets_livePhotoVideoId",
-      "StackEntity__StackEntity_assets"."originalFileName" AS "StackEntity__StackEntity_assets_originalFileName",
-      "StackEntity__StackEntity_assets"."sidecarPath" AS "StackEntity__StackEntity_assets_sidecarPath",
-      "StackEntity__StackEntity_assets"."stackId" AS "StackEntity__StackEntity_assets_stackId",
-      "StackEntity__StackEntity_assets"."duplicateId" AS "StackEntity__StackEntity_assets_duplicateId",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."assetId" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_assetId",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."description" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_description",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."exifImageWidth" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_exifImageWidth",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."exifImageHeight" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_exifImageHeight",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."fileSizeInByte" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_fileSizeInByte",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."orientation" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_orientation",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."dateTimeOriginal" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_dateTimeOriginal",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."modifyDate" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_modifyDate",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."timeZone" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_timeZone",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."latitude" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_latitude",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."longitude" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_longitude",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."projectionType" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_projectionType",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."city" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_city",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."livePhotoCID" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_livePhotoCID",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."autoStackId" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_autoStackId",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."state" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_state",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."country" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_country",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."make" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_make",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."model" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_model",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."lensModel" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_lensModel",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."fNumber" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_fNumber",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."focalLength" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_focalLength",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."iso" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_iso",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."exposureTime" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_exposureTime",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."profileDescription" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_profileDescription",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."colorspace" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_colorspace",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."bitsPerSample" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_bitsPerSample",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."rating" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_rating",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."fps" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_fps",
-      "3e3064f11b97177a1e1ce3c77ecf32850343aba1"."id" AS "3e3064f11b97177a1e1ce3c77ecf32850343aba1_id",
-      "3e3064f11b97177a1e1ce3c77ecf32850343aba1"."value" AS "3e3064f11b97177a1e1ce3c77ecf32850343aba1_value",
-      "3e3064f11b97177a1e1ce3c77ecf32850343aba1"."createdAt" AS "3e3064f11b97177a1e1ce3c77ecf32850343aba1_createdAt",
-      "3e3064f11b97177a1e1ce3c77ecf32850343aba1"."updatedAt" AS "3e3064f11b97177a1e1ce3c77ecf32850343aba1_updatedAt",
-      "3e3064f11b97177a1e1ce3c77ecf32850343aba1"."color" AS "3e3064f11b97177a1e1ce3c77ecf32850343aba1_color",
-      "3e3064f11b97177a1e1ce3c77ecf32850343aba1"."parentId" AS "3e3064f11b97177a1e1ce3c77ecf32850343aba1_parentId",
-      "3e3064f11b97177a1e1ce3c77ecf32850343aba1"."userId" AS "3e3064f11b97177a1e1ce3c77ecf32850343aba1_userId"
-    FROM
-      "asset_stack" "StackEntity"
-      LEFT JOIN "assets" "StackEntity__StackEntity_assets" ON "StackEntity__StackEntity_assets"."stackId" = "StackEntity"."id"
-      AND (
-        "StackEntity__StackEntity_assets"."deletedAt" IS NULL
-      )
-      LEFT JOIN "exif" "01db479afeb88793eed8e0d1dde6ccfccf1698b9" ON "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."assetId" = "StackEntity__StackEntity_assets"."id"
-      LEFT JOIN "tag_asset" "4f1c9474d4596aede2814ee2eb938eecf7a93b95" ON "4f1c9474d4596aede2814ee2eb938eecf7a93b95"."assetsId" = "StackEntity__StackEntity_assets"."id"
-      LEFT JOIN "tags" "3e3064f11b97177a1e1ce3c77ecf32850343aba1" ON "3e3064f11b97177a1e1ce3c77ecf32850343aba1"."id" = "4f1c9474d4596aede2814ee2eb938eecf7a93b95"."tagsId"
-    WHERE
-      (("StackEntity"."id" = $1))
-  ) "distinctAlias"
-ORDER BY
-  "distinctAlias"."StackEntity__StackEntity_assets_fileCreatedAt" ASC,
-  "StackEntity_id" ASC
-LIMIT
-  1
+    select
+      coalesce(json_agg(agg), '[]')
+    from
+      (
+        select
+          *,
+          (
+            select
+              coalesce(json_agg(agg), '[]')
+            from
+              (
+                select
+                  "tags".*
+                from
+                  "tags"
+                  inner join "tag_asset" on "tags"."id" = "tag_asset"."tagsId"
+                where
+                  "tag_asset"."assetsId" = "assets"."id"
+              ) as agg
+          ) as "tags"
+        from
+          "assets"
+        where
+          "assets"."deletedAt" is null
+          and "assets"."stackId" = "asset_stack"."id"
+      ) as agg
+  ) as "assets"
+from
+  "asset_stack"
+where
+  "id" = $1::uuid
 
 -- StackRepository.getById
-SELECT DISTINCT
-  "distinctAlias"."StackEntity_id" AS "ids_StackEntity_id",
-  "distinctAlias"."StackEntity__StackEntity_assets_fileCreatedAt"
-FROM
+select
+  *,
   (
-    SELECT
-      "StackEntity"."id" AS "StackEntity_id",
-      "StackEntity"."ownerId" AS "StackEntity_ownerId",
-      "StackEntity"."primaryAssetId" AS "StackEntity_primaryAssetId",
-      "StackEntity__StackEntity_assets"."id" AS "StackEntity__StackEntity_assets_id",
-      "StackEntity__StackEntity_assets"."deviceAssetId" AS "StackEntity__StackEntity_assets_deviceAssetId",
-      "StackEntity__StackEntity_assets"."ownerId" AS "StackEntity__StackEntity_assets_ownerId",
-      "StackEntity__StackEntity_assets"."libraryId" AS "StackEntity__StackEntity_assets_libraryId",
-      "StackEntity__StackEntity_assets"."deviceId" AS "StackEntity__StackEntity_assets_deviceId",
-      "StackEntity__StackEntity_assets"."type" AS "StackEntity__StackEntity_assets_type",
-      "StackEntity__StackEntity_assets"."status" AS "StackEntity__StackEntity_assets_status",
-      "StackEntity__StackEntity_assets"."originalPath" AS "StackEntity__StackEntity_assets_originalPath",
-      "StackEntity__StackEntity_assets"."thumbhash" AS "StackEntity__StackEntity_assets_thumbhash",
-      "StackEntity__StackEntity_assets"."encodedVideoPath" AS "StackEntity__StackEntity_assets_encodedVideoPath",
-      "StackEntity__StackEntity_assets"."createdAt" AS "StackEntity__StackEntity_assets_createdAt",
-      "StackEntity__StackEntity_assets"."updatedAt" AS "StackEntity__StackEntity_assets_updatedAt",
-      "StackEntity__StackEntity_assets"."deletedAt" AS "StackEntity__StackEntity_assets_deletedAt",
-      "StackEntity__StackEntity_assets"."fileCreatedAt" AS "StackEntity__StackEntity_assets_fileCreatedAt",
-      "StackEntity__StackEntity_assets"."localDateTime" AS "StackEntity__StackEntity_assets_localDateTime",
-      "StackEntity__StackEntity_assets"."fileModifiedAt" AS "StackEntity__StackEntity_assets_fileModifiedAt",
-      "StackEntity__StackEntity_assets"."isFavorite" AS "StackEntity__StackEntity_assets_isFavorite",
-      "StackEntity__StackEntity_assets"."isArchived" AS "StackEntity__StackEntity_assets_isArchived",
-      "StackEntity__StackEntity_assets"."isExternal" AS "StackEntity__StackEntity_assets_isExternal",
-      "StackEntity__StackEntity_assets"."isOffline" AS "StackEntity__StackEntity_assets_isOffline",
-      "StackEntity__StackEntity_assets"."checksum" AS "StackEntity__StackEntity_assets_checksum",
-      "StackEntity__StackEntity_assets"."duration" AS "StackEntity__StackEntity_assets_duration",
-      "StackEntity__StackEntity_assets"."isVisible" AS "StackEntity__StackEntity_assets_isVisible",
-      "StackEntity__StackEntity_assets"."livePhotoVideoId" AS "StackEntity__StackEntity_assets_livePhotoVideoId",
-      "StackEntity__StackEntity_assets"."originalFileName" AS "StackEntity__StackEntity_assets_originalFileName",
-      "StackEntity__StackEntity_assets"."sidecarPath" AS "StackEntity__StackEntity_assets_sidecarPath",
-      "StackEntity__StackEntity_assets"."stackId" AS "StackEntity__StackEntity_assets_stackId",
-      "StackEntity__StackEntity_assets"."duplicateId" AS "StackEntity__StackEntity_assets_duplicateId",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."assetId" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_assetId",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."description" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_description",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."exifImageWidth" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_exifImageWidth",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."exifImageHeight" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_exifImageHeight",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."fileSizeInByte" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_fileSizeInByte",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."orientation" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_orientation",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."dateTimeOriginal" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_dateTimeOriginal",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."modifyDate" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_modifyDate",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."timeZone" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_timeZone",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."latitude" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_latitude",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."longitude" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_longitude",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."projectionType" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_projectionType",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."city" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_city",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."livePhotoCID" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_livePhotoCID",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."autoStackId" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_autoStackId",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."state" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_state",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."country" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_country",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."make" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_make",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."model" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_model",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."lensModel" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_lensModel",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."fNumber" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_fNumber",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."focalLength" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_focalLength",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."iso" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_iso",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."exposureTime" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_exposureTime",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."profileDescription" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_profileDescription",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."colorspace" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_colorspace",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."bitsPerSample" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_bitsPerSample",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."rating" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_rating",
-      "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."fps" AS "01db479afeb88793eed8e0d1dde6ccfccf1698b9_fps",
-      "3e3064f11b97177a1e1ce3c77ecf32850343aba1"."id" AS "3e3064f11b97177a1e1ce3c77ecf32850343aba1_id",
-      "3e3064f11b97177a1e1ce3c77ecf32850343aba1"."value" AS "3e3064f11b97177a1e1ce3c77ecf32850343aba1_value",
-      "3e3064f11b97177a1e1ce3c77ecf32850343aba1"."createdAt" AS "3e3064f11b97177a1e1ce3c77ecf32850343aba1_createdAt",
-      "3e3064f11b97177a1e1ce3c77ecf32850343aba1"."updatedAt" AS "3e3064f11b97177a1e1ce3c77ecf32850343aba1_updatedAt",
-      "3e3064f11b97177a1e1ce3c77ecf32850343aba1"."color" AS "3e3064f11b97177a1e1ce3c77ecf32850343aba1_color",
-      "3e3064f11b97177a1e1ce3c77ecf32850343aba1"."parentId" AS "3e3064f11b97177a1e1ce3c77ecf32850343aba1_parentId",
-      "3e3064f11b97177a1e1ce3c77ecf32850343aba1"."userId" AS "3e3064f11b97177a1e1ce3c77ecf32850343aba1_userId"
-    FROM
-      "asset_stack" "StackEntity"
-      LEFT JOIN "assets" "StackEntity__StackEntity_assets" ON "StackEntity__StackEntity_assets"."stackId" = "StackEntity"."id"
-      AND (
-        "StackEntity__StackEntity_assets"."deletedAt" IS NULL
-      )
-      LEFT JOIN "exif" "01db479afeb88793eed8e0d1dde6ccfccf1698b9" ON "01db479afeb88793eed8e0d1dde6ccfccf1698b9"."assetId" = "StackEntity__StackEntity_assets"."id"
-      LEFT JOIN "tag_asset" "4f1c9474d4596aede2814ee2eb938eecf7a93b95" ON "4f1c9474d4596aede2814ee2eb938eecf7a93b95"."assetsId" = "StackEntity__StackEntity_assets"."id"
-      LEFT JOIN "tags" "3e3064f11b97177a1e1ce3c77ecf32850343aba1" ON "3e3064f11b97177a1e1ce3c77ecf32850343aba1"."id" = "4f1c9474d4596aede2814ee2eb938eecf7a93b95"."tagsId"
-    WHERE
-      (("StackEntity"."id" = $1))
-  ) "distinctAlias"
-ORDER BY
-  "distinctAlias"."StackEntity__StackEntity_assets_fileCreatedAt" ASC,
-  "StackEntity_id" ASC
-LIMIT
-  1
+    select
+      coalesce(json_agg(agg), '[]')
+    from
+      (
+        select
+          *,
+          (
+            select
+              coalesce(json_agg(agg), '[]')
+            from
+              (
+                select
+                  "tags".*
+                from
+                  "tags"
+                  inner join "tag_asset" on "tags"."id" = "tag_asset"."tagsId"
+                where
+                  "tag_asset"."assetsId" = "assets"."id"
+              ) as agg
+          ) as "tags"
+        from
+          "assets"
+        where
+          "assets"."deletedAt" is null
+          and "assets"."stackId" = "asset_stack"."id"
+      ) as agg
+  ) as "assets"
+from
+  "asset_stack"
+where
+  "id" = $1::uuid
diff --git a/server/src/repositories/access.repository.ts b/server/src/repositories/access.repository.ts
index 15288b94fa..4d32950d85 100644
--- a/server/src/repositories/access.repository.ts
+++ b/server/src/repositories/access.repository.ts
@@ -36,10 +36,7 @@ class ActivityAccess implements IActivityAccess {
       .where('activity.id', 'in', [...activityIds])
       .where('activity.userId', '=', userId)
       .execute()
-      .then((activities) => {
-        console.log('activities', activities);
-        return new Set(activities.map((activity) => activity.id));
-      });
+      .then((activities) => new Set(activities.map((activity) => activity.id)));
   }
 
   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] })
diff --git a/server/src/repositories/stack.repository.ts b/server/src/repositories/stack.repository.ts
index 2887fbeb96..6a80c1f59c 100644
--- a/server/src/repositories/stack.repository.ts
+++ b/server/src/repositories/stack.repository.ts
@@ -1,84 +1,113 @@
 import { Injectable } from '@nestjs/common';
-import { InjectDataSource, InjectRepository } from '@nestjs/typeorm';
+import { ExpressionBuilder, Kysely, Updateable } from 'kysely';
+import { jsonArrayFrom } from 'kysely/helpers/postgres';
+import { InjectKysely } from 'nestjs-kysely';
+import { DB } from 'src/db';
 import { DummyValue, GenerateSql } from 'src/decorators';
-import { AssetEntity } from 'src/entities/asset.entity';
 import { StackEntity } from 'src/entities/stack.entity';
 import { IStackRepository, StackSearch } from 'src/interfaces/stack.interface';
-import { DataSource, In, Repository } from 'typeorm';
+import { asUuid } from 'src/utils/database';
+
+const withAssets = (eb: ExpressionBuilder<DB, 'asset_stack'>, withTags = false) => {
+  return jsonArrayFrom(
+    eb
+      .selectFrom('assets')
+      .selectAll()
+      .$if(withTags, (eb) =>
+        eb.select((eb) =>
+          jsonArrayFrom(
+            eb
+              .selectFrom('tags')
+              .selectAll('tags')
+              .innerJoin('tag_asset', 'tags.id', 'tag_asset.tagsId')
+              .whereRef('tag_asset.assetsId', '=', 'assets.id'),
+          ).as('tags'),
+        ),
+      )
+      .where('assets.deletedAt', 'is', null)
+      .whereRef('assets.stackId', '=', 'asset_stack.id'),
+  ).as('assets');
+};
 
 @Injectable()
 export class StackRepository implements IStackRepository {
-  constructor(
-    @InjectDataSource() private dataSource: DataSource,
-    @InjectRepository(StackEntity) private repository: Repository<StackEntity>,
-  ) {}
+  constructor(@InjectKysely() private db: Kysely<DB>) {}
 
   @GenerateSql({ params: [{ ownerId: DummyValue.UUID }] })
   search(query: StackSearch): Promise<StackEntity[]> {
-    return this.repository.find({
-      where: {
-        ownerId: query.ownerId,
-        primaryAssetId: query.primaryAssetId,
-      },
-      relations: {
-        assets: {
-          exifInfo: true,
-        },
-      },
-    });
+    return this.db
+      .selectFrom('asset_stack')
+      .selectAll('asset_stack')
+      .select(withAssets)
+      .where('asset_stack.ownerId', '=', query.ownerId)
+      .$if(!!query.primaryAssetId, (eb) => eb.where('asset_stack.primaryAssetId', '=', query.primaryAssetId!))
+      .execute() as unknown as Promise<StackEntity[]>;
   }
 
   async create(entity: { ownerId: string; assetIds: string[] }): Promise<StackEntity> {
-    return this.dataSource.manager.transaction(async (manager) => {
-      const stackRepository = manager.getRepository(StackEntity);
-
-      const stacks = await stackRepository.find({
-        where: {
-          ownerId: entity.ownerId,
-          primaryAssetId: In(entity.assetIds),
-        },
-        select: {
-          id: true,
-          assets: {
-            id: true,
-          },
-        },
-        relations: {
-          assets: {
-            exifInfo: true,
-          },
-        },
-      });
+    return this.db.transaction().execute(async (tx) => {
+      const stacks = await tx
+        .selectFrom('asset_stack')
+        .where('asset_stack.ownerId', '=', entity.ownerId)
+        .where('asset_stack.primaryAssetId', 'in', entity.assetIds)
+        .select('asset_stack.id')
+        .select((eb) =>
+          jsonArrayFrom(
+            eb
+              .selectFrom('assets')
+              .select('assets.id')
+              .whereRef('assets.stackId', '=', 'asset_stack.id')
+              .where('assets.deletedAt', 'is', null),
+          ).as('assets'),
+        )
+        .execute();
 
       const assetIds = new Set<string>(entity.assetIds);
 
       // children
       for (const stack of stacks) {
-        for (const asset of stack.assets) {
-          assetIds.add(asset.id);
+        if (stack.assets && stack.assets.length > 0) {
+          for (const asset of stack.assets) {
+            assetIds.add(asset.id);
+          }
         }
       }
 
       if (stacks.length > 0) {
-        await stackRepository.delete({ id: In(stacks.map((stack) => stack.id)) });
+        await tx
+          .deleteFrom('asset_stack')
+          .where(
+            'id',
+            'in',
+            stacks.map((stack) => stack.id),
+          )
+          .execute();
       }
 
-      const { id } = await stackRepository.save({
-        ownerId: entity.ownerId,
-        primaryAssetId: entity.assetIds[0],
-        assets: [...assetIds].map((id) => ({ id }) as AssetEntity),
-      });
+      const newRecord = await tx
+        .insertInto('asset_stack')
+        .values({
+          ownerId: entity.ownerId,
+          primaryAssetId: entity.assetIds[0],
+        })
+        .returning('id')
+        .executeTakeFirstOrThrow();
 
-      return stackRepository.findOneOrFail({
-        where: {
-          id,
-        },
-        relations: {
-          assets: {
-            exifInfo: true,
-          },
-        },
-      });
+      await tx
+        .updateTable('assets')
+        .set({
+          stackId: newRecord.id,
+          updatedAt: new Date(),
+        })
+        .where('id', 'in', [...assetIds])
+        .execute();
+
+      return tx
+        .selectFrom('asset_stack')
+        .selectAll('asset_stack')
+        .select(withAssets)
+        .where('id', '=', newRecord.id)
+        .executeTakeFirst() as unknown as Promise<StackEntity>;
     });
   }
 
@@ -91,12 +120,12 @@ export class StackRepository implements IStackRepository {
 
     const assetIds = stack.assets.map(({ id }) => id);
 
-    await this.repository.delete(id);
-
-    // Update assets updatedAt
-    await this.dataSource.manager.update(AssetEntity, assetIds, {
-      updatedAt: new Date(),
-    });
+    await this.db.deleteFrom('asset_stack').where('id', '=', asUuid(id)).execute();
+    await this.db
+      .updateTable('assets')
+      .set({ stackId: null, updatedAt: new Date() })
+      .where('id', 'in', assetIds)
+      .execute();
   }
 
   async deleteAll(ids: string[]): Promise<void> {
@@ -110,54 +139,31 @@ export class StackRepository implements IStackRepository {
       assetIds.push(...stack.assets.map(({ id }) => id));
     }
 
-    await this.repository.delete(ids);
-
-    // Update assets updatedAt
-    await this.dataSource.manager.update(AssetEntity, assetIds, {
-      updatedAt: new Date(),
-    });
+    await this.db
+      .updateTable('assets')
+      .set({ updatedAt: new Date(), stackId: null })
+      .where('id', 'in', assetIds)
+      .where('stackId', 'in', ids)
+      .execute();
   }
 
-  update(entity: Partial<StackEntity>) {
-    return this.save(entity);
+  update(id: string, entity: Updateable<StackEntity>): Promise<StackEntity> {
+    return this.db
+      .updateTable('asset_stack')
+      .set(entity)
+      .where('id', '=', asUuid(id))
+      .returningAll('asset_stack')
+      .returning((eb) => withAssets(eb, true))
+      .executeTakeFirstOrThrow() as unknown as Promise<StackEntity>;
   }
 
   @GenerateSql({ params: [DummyValue.UUID] })
-  async getById(id: string): Promise<StackEntity | null> {
-    return this.repository.findOne({
-      where: {
-        id,
-      },
-      relations: {
-        assets: {
-          exifInfo: true,
-          tags: true,
-        },
-      },
-      order: {
-        assets: {
-          fileCreatedAt: 'ASC',
-        },
-      },
-    });
-  }
-
-  private async save(entity: Partial<StackEntity>) {
-    const { id } = await this.repository.save(entity);
-    return this.repository.findOneOrFail({
-      where: {
-        id,
-      },
-      relations: {
-        assets: {
-          exifInfo: true,
-        },
-      },
-      order: {
-        assets: {
-          fileCreatedAt: 'ASC',
-        },
-      },
-    });
+  getById(id: string): Promise<StackEntity | undefined> {
+    return this.db
+      .selectFrom('asset_stack')
+      .selectAll()
+      .select((eb) => withAssets(eb, true))
+      .where('id', '=', asUuid(id))
+      .executeTakeFirst() as Promise<StackEntity | undefined>;
   }
 }
diff --git a/server/src/services/asset.service.spec.ts b/server/src/services/asset.service.spec.ts
index cc8f0a1ab0..bf36c181fc 100755
--- a/server/src/services/asset.service.spec.ts
+++ b/server/src/services/asset.service.spec.ts
@@ -520,7 +520,7 @@ describe(AssetService.name, () => {
 
       await sut.handleAssetDeletion({ id: assetStub.primaryImage.id, deleteOnDisk: true });
 
-      expect(stackMock.update).toHaveBeenCalledWith({
+      expect(stackMock.update).toHaveBeenCalledWith('stack-1', {
         id: 'stack-1',
         primaryAssetId: 'stack-child-asset-1',
       });
diff --git a/server/src/services/asset.service.ts b/server/src/services/asset.service.ts
index de4c0fe0f1..3913c0ce4c 100644
--- a/server/src/services/asset.service.ts
+++ b/server/src/services/asset.service.ts
@@ -192,7 +192,7 @@ export class AssetService extends BaseService {
       const stackAssetIds = asset.stack.assets.map((a) => a.id);
       if (stackAssetIds.length > 2) {
         const newPrimaryAssetId = stackAssetIds.find((a) => a !== id)!;
-        await this.stackRepository.update({
+        await this.stackRepository.update(asset.stack.id, {
           id: asset.stack.id,
           primaryAssetId: newPrimaryAssetId,
         });
diff --git a/server/src/services/stack.service.spec.ts b/server/src/services/stack.service.spec.ts
index 4e8813145c..f37e2c4af4 100644
--- a/server/src/services/stack.service.spec.ts
+++ b/server/src/services/stack.service.spec.ts
@@ -141,7 +141,10 @@ describe(StackService.name, () => {
       await sut.update(authStub.admin, 'stack-id', { primaryAssetId: assetStub.image1.id });
 
       expect(stackMock.getById).toHaveBeenCalledWith('stack-id');
-      expect(stackMock.update).toHaveBeenCalledWith({ id: 'stack-id', primaryAssetId: assetStub.image1.id });
+      expect(stackMock.update).toHaveBeenCalledWith('stack-id', {
+        id: 'stack-id',
+        primaryAssetId: assetStub.image1.id,
+      });
       expect(eventMock.emit).toHaveBeenCalledWith('stack.update', {
         stackId: 'stack-id',
         userId: authStub.admin.user.id,
diff --git a/server/src/services/stack.service.ts b/server/src/services/stack.service.ts
index 58fccc8be2..29413109c5 100644
--- a/server/src/services/stack.service.ts
+++ b/server/src/services/stack.service.ts
@@ -39,7 +39,7 @@ export class StackService extends BaseService {
       throw new BadRequestException('Primary asset must be in the stack');
     }
 
-    const updatedStack = await this.stackRepository.update({ id, primaryAssetId: dto.primaryAssetId });
+    const updatedStack = await this.stackRepository.update(id, { id, primaryAssetId: dto.primaryAssetId });
 
     await this.eventRepository.emit('stack.update', { stackId: id, userId: auth.user.id });