diff --git a/integration/caching_test.js b/integration/caching_test.js
index b3915a8c7e6f8c5d12f13fdb01d38c7585d494c4..a4b831e07dbd817b1e49f339935430fd21c4634d 100644
--- a/integration/caching_test.js
+++ b/integration/caching_test.js
@@ -4,6 +4,7 @@ import { generateSimpleViteManifest, mockApp, mockConfig, mockFetch } from '../s
 import { client } from '../src/redis.js'
 import * as td from 'testdouble'
 import { getRedisKey } from '../src/util.js'
+import { gunzipSync } from 'node:zlib'
 
 describe('File caching service', function () {
   let app
@@ -40,8 +41,10 @@ describe('File caching service', function () {
     expect(response.statusCode).to.equal(200)
     const version = response.headers.version
 
-    expect(await client.get(getRedisKey({ version, name: '/index.html:meta' }))).to.equal('{"sha256Sum":"iFSuC3aK6EN/ASUamuZ+j3xZXI9eBdIlxtVDFjn7y1I=","headers":{"content-type":"text/html","dependencies":false}}')
-    expect(await client.get(getRedisKey({ version, name: '/index.html:body' }))).to.equal('<html><head></head><body>it\'s me</body></html>')
+    const body = await client.getBuffer(getRedisKey({ version, name: '/index.html:body' }))
+    expect(gunzipSync(body).toString()).to.equal('<html><head></head><body>it\'s me</body></html>')
+    const meta = await client.get(getRedisKey({ version, name: '/index.html:meta' }))
+    expect(meta).to.equal('{"headers":{"content-type":"text/html","dependencies":false,"content-encoding":"gzip"}}')
   })
 
   it('serves files from redis and stores them in local cache', async function () {
diff --git a/spec/file_caching_test.js b/spec/file_caching_test.js
index 2037f3aa8a9c1c49abc1f2ab751ba98a31fd25a4..3bbf8f2a1e4dffd09d6d23823a7aa26b97b3ce79 100644
--- a/spec/file_caching_test.js
+++ b/spec/file_caching_test.js
@@ -5,6 +5,7 @@ import { expect } from 'chai'
 import * as td from 'testdouble'
 import RedisMock from 'ioredis-mock'
 import sinon from 'sinon'
+import zlib from 'node:zlib'
 
 const image = fs.readFileSync('./spec/media/image.png')
 const imageStat = fs.statSync('./spec/media/image.png')
@@ -347,4 +348,13 @@ describe('File caching service', function () {
       expect(spy.callCount).to.equal(1)
     })
   })
+
+  it('serves files as gzip', async function () {
+    const response = await request(app).get('/example.js')
+    expect(response.statusCode).to.equal(200)
+    expect(response.headers['content-encoding']).to.equal('gzip')
+
+    // check for files in redis
+    expect(zlib.gunzipSync(await redis.client.getBuffer('ui-middleware:554855300:/example.js:body')).toString()).to.equal(response.text)
+  })
 })
diff --git a/src/files.js b/src/files.js
index 7fe9bdb3f1dc2ee0902ba587745827fee275d973..e7bd62a96c081170f40ea61dffcdc1241f0fe960 100644
--- a/src/files.js
+++ b/src/files.js
@@ -1,4 +1,3 @@
-import crypto from 'crypto'
 import { config } from './config.js'
 import { getRedisKey, isJSFile } from './util.js'
 import { getCSSDependenciesFor, getViteManifests } from './manifests.js'
@@ -6,12 +5,28 @@ import * as cache from './cache.js'
 import { logger } from './logger.js'
 import { NotFoundError } from './errors.js'
 import * as redis from './redis.js'
+import zlib from 'node:zlib'
+import { promisify } from 'node:util'
+const gzip = promisify(zlib.gzip)
 
 export function createWritable (body) {
   if (typeof body !== 'string' && !(body instanceof Buffer)) return JSON.stringify(body)
   return body
 }
 
+async function createFileBuffer (response, dependencies) {
+  const cssString = dependencies && dependencies.map(file => `"${file}"`).join(',')
+  const appendix = cssString && `\n/*injected by ui-middleware*/document.dispatchEvent(new CustomEvent("load-css",{detail:{css:[${cssString}]}}))`
+  const resBuffer = await response.arrayBuffer()
+  const appendixLength = appendix?.length || 0
+  const buffer = Buffer.alloc(resBuffer.byteLength + appendixLength)
+
+  buffer.fill(Buffer.from(resBuffer), 0, resBuffer.byteLength)
+  if (appendix) buffer.write(appendix, resBuffer.byteLength)
+
+  return await gzip(buffer)
+}
+
 export async function fetchFileWithHeadersFromBaseUrl (path, baseUrl, version) {
   const [response, dependencies] = await Promise.all([
     fetch(new URL(path, baseUrl)),
@@ -20,23 +35,14 @@ export async function fetchFileWithHeadersFromBaseUrl (path, baseUrl, version) {
 
   if (!response.ok) throw new NotFoundError(`Error fetching file: ${path}`)
 
-  const cssString = dependencies && dependencies.map(file => `"${file}"`).join(',')
-  const appendix = cssString && `\n/*injected by ui-middleware*/document.dispatchEvent(new CustomEvent("load-css",{detail:{css:[${cssString}]}}))`
-  const resBuffer = await response.arrayBuffer()
-  const appendixLength = appendix?.length || 0
-  const body = Buffer.alloc(resBuffer.byteLength + appendixLength)
-
-  body.fill(Buffer.from(resBuffer), 0, resBuffer.byteLength)
-  if (appendix) body.write(appendix, resBuffer.byteLength)
-
-  const sha256Sum = crypto.createHash('sha256').update(body).digest('base64')
+  const body = await createFileBuffer(response, dependencies)
 
   return {
     body,
-    sha256Sum,
     headers: {
       'content-type': response.headers.get('content-type'),
-      dependencies
+      dependencies,
+      'content-encoding': 'gzip'
     }
   }
 }
diff --git a/src/middlewares/serve-files.js b/src/middlewares/serve-files.js
index 1ef2cb4cde7f63d6310e9c64ef3829c2d903a3f8..4bae7331d8c031a5681ce367f71ecf1baf5f798b 100644
--- a/src/middlewares/serve-files.js
+++ b/src/middlewares/serve-files.js
@@ -7,10 +7,9 @@ export default async function (req, res, next) {
     if (req.method !== 'GET') return next()
     const version = res.version
     const path = req.path === '/' ? '/index.html' : req.path
-    const { body, headers, sha256Sum } = await getFile({ version, path })
+    const { body, headers } = await getFile({ version, path })
 
     res.set(headers)
-    res.locals.sha256Sum = sha256Sum
     res.send(body)
   } catch (err) {
     const errors = err.errors || [err]