diff --git a/.envrc.local.template b/.envrc.local.template
index 3ce6b0f6495615dcc7e860b5d64bc7615d2033a5..4f325c997226bd05b4cf139a62d77acd72813181 100644
--- a/.envrc.local.template
+++ b/.envrc.local.template
@@ -1 +1,5 @@
 export HOLI_LIBRETRANSLATE_BASE_URL=http://localhost:5000
+export REDIS_HOST=localhost
+export REDIS_PORT=6380
+export REDIS_PASSWORD=
+export REDIS_DB=
diff --git a/README.md b/README.md
index 2481e7bfed3225d57a0a546dde99e420c34930fc..7a47a5be8ecce636cf3a8a1ff24d6609e01f18e7 100644
--- a/README.md
+++ b/README.md
@@ -151,8 +151,14 @@ if "you know what you're doing".
 
 ### Configuration
 
+To run it locally, use the same Redis environment variables as those used by your local `unified-api` or `okuna`.
+
 | Environment Variable         | Default Value | Description                                   |
-| ---------------------------- | ------------- | ----------------------------------------------|
+| ---------------------------- | ------------- | --------------------------------------------- |
 | PORT                         | 8089          | the port to listen on                         |
 | CACHE_ENABLED                | true          | wether or not to enable caching               |
 | CACHE_TTL_MS_LIBRE_TRANSLATE | 60 seconds    | time-to-live in ms for libretranslate caching |
+| REDIS_HOST                   | localhost     | the hostname of the Redis server              |
+| REDIS_PORT                   | 6380          | the port number of the Redis server           |
+| REDIS_PASSWORD               | -             | the password for the Redis server             |
+| REDIS_DB                     | -             | the Redis database number to use              |
diff --git a/app/deps.ts b/app/deps.ts
index c41463b83ddbfbb2f20533698812e8a75ef59674..7b042e380f650a7ae207e37dbad7d10dcea7ae8e 100644
--- a/app/deps.ts
+++ b/app/deps.ts
@@ -3,3 +3,4 @@ export { createSchema, createYoga } from "npm:graphql-yoga@5.0.1";
 export { useResponseCache } from "npm:@graphql-yoga/plugin-response-cache@1.0.0";
 export { GraphQLError } from "npm:graphql@16.8.1";
 export { Parser } from "https://deno.land/x/html_parser@v0.1.3/src/mod.ts";
+export { createHash } from "https://deno.land/std@0.129.0/hash/mod.ts";
diff --git a/app/libretranslate.ts b/app/libretranslate.ts
index c14ffbcad0aca3e33df6cce254d8b2ffa288a4f6..fe71eb410cddba2aee8f57934d46a2f3566cb09f 100644
--- a/app/libretranslate.ts
+++ b/app/libretranslate.ts
@@ -8,7 +8,8 @@ import {
   ApiTranslationReslut,
 } from "./api_types.ts";
 import { logger } from "./logging.ts";
-import { GraphQLError } from "./deps.ts";
+import { client } from "./redis.ts";
+import { createHash, GraphQLError } from "./deps.ts";
 
 const BASE_URL = Deno.env.get("HOLI_LIBRETRANSLATE_BASE_URL");
 
@@ -31,6 +32,17 @@ const transformLanguageDetectionResult = (
 export const translate = async (
   query: TranslationQueryParameters,
 ): Promise<string> => {
+  const cacheKey = createHash("sha256").update(
+    `translate:${query.text}:${query.targetLanguage}`,
+  ).toString();
+
+  const cachedResult = await client.get(cacheKey);
+
+  if (cachedResult) {
+    logger.debug(`cache hit: ${JSON.stringify({ key: cacheKey })}`);
+    return cachedResult;
+  }
+
   const url = `${BASE_URL}/translate`;
   logger.info(`Starting translation...`);
   const start = Date.now();
@@ -42,7 +54,6 @@ export const translate = async (
         source: "auto",
         target: query.targetLanguage,
         format: TranslationFormat.TEXT,
-        api_key: "",
       }),
       headers: { "Content-Type": "application/json" },
     });
@@ -50,10 +61,19 @@ export const translate = async (
       throw new GraphQLError("Translation failed");
     }
     const json = await response.json();
-    return transformTranslationResult(json);
+    const result = transformTranslationResult(json);
+
+    await client.set(cacheKey, result);
+
+    return result;
   } catch (e) {
     logger.error(
-      `Error performing request to ${url}: ${e.message}`,
+      `Error performing request to ${url}: ${
+        JSON.stringify({
+          message: e.message,
+          cause: e.cause,
+        })
+      }`,
     );
     throw e;
   } finally {
@@ -84,10 +104,12 @@ export const detectLanguage = async (
     return transformLanguageDetectionResult(json);
   } catch (e) {
     logger.error(
-      `Error performing request to ${url}: ${e.message}`,
-    );
-    logger.error(
-      `Error performing request to ${url}: ${e.cause}`,
+      `Error performing request to ${url}: ${
+        JSON.stringify({
+          message: e.message,
+          cause: e.cause,
+        })
+      }`,
     );
     throw e;
   } finally {
diff --git a/app/redis.ts b/app/redis.ts
new file mode 100644
index 0000000000000000000000000000000000000000..0149d7bedacb7f53b7cafd149609d08727be639d
--- /dev/null
+++ b/app/redis.ts
@@ -0,0 +1,30 @@
+import { createClient } from "npm:redis@^4.6";
+
+const missingEnvVars = [];
+
+const REDIS_HOST = Deno.env.get("REDIS_HOST");
+const REDIS_PORT = Deno.env.get("REDIS_PORT");
+const REDIS_PASSWORD = Deno.env.get("REDIS_PASSWORD");
+const REDIS_DB = Deno.env.get("REDIS_DB");
+
+if (!REDIS_HOST) missingEnvVars.push("REDIS_HOST");
+if (!REDIS_PORT) missingEnvVars.push("REDIS_PORT");
+if (!REDIS_PASSWORD) missingEnvVars.push("REDIS_PASSWORD");
+if (!REDIS_DB) missingEnvVars.push("REDIS_DB");
+
+if (missingEnvVars.length > 0) {
+  throw new Error(
+    `The following Redis environment variables are missing: ${
+      missingEnvVars.join(", ")
+    }`,
+  );
+}
+
+export const client = await createClient({
+  socket: {
+    host: REDIS_HOST,
+    port: parseInt(REDIS_PORT),
+  },
+  password: REDIS_PASSWORD,
+  database: parseInt(REDIS_DB),
+}).connect();
diff --git a/deno.lock b/deno.lock
index efe8d6ab0823b5245462417be4f6646c63d5474b..856b5a1fee347c66ba154eea8ae70273fe3e30d6 100644
--- a/deno.lock
+++ b/deno.lock
@@ -3,23 +3,25 @@
   "packages": {
     "specifiers": {
       "npm:@graphql-yoga/plugin-response-cache@1.0.0": "npm:@graphql-yoga/plugin-response-cache@1.0.0_graphql@16.8.1_graphql-yoga@3.9.1__graphql@16.8.1__@envelop+core@3.0.6",
-      "npm:@graphql-yoga/plugin-response-cache@3.3.0": "npm:@graphql-yoga/plugin-response-cache@3.3.0_graphql@16.8.1_graphql-yoga@5.1.1__graphql@16.8.1",
       "npm:graphql-yoga@5.0.1": "npm:graphql-yoga@5.0.1_graphql@16.8.1",
-      "npm:graphql@16.8.1": "npm:graphql@16.8.1"
+      "npm:graphql@16.8.1": "npm:graphql@16.8.1",
+      "npm:redis@4.6.15": "npm:redis@4.6.15_@redis+client@1.5.17",
+      "npm:redis@^4.5": "npm:redis@4.6.15_@redis+client@1.5.17",
+      "npm:redis@^4.6": "npm:redis@4.6.15_@redis+client@1.5.17"
     },
     "npm": {
       "@envelop/core@3.0.6": {
         "integrity": "sha512-06t1xCPXq6QFN7W1JUEf68aCwYN0OUDNAIoJe7bAqhaoa2vn7NCcuX1VHkJ/OWpmElUgCsRO6RiBbIru1in0Ig==",
         "dependencies": {
           "@envelop/types": "@envelop/types@3.0.2",
-          "tslib": "tslib@2.6.2"
+          "tslib": "tslib@2.6.3"
         }
       },
-      "@envelop/core@5.0.0": {
-        "integrity": "sha512-aJdnH/ptv+cvwfvciCBe7TSvccBwo9g0S5f6u35TBVzRVqIGkK03lFlIL+x1cnfZgN9EfR2b1PH2galrT1CdCQ==",
+      "@envelop/core@5.0.1": {
+        "integrity": "sha512-wxA8EyE1fPnlbP0nC/SFI7uU8wSNf4YjxZhAPu0P63QbgIvqHtHsH4L3/u+rsTruzhk3OvNRgQyLsMfaR9uzAQ==",
         "dependencies": {
           "@envelop/types": "@envelop/types@5.0.0",
-          "tslib": "tslib@2.6.2"
+          "tslib": "tslib@2.6.3"
         }
       },
       "@envelop/response-cache@4.0.3_@envelop+core@3.0.6_graphql@16.8.1": {
@@ -30,31 +32,19 @@
           "fast-json-stable-stringify": "fast-json-stable-stringify@2.1.0",
           "graphql": "graphql@16.8.1",
           "lru-cache": "lru-cache@6.0.0",
-          "tslib": "tslib@2.6.2"
-        }
-      },
-      "@envelop/response-cache@6.1.2_@envelop+core@5.0.0_graphql@16.8.1": {
-        "integrity": "sha512-vBX6z/TxBZSNReVn69VJVkdGHpGzHyeQNMz9LXobczl55KCZaf2inBWguSdGq+vx6PlB068GhLeg+a7kseiF1Q==",
-        "dependencies": {
-          "@envelop/core": "@envelop/core@5.0.0",
-          "@graphql-tools/utils": "@graphql-tools/utils@10.0.13_graphql@16.8.1",
-          "@whatwg-node/fetch": "@whatwg-node/fetch@0.9.16",
-          "fast-json-stable-stringify": "fast-json-stable-stringify@2.1.0",
-          "graphql": "graphql@16.8.1",
-          "lru-cache": "lru-cache@10.2.0",
-          "tslib": "tslib@2.6.2"
+          "tslib": "tslib@2.6.3"
         }
       },
       "@envelop/types@3.0.2": {
         "integrity": "sha512-pOFea9ha0EkURWxJ/35axoH9fDGP5S2cUu/5Mmo9pb8zUf+TaEot8vB670XXihFEn/92759BMjLJNWBKmNhyng==",
         "dependencies": {
-          "tslib": "tslib@2.6.2"
+          "tslib": "tslib@2.6.3"
         }
       },
       "@envelop/types@5.0.0": {
         "integrity": "sha512-IPjmgSc4KpQRlO4qbEDnBEixvtb06WDmjKfi/7fkZaryh5HuOmTtixe1EupQI5XfXO8joc3d27uUZ0QdC++euA==",
         "dependencies": {
-          "tslib": "tslib@2.6.2"
+          "tslib": "tslib@2.6.3"
         }
       },
       "@envelop/validation-cache@5.1.3_@envelop+core@3.0.6_graphql@16.8.1": {
@@ -64,7 +54,7 @@
           "graphql": "graphql@16.8.1",
           "hash-it": "hash-it@6.0.0",
           "lru-cache": "lru-cache@6.0.0",
-          "tslib": "tslib@2.6.2"
+          "tslib": "tslib@2.6.3"
         }
       },
       "@graphql-tools/executor@0.0.18_graphql@16.8.1": {
@@ -74,18 +64,18 @@
           "@graphql-typed-document-node/core": "@graphql-typed-document-node/core@3.2.0_graphql@16.8.1",
           "@repeaterjs/repeater": "@repeaterjs/repeater@3.0.4",
           "graphql": "graphql@16.8.1",
-          "tslib": "tslib@2.6.2",
+          "tslib": "tslib@2.6.3",
           "value-or-promise": "value-or-promise@1.0.12"
         }
       },
-      "@graphql-tools/executor@1.2.0_graphql@16.8.1": {
-        "integrity": "sha512-SKlIcMA71Dha5JnEWlw4XxcaJ+YupuXg0QCZgl2TOLFz4SkGCwU/geAsJvUJFwK2RbVLpQv/UMq67lOaBuwDtg==",
+      "@graphql-tools/executor@1.3.0_graphql@16.8.1": {
+        "integrity": "sha512-e+rmEf/2EO4hDnbkO8mTS2FI+jGUNmYkSDKw5TgPVlO8VOKS+TXmJBK6E9v4Gc/39yVkZsffYfW/R8obJrA0mg==",
         "dependencies": {
-          "@graphql-tools/utils": "@graphql-tools/utils@10.0.13_graphql@16.8.1",
+          "@graphql-tools/utils": "@graphql-tools/utils@10.3.2_graphql@16.8.1",
           "@graphql-typed-document-node/core": "@graphql-typed-document-node/core@3.2.0_graphql@16.8.1",
-          "@repeaterjs/repeater": "@repeaterjs/repeater@3.0.5",
+          "@repeaterjs/repeater": "@repeaterjs/repeater@3.0.6",
           "graphql": "graphql@16.8.1",
-          "tslib": "tslib@2.6.2",
+          "tslib": "tslib@2.6.3",
           "value-or-promise": "value-or-promise@1.0.12"
         }
       },
@@ -94,24 +84,24 @@
         "dependencies": {
           "@graphql-tools/utils": "@graphql-tools/utils@9.2.1_graphql@16.8.1",
           "graphql": "graphql@16.8.1",
-          "tslib": "tslib@2.6.2"
+          "tslib": "tslib@2.6.3"
         }
       },
-      "@graphql-tools/merge@9.0.1_graphql@16.8.1": {
-        "integrity": "sha512-hIEExWO9fjA6vzsVjJ3s0cCQ+Q/BEeMVJZtMXd7nbaVefVy0YDyYlEkeoYYNV3NVVvu1G9lr6DM1Qd0DGo9Caw==",
+      "@graphql-tools/merge@9.0.4_graphql@16.8.1": {
+        "integrity": "sha512-MivbDLUQ+4Q8G/Hp/9V72hbn810IJDEZQ57F01sHnlrrijyadibfVhaQfW/pNH+9T/l8ySZpaR/DpL5i+ruZ+g==",
         "dependencies": {
-          "@graphql-tools/utils": "@graphql-tools/utils@10.0.13_graphql@16.8.1",
+          "@graphql-tools/utils": "@graphql-tools/utils@10.3.2_graphql@16.8.1",
           "graphql": "graphql@16.8.1",
-          "tslib": "tslib@2.6.2"
+          "tslib": "tslib@2.6.3"
         }
       },
-      "@graphql-tools/schema@10.0.2_graphql@16.8.1": {
-        "integrity": "sha512-TbPsIZnWyDCLhgPGnDjt4hosiNU2mF/rNtSk5BVaXWnZqvKJ6gzJV4fcHcvhRIwtscDMW2/YTnK6dLVnk8pc4w==",
+      "@graphql-tools/schema@10.0.4_graphql@16.8.1": {
+        "integrity": "sha512-HuIwqbKxPaJujox25Ra4qwz0uQzlpsaBOzO6CVfzB/MemZdd+Gib8AIvfhQArK0YIN40aDran/yi+E5Xf0mQww==",
         "dependencies": {
-          "@graphql-tools/merge": "@graphql-tools/merge@9.0.1_graphql@16.8.1",
-          "@graphql-tools/utils": "@graphql-tools/utils@10.0.13_graphql@16.8.1",
+          "@graphql-tools/merge": "@graphql-tools/merge@9.0.4_graphql@16.8.1",
+          "@graphql-tools/utils": "@graphql-tools/utils@10.3.2_graphql@16.8.1",
           "graphql": "graphql@16.8.1",
-          "tslib": "tslib@2.6.2",
+          "tslib": "tslib@2.6.3",
           "value-or-promise": "value-or-promise@1.0.12"
         }
       },
@@ -121,25 +111,25 @@
           "@graphql-tools/merge": "@graphql-tools/merge@8.4.2_graphql@16.8.1",
           "@graphql-tools/utils": "@graphql-tools/utils@9.2.1_graphql@16.8.1",
           "graphql": "graphql@16.8.1",
-          "tslib": "tslib@2.6.2",
+          "tslib": "tslib@2.6.3",
           "value-or-promise": "value-or-promise@1.0.12"
         }
       },
-      "@graphql-tools/utils@10.0.13_graphql@16.8.1": {
-        "integrity": "sha512-fMILwGr5Dm2zefNItjQ6C2rauigklv69LIwppccICuGTnGaOp3DspLt/6Lxj72cbg5d9z60Sr+Egco3CJKLsNg==",
+      "@graphql-tools/utils@10.3.2_graphql@16.8.1": {
+        "integrity": "sha512-iaqOHS4f90KNADBHqVsRBjKpM6iSvsUg1q5GhWMK03loYLaDzftrEwcsl0OkSSnRhJvAsT7q4q3r3YzRoV0v1g==",
         "dependencies": {
           "@graphql-typed-document-node/core": "@graphql-typed-document-node/core@3.2.0_graphql@16.8.1",
           "cross-inspect": "cross-inspect@1.0.0",
           "dset": "dset@3.1.3",
           "graphql": "graphql@16.8.1",
-          "tslib": "tslib@2.6.2"
+          "tslib": "tslib@2.6.3"
         }
       },
       "@graphql-tools/utils@8.13.1_graphql@16.8.1": {
         "integrity": "sha512-qIh9yYpdUFmctVqovwMdheVNJqFh+DQNWIhX87FJStfXYnmweBUDATok9fWPleKeFwxnW8IapKmY8m8toJEkAw==",
         "dependencies": {
           "graphql": "graphql@16.8.1",
-          "tslib": "tslib@2.6.2"
+          "tslib": "tslib@2.6.3"
         }
       },
       "@graphql-tools/utils@9.2.1_graphql@16.8.1": {
@@ -147,7 +137,7 @@
         "dependencies": {
           "@graphql-typed-document-node/core": "@graphql-typed-document-node/core@3.2.0_graphql@16.8.1",
           "graphql": "graphql@16.8.1",
-          "tslib": "tslib@2.6.2"
+          "tslib": "tslib@2.6.3"
         }
       },
       "@graphql-typed-document-node/core@3.2.0_graphql@16.8.1": {
@@ -159,13 +149,13 @@
       "@graphql-yoga/logger@0.0.1": {
         "integrity": "sha512-6npFz7eZz33mXgSm1waBLMjUNG0D5hTc/p5Hcs1mojkT3KsLpCOFokzTEKboNsBhKevYcaVa/xeA7WBj4UYMLg==",
         "dependencies": {
-          "tslib": "tslib@2.6.2"
+          "tslib": "tslib@2.6.3"
         }
       },
       "@graphql-yoga/logger@2.0.0": {
         "integrity": "sha512-Mg8psdkAp+YTG1OGmvU+xa6xpsAmSir0hhr3yFYPyLNwzUj95DdIwsMpKadDj9xDpYgJcH3Hp/4JMal9DhQimA==",
         "dependencies": {
-          "tslib": "tslib@2.6.2"
+          "tslib": "tslib@2.6.3"
         }
       },
       "@graphql-yoga/plugin-response-cache@1.0.0_graphql@16.8.1_graphql-yoga@3.9.1__graphql@16.8.1__@envelop+core@3.0.6": {
@@ -176,44 +166,36 @@
           "graphql-yoga": "graphql-yoga@3.9.1_graphql@16.8.1_@envelop+core@3.0.6"
         }
       },
-      "@graphql-yoga/plugin-response-cache@3.3.0_graphql@16.8.1_graphql-yoga@5.1.1__graphql@16.8.1": {
-        "integrity": "sha512-SoVpPqR3tBeSyrdVb81zBGehWgtdeqBxEh2HTuv10jhLCL62nvCrCMfe1DYD6AvRE8DlRfLY/uCn8lwS3CAOwg==",
-        "dependencies": {
-          "@envelop/response-cache": "@envelop/response-cache@6.1.2_@envelop+core@5.0.0_graphql@16.8.1",
-          "graphql": "graphql@16.8.1",
-          "graphql-yoga": "graphql-yoga@5.1.1_graphql@16.8.1"
-        }
-      },
       "@graphql-yoga/subscription@3.1.0": {
         "integrity": "sha512-Vc9lh8KzIHyS3n4jBlCbz7zCjcbtQnOBpsymcRvHhFr2cuH+knmRn0EmzimMQ58jQ8kxoRXXC3KJS3RIxSdPIg==",
         "dependencies": {
           "@graphql-yoga/typed-event-target": "@graphql-yoga/typed-event-target@1.0.0",
-          "@repeaterjs/repeater": "@repeaterjs/repeater@3.0.5",
+          "@repeaterjs/repeater": "@repeaterjs/repeater@3.0.6",
           "@whatwg-node/events": "@whatwg-node/events@0.0.2",
-          "tslib": "tslib@2.6.2"
+          "tslib": "tslib@2.6.3"
         }
       },
-      "@graphql-yoga/subscription@5.0.0": {
-        "integrity": "sha512-Ri7sK8hmxd/kwaEa0YT8uqQUb2wOLsmBMxI90QDyf96lzOMJRgBuNYoEkU1pSgsgmW2glceZ96sRYfaXqwVxUw==",
+      "@graphql-yoga/subscription@5.0.1": {
+        "integrity": "sha512-1wCB1DfAnaLzS+IdoOzELGGnx1ODEg9nzQXFh4u2j02vAnne6d+v4A7HIH9EqzVdPLoAaMKXCZUUdKs+j3z1fg==",
         "dependencies": {
           "@graphql-yoga/typed-event-target": "@graphql-yoga/typed-event-target@3.0.0",
-          "@repeaterjs/repeater": "@repeaterjs/repeater@3.0.5",
+          "@repeaterjs/repeater": "@repeaterjs/repeater@3.0.6",
           "@whatwg-node/events": "@whatwg-node/events@0.1.1",
-          "tslib": "tslib@2.6.2"
+          "tslib": "tslib@2.6.3"
         }
       },
       "@graphql-yoga/typed-event-target@1.0.0": {
         "integrity": "sha512-Mqni6AEvl3VbpMtKw+TIjc9qS9a8hKhiAjFtqX488yq5oJtj9TkNlFTIacAVS3vnPiswNsmDiQqvwUOcJgi1DA==",
         "dependencies": {
-          "@repeaterjs/repeater": "@repeaterjs/repeater@3.0.5",
-          "tslib": "tslib@2.6.2"
+          "@repeaterjs/repeater": "@repeaterjs/repeater@3.0.6",
+          "tslib": "tslib@2.6.3"
         }
       },
       "@graphql-yoga/typed-event-target@3.0.0": {
         "integrity": "sha512-w+liuBySifrstuHbFrHoHAEyVnDFVib+073q8AeAJ/qqJfvFvAwUPLLtNohR/WDVRgSasfXtl3dcNuVJWN+rjg==",
         "dependencies": {
-          "@repeaterjs/repeater": "@repeaterjs/repeater@3.0.5",
-          "tslib": "tslib@2.6.2"
+          "@repeaterjs/repeater": "@repeaterjs/repeater@3.0.6",
+          "tslib": "tslib@2.6.3"
         }
       },
       "@kamilkisiela/fast-url-parser@1.1.4": {
@@ -225,31 +207,69 @@
         "dependencies": {
           "asn1js": "asn1js@3.0.5",
           "pvtsutils": "pvtsutils@1.3.5",
-          "tslib": "tslib@2.6.2"
+          "tslib": "tslib@2.6.3"
         }
       },
       "@peculiar/json-schema@1.1.12": {
         "integrity": "sha512-coUfuoMeIB7B8/NMekxaDzLhaYmp0HZNPEjYRm9goRou8UZIC3z21s0sL9AWoCw4EG876QyO3kYrc61WNF9B/w==",
         "dependencies": {
-          "tslib": "tslib@2.6.2"
+          "tslib": "tslib@2.6.3"
         }
       },
-      "@peculiar/webcrypto@1.4.5": {
-        "integrity": "sha512-oDk93QCDGdxFRM8382Zdminzs44dg3M2+E5Np+JWkpqLDyJC9DviMh8F8mEJkYuUcUOGA5jHO5AJJ10MFWdbZw==",
+      "@peculiar/webcrypto@1.5.0": {
+        "integrity": "sha512-BRs5XUAwiyCDQMsVA9IDvDa7UBR9gAvPHgugOeGng3YN6vJ9JYonyDc0lNczErgtCWtucjR5N7VtaonboD/ezg==",
         "dependencies": {
           "@peculiar/asn1-schema": "@peculiar/asn1-schema@2.3.8",
           "@peculiar/json-schema": "@peculiar/json-schema@1.1.12",
           "pvtsutils": "pvtsutils@1.3.5",
-          "tslib": "tslib@2.6.2",
-          "webcrypto-core": "webcrypto-core@1.7.8"
+          "tslib": "tslib@2.6.3",
+          "webcrypto-core": "webcrypto-core@1.8.0"
+        }
+      },
+      "@redis/bloom@1.2.0_@redis+client@1.5.17": {
+        "integrity": "sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==",
+        "dependencies": {
+          "@redis/client": "@redis/client@1.5.17"
+        }
+      },
+      "@redis/client@1.5.17": {
+        "integrity": "sha512-IPvU9A31qRCZ7lds/x+ksuK/UMndd0EASveAvCvEtFFKIZjZ+m/a4a0L7S28KEWoR5ka8526hlSghDo4Hrc2Hg==",
+        "dependencies": {
+          "cluster-key-slot": "cluster-key-slot@1.1.2",
+          "generic-pool": "generic-pool@3.9.0",
+          "yallist": "yallist@4.0.0"
+        }
+      },
+      "@redis/graph@1.1.1_@redis+client@1.5.17": {
+        "integrity": "sha512-FEMTcTHZozZciLRl6GiiIB4zGm5z5F3F6a6FZCyrfxdKOhFlGkiAqlexWMBzCi4DcRoyiOsuLfW+cjlGWyExOw==",
+        "dependencies": {
+          "@redis/client": "@redis/client@1.5.17"
+        }
+      },
+      "@redis/json@1.0.6_@redis+client@1.5.17": {
+        "integrity": "sha512-rcZO3bfQbm2zPRpqo82XbW8zg4G/w4W3tI7X8Mqleq9goQjAGLL7q/1n1ZX4dXEAmORVZ4s1+uKLaUOg7LrUhw==",
+        "dependencies": {
+          "@redis/client": "@redis/client@1.5.17"
+        }
+      },
+      "@redis/search@1.1.6_@redis+client@1.5.17": {
+        "integrity": "sha512-mZXCxbTYKBQ3M2lZnEddwEAks0Kc7nauire8q20oA0oA/LoA+E/b5Y5KZn232ztPb1FkIGqo12vh3Lf+Vw5iTw==",
+        "dependencies": {
+          "@redis/client": "@redis/client@1.5.17"
+        }
+      },
+      "@redis/time-series@1.0.5_@redis+client@1.5.17": {
+        "integrity": "sha512-IFjIgTusQym2B5IZJG3XKr5llka7ey84fw/NOYqESP5WUfQs9zz1ww/9+qoz4ka/S6KcGBodzlCeZ5UImKbscg==",
+        "dependencies": {
+          "@redis/client": "@redis/client@1.5.17"
         }
       },
       "@repeaterjs/repeater@3.0.4": {
         "integrity": "sha512-AW8PKd6iX3vAZ0vA43nOUOnbq/X5ihgU+mSXXqunMkeQADGiqw/PY0JNeYtD5sr0PAy51YPgAPbDoeapv9r8WA==",
         "dependencies": {}
       },
-      "@repeaterjs/repeater@3.0.5": {
-        "integrity": "sha512-l3YHBLAol6d/IKnB9LhpD0cEZWAoe3eFKUyTYWmFmCO2Q/WOckxLQAUyMZWwZV2M/m3+4vgRoaolFqaII82/TA==",
+      "@repeaterjs/repeater@3.0.6": {
+        "integrity": "sha512-Javneu5lsuhwNCryN+pXH93VPQ8g0dBX7wItHFgYiwQmzE1sVdg5tWHiOgHywzL2W21XQopa7IwIEnNbmeUJYA==",
         "dependencies": {}
       },
       "@whatwg-node/events@0.0.2": {
@@ -267,17 +287,17 @@
       "@whatwg-node/fetch@0.8.8": {
         "integrity": "sha512-CdcjGC2vdKhc13KKxgsc6/616BQ7ooDIgPeTuAiE8qfCnS0mGzcfCOoZXypQSz73nxI+GWc7ZReIAVhxoE1KCg==",
         "dependencies": {
-          "@peculiar/webcrypto": "@peculiar/webcrypto@1.4.5",
+          "@peculiar/webcrypto": "@peculiar/webcrypto@1.5.0",
           "@whatwg-node/node-fetch": "@whatwg-node/node-fetch@0.3.6",
           "busboy": "busboy@1.6.0",
           "urlpattern-polyfill": "urlpattern-polyfill@8.0.2",
-          "web-streams-polyfill": "web-streams-polyfill@3.3.2"
+          "web-streams-polyfill": "web-streams-polyfill@3.3.3"
         }
       },
-      "@whatwg-node/fetch@0.9.16": {
-        "integrity": "sha512-mqasZiUNquRe3ea9+aCAuo81BR6vq5opUKprPilIHTnrg8a21Z1T1OrI+KiMFX8OmwO5HUJe/vro47lpj2JPWQ==",
+      "@whatwg-node/fetch@0.9.19": {
+        "integrity": "sha512-J+zopRcUVOhkiQYlHpxOEZuOgZtqW9xMaNQFDjESm9vRcyATms+E2/p2mZiVQGllPqWflkA3SzoJC1MxV4Pf9g==",
         "dependencies": {
-          "@whatwg-node/node-fetch": "@whatwg-node/node-fetch@0.5.6",
+          "@whatwg-node/node-fetch": "@whatwg-node/node-fetch@0.5.16",
           "urlpattern-polyfill": "urlpattern-polyfill@10.0.0"
         }
       },
@@ -288,31 +308,31 @@
           "busboy": "busboy@1.6.0",
           "fast-querystring": "fast-querystring@1.1.2",
           "fast-url-parser": "fast-url-parser@1.1.3",
-          "tslib": "tslib@2.6.2"
+          "tslib": "tslib@2.6.3"
         }
       },
-      "@whatwg-node/node-fetch@0.5.6": {
-        "integrity": "sha512-cmAsGMHoI0S3AHi3CmD3ma1Q234ZI2JNmXyDyM9rLtbXejBKxU3ZWdhS+mzRIAyUxZCMGlFW1tHmROv0MDdxpw==",
+      "@whatwg-node/node-fetch@0.5.16": {
+        "integrity": "sha512-BmwxxGZTI8IDSiocYyb2sWMlHpa4Jq2NZ4BOuvmODgL2pqjgcFfLBuEnpX2xLscQHmmTnk+gKh0EShfRAGn3Pw==",
         "dependencies": {
           "@kamilkisiela/fast-url-parser": "@kamilkisiela/fast-url-parser@1.1.4",
           "@whatwg-node/events": "@whatwg-node/events@0.1.1",
           "busboy": "busboy@1.6.0",
           "fast-querystring": "fast-querystring@1.1.2",
-          "tslib": "tslib@2.6.2"
+          "tslib": "tslib@2.6.3"
         }
       },
       "@whatwg-node/server@0.7.7": {
         "integrity": "sha512-aHURgNDFm/48WVV3vhTMfnEKCYwYgdaRdRhZsQZx4UVFjGGkGay7Ys0+AYu9QT/jpoImv2oONkstoTMUprDofg==",
         "dependencies": {
           "@whatwg-node/fetch": "@whatwg-node/fetch@0.8.8",
-          "tslib": "tslib@2.6.2"
+          "tslib": "tslib@2.6.3"
         }
       },
-      "@whatwg-node/server@0.9.25": {
-        "integrity": "sha512-DlPqPPcfyzh4/9Lz1fl4c5bZsGp/1wCh7B+cK8FE1bWoW7tlZkVguvGn/XnYPKthGzEIwo/fLdHwevH44z+eeg==",
+      "@whatwg-node/server@0.9.44": {
+        "integrity": "sha512-Gmnr598EOl0Y3TCTeAS3PhX8Bj/Np3JoAfED1clln/5nw/cUaYuAUW/0kL7OubKaSCYFB3FKkhHu91VR9Y/LuQ==",
         "dependencies": {
-          "@whatwg-node/fetch": "@whatwg-node/fetch@0.9.16",
-          "tslib": "tslib@2.6.2"
+          "@whatwg-node/fetch": "@whatwg-node/fetch@0.9.19",
+          "tslib": "tslib@2.6.3"
         }
       },
       "asn1js@3.0.5": {
@@ -320,7 +340,7 @@
         "dependencies": {
           "pvtsutils": "pvtsutils@1.3.5",
           "pvutils": "pvutils@1.1.3",
-          "tslib": "tslib@2.6.2"
+          "tslib": "tslib@2.6.3"
         }
       },
       "busboy@1.6.0": {
@@ -329,10 +349,14 @@
           "streamsearch": "streamsearch@1.1.0"
         }
       },
+      "cluster-key-slot@1.1.2": {
+        "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==",
+        "dependencies": {}
+      },
       "cross-inspect@1.0.0": {
         "integrity": "sha512-4PFfn4b5ZN6FMNGSZlyb7wUhuN8wvj8t/VQHZdM4JsDcruGJ8L2kf9zao98QIrBPFCpdk27qst/AGTl7pL3ypQ==",
         "dependencies": {
-          "tslib": "tslib@2.6.2"
+          "tslib": "tslib@2.6.3"
         }
       },
       "dset@3.1.3": {
@@ -359,6 +383,10 @@
           "punycode": "punycode@1.4.1"
         }
       },
+      "generic-pool@3.9.0": {
+        "integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==",
+        "dependencies": {}
+      },
       "graphql-yoga@3.9.1_graphql@16.8.1_@envelop+core@3.0.6": {
         "integrity": "sha512-BB6EkN64VBTXWmf9Kym2OsVZFzBC0mAsQNo9eNB5xIr3t+x7qepQ34xW5A353NWol3Js3xpzxwIKFVF6l9VsPg==",
         "dependencies": {
@@ -374,41 +402,24 @@
           "dset": "dset@3.1.3",
           "graphql": "graphql@16.8.1",
           "lru-cache": "lru-cache@7.18.3",
-          "tslib": "tslib@2.6.2"
+          "tslib": "tslib@2.6.3"
         }
       },
       "graphql-yoga@5.0.1_graphql@16.8.1": {
         "integrity": "sha512-tcdJOjEv5am5TOGX6TcKDyLT5azrnZ38Y+WUgnbYSYeYX12AKuEju94Sr1ixACvruQo6EyogfKpUGwtb7LQYCw==",
         "dependencies": {
-          "@envelop/core": "@envelop/core@5.0.0",
-          "@graphql-tools/executor": "@graphql-tools/executor@1.2.0_graphql@16.8.1",
-          "@graphql-tools/schema": "@graphql-tools/schema@10.0.2_graphql@16.8.1",
-          "@graphql-tools/utils": "@graphql-tools/utils@10.0.13_graphql@16.8.1",
-          "@graphql-yoga/logger": "@graphql-yoga/logger@2.0.0",
-          "@graphql-yoga/subscription": "@graphql-yoga/subscription@5.0.0",
-          "@whatwg-node/fetch": "@whatwg-node/fetch@0.9.16",
-          "@whatwg-node/server": "@whatwg-node/server@0.9.25",
-          "dset": "dset@3.1.3",
-          "graphql": "graphql@16.8.1",
-          "lru-cache": "lru-cache@10.2.0",
-          "tslib": "tslib@2.6.2"
-        }
-      },
-      "graphql-yoga@5.1.1_graphql@16.8.1": {
-        "integrity": "sha512-oak5nVKTHpqJgpA1aT3cJPOlCidrW7l6nbc5L6w07VdFul16ielGI2ZnQDAXO+qQih09/4WspD5x0SsSZH+hkg==",
-        "dependencies": {
-          "@envelop/core": "@envelop/core@5.0.0",
-          "@graphql-tools/executor": "@graphql-tools/executor@1.2.0_graphql@16.8.1",
-          "@graphql-tools/schema": "@graphql-tools/schema@10.0.2_graphql@16.8.1",
-          "@graphql-tools/utils": "@graphql-tools/utils@10.0.13_graphql@16.8.1",
+          "@envelop/core": "@envelop/core@5.0.1",
+          "@graphql-tools/executor": "@graphql-tools/executor@1.3.0_graphql@16.8.1",
+          "@graphql-tools/schema": "@graphql-tools/schema@10.0.4_graphql@16.8.1",
+          "@graphql-tools/utils": "@graphql-tools/utils@10.3.2_graphql@16.8.1",
           "@graphql-yoga/logger": "@graphql-yoga/logger@2.0.0",
-          "@graphql-yoga/subscription": "@graphql-yoga/subscription@5.0.0",
-          "@whatwg-node/fetch": "@whatwg-node/fetch@0.9.16",
-          "@whatwg-node/server": "@whatwg-node/server@0.9.25",
+          "@graphql-yoga/subscription": "@graphql-yoga/subscription@5.0.1",
+          "@whatwg-node/fetch": "@whatwg-node/fetch@0.9.19",
+          "@whatwg-node/server": "@whatwg-node/server@0.9.44",
           "dset": "dset@3.1.3",
           "graphql": "graphql@16.8.1",
-          "lru-cache": "lru-cache@10.2.0",
-          "tslib": "tslib@2.6.2"
+          "lru-cache": "lru-cache@10.4.3",
+          "tslib": "tslib@2.6.3"
         }
       },
       "graphql@16.8.1": {
@@ -419,8 +430,8 @@
         "integrity": "sha512-KHzmSFx1KwyMPw0kXeeUD752q/Kfbzhy6dAZrjXV9kAIXGqzGvv8vhkUqj+2MGZldTo0IBpw6v7iWE7uxsvH0w==",
         "dependencies": {}
       },
-      "lru-cache@10.2.0": {
-        "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==",
+      "lru-cache@10.4.3": {
+        "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
         "dependencies": {}
       },
       "lru-cache@6.0.0": {
@@ -440,19 +451,30 @@
       "pvtsutils@1.3.5": {
         "integrity": "sha512-ARvb14YB9Nm2Xi6nBq1ZX6dAM0FsJnuk+31aUp4TrcZEdKUlSqOqsxJHUPJDNE3qiIp+iUPEIeR6Je/tgV7zsA==",
         "dependencies": {
-          "tslib": "tslib@2.6.2"
+          "tslib": "tslib@2.6.3"
         }
       },
       "pvutils@1.1.3": {
         "integrity": "sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ==",
         "dependencies": {}
       },
+      "redis@4.6.15_@redis+client@1.5.17": {
+        "integrity": "sha512-2NtuOpMW3tnYzBw6S8mbXSX7RPzvVFCA2wFJq9oErushO2UeBkxObk+uvo7gv7n0rhWeOj/IzrHO8TjcFlRSOg==",
+        "dependencies": {
+          "@redis/bloom": "@redis/bloom@1.2.0_@redis+client@1.5.17",
+          "@redis/client": "@redis/client@1.5.17",
+          "@redis/graph": "@redis/graph@1.1.1_@redis+client@1.5.17",
+          "@redis/json": "@redis/json@1.0.6_@redis+client@1.5.17",
+          "@redis/search": "@redis/search@1.1.6_@redis+client@1.5.17",
+          "@redis/time-series": "@redis/time-series@1.0.5_@redis+client@1.5.17"
+        }
+      },
       "streamsearch@1.1.0": {
         "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==",
         "dependencies": {}
       },
-      "tslib@2.6.2": {
-        "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==",
+      "tslib@2.6.3": {
+        "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==",
         "dependencies": {}
       },
       "urlpattern-polyfill@10.0.0": {
@@ -467,18 +489,18 @@
         "integrity": "sha512-Z6Uz+TYwEqE7ZN50gwn+1LCVo9ZVrpxRPOhOLnncYkY1ZzOYtrX8Fwf/rFktZ8R5mJms6EZf5TqNOMeZmnPq9Q==",
         "dependencies": {}
       },
-      "web-streams-polyfill@3.3.2": {
-        "integrity": "sha512-3pRGuxRF5gpuZc0W+EpwQRmCD7gRqcDOMt688KmdlDAgAyaB1XlN0zq2njfDNm44XVdIouE7pZ6GzbdyH47uIQ==",
+      "web-streams-polyfill@3.3.3": {
+        "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==",
         "dependencies": {}
       },
-      "webcrypto-core@1.7.8": {
-        "integrity": "sha512-eBR98r9nQXTqXt/yDRtInszPMjTaSAMJAFDg2AHsgrnczawT1asx9YNBX6k5p+MekbPF4+s/UJJrr88zsTqkSg==",
+      "webcrypto-core@1.8.0": {
+        "integrity": "sha512-kR1UQNH8MD42CYuLzvibfakG5Ew5seG85dMMoAM/1LqvckxaF6pUiidLuraIu4V+YCIFabYecUZAW0TuxAoaqw==",
         "dependencies": {
           "@peculiar/asn1-schema": "@peculiar/asn1-schema@2.3.8",
           "@peculiar/json-schema": "@peculiar/json-schema@1.1.12",
           "asn1js": "asn1js@3.0.5",
           "pvtsutils": "pvtsutils@1.3.5",
-          "tslib": "tslib@2.6.2"
+          "tslib": "tslib@2.6.3"
         }
       },
       "yallist@4.0.0": {
@@ -488,6 +510,12 @@
     }
   },
   "remote": {
+    "https://deno.land/std@0.129.0/encoding/base64.ts": "c8c16b4adaa60d7a8eee047c73ece26844435e8f7f1328d74593dbb2dd58ea4f",
+    "https://deno.land/std@0.129.0/encoding/hex.ts": "7f023e1e51cfd6b189682e602e8640939e7be71a300a2fcf3daf8f84dc609bbc",
+    "https://deno.land/std@0.129.0/hash/_wasm/hash.ts": "c7535aea17d093b51204124e01a45d2924971b584b31893bf3628dafbd466852",
+    "https://deno.land/std@0.129.0/hash/_wasm/wasm.js": "030357a5b58631dfe1ae8c54ef8b481f8abd7c5d06e59b402f090f6672c8ee8e",
+    "https://deno.land/std@0.129.0/hash/hasher.ts": "42fa30957370d69d22800a901ee147a2539b2b8cf3a9000737a4b0fb2317bb8f",
+    "https://deno.land/std@0.129.0/hash/mod.ts": "69943ac4b036f0699994c7ff75415233fb042591b737d9e0c8cd601dda1b84b3",
     "https://deno.land/std@0.155.0/fmt/colors.ts": "ff7dc9c9f33a72bd48bc24b21bbc1b4545d8494a431f17894dbc5fe92a938fc4",
     "https://deno.land/std@0.155.0/testing/_diff.ts": "a23e7fc2b4d8daa3e158fa06856bedf5334ce2a2831e8bf9e509717f455adb2c",
     "https://deno.land/std@0.155.0/testing/_format.ts": "cd11136e1797791045e639e9f0f4640d5b4166148796cad37e6ef75f7d7f3832",
diff --git a/terraform/environments/deployment.tf b/terraform/environments/deployment.tf
index 450bf411ded6c575eef499b212e737ddc0538476..743e8a052e4258f7cf95e23d0a61605be06d8197 100644
--- a/terraform/environments/deployment.tf
+++ b/terraform/environments/deployment.tf
@@ -47,6 +47,29 @@ resource "google_cloud_run_v2_service" "translation_api_service" {
         value = local.environment == "production" ? "https://production.libretranslate.apis.holi.social" : "https://staging.libretranslate.apis.holi.social"
       }
 
+      env {
+        name  = "REDIS_HOST"
+        value = data.terraform_remote_state.holi_infra_state.outputs.redis_host_cmek_development
+      }
+      env {
+        name  = "REDIS_PORT"
+        value = data.terraform_remote_state.holi_infra_state.outputs.redis_port_cmek_development
+      }
+      env {
+        name = "REDIS_PASSWORD"
+        value_source {
+          secret_key_ref {
+            secret  = "REDIS_CMEK_PASSWORD"
+            version = "latest"
+
+          }
+        }
+      }
+      env {
+        name  = "REDIS_DB"
+        value = local.environment == "production" ? "13" : "5"
+      }
+
       resources {
         limits = {
           cpu    = "1"