diff --git a/server/package-lock.json b/server/package-lock.json
index 3279f5272f..0b8e755e22 100644
--- a/server/package-lock.json
+++ b/server/package-lock.json
@@ -51,6 +51,7 @@
         "rxjs": "^7.8.1",
         "sanitize-filename": "^1.6.3",
         "sharp": "^0.33.0",
+        "sirv": "^2.0.4",
         "thumbhash": "^0.1.1",
         "typeorm": "^0.3.17",
         "ua-parser-js": "^1.0.35"
@@ -2730,6 +2731,11 @@
         "url": "https://opencollective.com/unts"
       }
     },
+    "node_modules/@polka/url": {
+      "version": "1.0.0-next.25",
+      "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.25.tgz",
+      "integrity": "sha512-j7P6Rgr3mmtdkeDGTe0E/aYyWEWVtc5yFXtHCRHs28/jptDEWfaVOc5T7cblqy1XKPPfCxJc/8DwQ5YgLOZOVQ=="
+    },
     "node_modules/@sideway/address": {
       "version": "4.1.5",
       "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz",
@@ -8831,6 +8837,14 @@
       "integrity": "sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q==",
       "dev": true
     },
+    "node_modules/mrmime": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz",
+      "integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==",
+      "engines": {
+        "node": ">=10"
+      }
+    },
     "node_modules/ms": {
       "version": "2.1.2",
       "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
@@ -10821,6 +10835,19 @@
       "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
       "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="
     },
+    "node_modules/sirv": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.4.tgz",
+      "integrity": "sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==",
+      "dependencies": {
+        "@polka/url": "^1.0.0-next.24",
+        "mrmime": "^2.0.0",
+        "totalist": "^3.0.0"
+      },
+      "engines": {
+        "node": ">= 10"
+      }
+    },
     "node_modules/sisteransi": {
       "version": "1.0.5",
       "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
@@ -11748,6 +11775,14 @@
         "node": ">=0.6"
       }
     },
+    "node_modules/totalist": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz",
+      "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==",
+      "engines": {
+        "node": ">=6"
+      }
+    },
     "node_modules/tr46": {
       "version": "0.0.3",
       "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
@@ -14468,6 +14503,11 @@
       "integrity": "sha512-Zwq5OCzuwJC2jwqmpEQt7Ds1DTi6BWSwoGkbb1n9pO3hzb35BoJELx7c0T23iDkBGkh2e7tvOtjF3tr3OaQHDQ==",
       "dev": true
     },
+    "@polka/url": {
+      "version": "1.0.0-next.25",
+      "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.25.tgz",
+      "integrity": "sha512-j7P6Rgr3mmtdkeDGTe0E/aYyWEWVtc5yFXtHCRHs28/jptDEWfaVOc5T7cblqy1XKPPfCxJc/8DwQ5YgLOZOVQ=="
+    },
     "@sideway/address": {
       "version": "4.1.5",
       "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz",
@@ -19156,6 +19196,11 @@
       "integrity": "sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q==",
       "dev": true
     },
+    "mrmime": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz",
+      "integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw=="
+    },
     "ms": {
       "version": "2.1.2",
       "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
@@ -20648,6 +20693,16 @@
         }
       }
     },
+    "sirv": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.4.tgz",
+      "integrity": "sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==",
+      "requires": {
+        "@polka/url": "^1.0.0-next.24",
+        "mrmime": "^2.0.0",
+        "totalist": "^3.0.0"
+      }
+    },
     "sisteransi": {
       "version": "1.0.5",
       "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
@@ -21386,6 +21441,11 @@
       "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
       "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="
     },
+    "totalist": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz",
+      "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ=="
+    },
     "tr46": {
       "version": "0.0.3",
       "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
diff --git a/server/package.json b/server/package.json
index 24f77cb211..98ee13c1b1 100644
--- a/server/package.json
+++ b/server/package.json
@@ -76,6 +76,7 @@
     "rxjs": "^7.8.1",
     "sanitize-filename": "^1.6.3",
     "sharp": "^0.33.0",
+    "sirv": "^2.0.4",
     "thumbhash": "^0.1.1",
     "typeorm": "^0.3.17",
     "ua-parser-js": "^1.0.35"
diff --git a/server/src/immich/main.ts b/server/src/immich/main.ts
index 05f3f03811..0039019b62 100644
--- a/server/src/immich/main.ts
+++ b/server/src/immich/main.ts
@@ -5,6 +5,7 @@ import { NestFactory } from '@nestjs/core';
 import { NestExpressApplication } from '@nestjs/platform-express';
 import { json } from 'body-parser';
 import cookieParser from 'cookie-parser';
+import sirv from 'sirv';
 import { AppModule } from './app.module';
 import { AppService } from './app.service';
 import { useSwagger } from './app.utils';
@@ -28,7 +29,20 @@ export async function bootstrap() {
 
   const excludePaths = ['/.well-known/immich', '/custom.css'];
   app.setGlobalPrefix('api', { exclude: excludePaths });
-  app.useStaticAssets('www');
+  // copied from https://github.com/sveltejs/kit/blob/679b5989fe62e3964b9a73b712d7b41831aa1f07/packages/adapter-node/src/handler.js#L46
+  // provides serving of precompressed assets and caching of immutable assets
+  app.use(
+    sirv('www', {
+      etag: true,
+      gzip: true,
+      brotli: true,
+      setHeaders: (res, pathname) => {
+        if (pathname.startsWith(`/_app/immutable`) && res.statusCode === 200) {
+          res.setHeader('cache-control', 'public,max-age=31536000,immutable');
+        }
+      },
+    }),
+  );
   app.use(app.get(AppService).ssr(excludePaths));
 
   const server = await app.listen(port);
diff --git a/web/svelte.config.js b/web/svelte.config.js
index 3cb982c6b8..76a9c2e55b 100644
--- a/web/svelte.config.js
+++ b/web/svelte.config.js
@@ -6,13 +6,8 @@ const config = {
   preprocess: vitePreprocess(),
   kit: {
     adapter: adapter({
-      // default options are shown. On some platforms
-      // these options are set automatically — see below
-      pages: 'build',
-      assets: 'build',
       fallback: 'index.html',
-      precompress: false,
-      strict: true,
+      precompress: true,
     }),
     alias: {
       $lib: 'src/lib',