--- slug: /references/caching-module-provider tags: - caching - server - how to sidebar_label: Create Caching Provider keywords: - caching - provider - integration --- import { TypeList } from "docs-ui" # How to Create a Caching Module Provider In this guide, you’ll learn how to create a Caching Module Provider and the methods you must implement in its main service. :::note The Caching Module and its providers are available starting [Medusa v2.11.0](https://github.com/medusajs/medusa/releases/tag/v2.11.0). ::: --- ## Implementation Example As you implement your Caching Module Provider, it can be useful to refer to an existing provider and how it's implemeted. If you need to refer to an existing implementation as an example, check the [Redis Caching Module Provider in the Medusa repository](https://github.com/medusajs/medusa/tree/develop/packages/modules/providers/caching-redis). --- ## 1. Create Module Provider Directory Start by creating a new directory for your module provider. If you're creating the module provider in a Medusa application, create it under the `src/modules` directory. For example, `src/modules/my-caching`. If you're creating the module provider in a plugin, create it under the `src/providers` directory. For example, `src/providers/my-caching`. The rest of this guide always uses the `src/modules/my-caching` directory as an example. --- ## 2. Create the Caching Module Provider Service Create the file `src/modules/my-caching/service.ts` that holds the module provider's main service. It must implement the `ICachingProviderService` interface imported from `@medusajs/framework/types`: ```ts title="src/modules/my-caching/service.ts" import { ICachingProviderService } from "@medusajs/framework/types" class MyCachingProviderService implements ICachingProviderService { // TODO implement methods } export default MyCachingProviderService ``` ### constructor The constructor allows you to access resources from the module's container using the first parameter, and the module's options using the second parameter. If you're creating a client or establishing a connection with a third-party service, do it in a [Loader](https://docs.medusajs.com/learn/fundamentals/modules/loaders) and store it in the Module's container. Then, you can access it in your service using the container. :::note[Loader Example] [Initialize MongoDB client in loader and access it in service](https://docs.medusajs.com/learn/fundamentals/modules/loaders#example-register-custom-mongodb-connection). ::: #### Example ```ts import { ICachingProviderService } from "@medusajs/framework/types" import { Logger } from "@medusajs/framework/types" type InjectedDependencies = { logger: Logger // assuming you initialized a client // in a Loader and stored it in the container client: Client } type Options = { url: string } class MyCachingModuleProvider implements ICachingProviderService { static identifier = "my-cache" protected logger_: Logger protected options_: Options protected client constructor ( { logger, client }: InjectedDependencies, options: Options ) { this.logger_ = logger this.options_ = options // set the service's client to // the client from the container this.client = client } // ... } export default MyCachingModuleProvider ``` ### Identifier Every caching module provider must have an `identifier` static property. The provider's ID will be stored as `lp_{identifier}_{id}`, where `id` is the ID you set in your `medusa-config.ts` file. For example: ```ts class MyCachingModuleProvider implements ICachingProviderService { static identifier = "my-cache" // ... } ``` ### clear This method clears data from the cache. If no options are specified, all items matching the key or tags should be cleared. Otherwise, if `options.autoInvalidate` is `true`, only items that were set with `options.autoInvalidate: true` should be cleared. Items with `options.autoInvalidate: false` should only be cleared when no options are provided. If neither `key` nor `tags` are provided, nothing should be cleared. #### Example ```ts async clear({ key, tags, options, }: { key?: string; tags?: string[]; options?: { autoInvalidate?: boolean } }): Promise { if (!options) { // clear all items await this.client.invalidate({ key, tags }) } else if (options.autoInvalidate) { // clear only items with autoInvalidate option set to true const keysToDelete: string[] = [] const storedOptions = await this.client.get({ key, tags, pipeline: "options" }) storedOptions.forEach((item) => { if (item.autoInvalidate) { keysToDelete.push(item.key as string) } }) await this.client.invalidate({ keys: keysToDelete }) } } ``` #### Parameters #### Returns ### get This method retrieves data from the cache either by `key` or `tags`. If neither `key` nor `tags` are provided, `null` should be returned. If both `key` and `tags` are provided, `key` should take precedence over `tags`. #### Example ```ts class MyCachingModuleProvider implements ICachingProviderService { // ... async get({ key, tags }: { key?: string; tags?: string[] }): Promise { // Assuming you're using a client to get data if (key) { return await this.client.get({ key }) } if (tags) { return await this.client.getByTags({ tags }) } return null } } ``` #### Parameters #### Returns ### set This method stores data in the cache. It should also store the options with the item, allowing you to later to check the `autoInvalidate` option when clearing the item. #### Example ```ts class MyCachingModuleProvider implements ICachingProviderService { // ... async set({ key, data, ttl, tags, options }: { key: string; data: any; ttl?: number; tags?: string[]; options?: { autoInvalidate?: boolean } }): Promise { // Assuming you're using a client to set data await this.client.set({ key, data, ttl, tags }) await this.client.set({ key, data: options, pipeline: "options" }) } } ``` #### Parameters #### Returns --- ## 3. Create Module Definition File Create the file `src/modules/my-caching/index.ts` with the following content: ```ts title="src/modules/my-caching/index.ts" import { ModuleProvider, Modules } from "@medusajs/framework/utils" import MyCachingProviderService from "./service" export default ModuleProvider(Modules.CACHING, { services: [MyCachingProviderService], }) ``` This exports the module provider's definition, indicating that the `MyCachingProviderService` is the module provider's service. --- ## 4. Use Module Provider To use your Caching Module Provider, add it to the `providers` array of the Caching Module in `medusa-config.ts`: ```ts title="medusa-config.ts" module.exports = defineConfig({ // ... modules: [ { resolve: "@medusajs/medusa/caching", options: { providers: [ { // if module provider is in a plugin, use `plugin-name/providers/my-caching` resolve: "./src/modules/my-caching", id: "my-caching", // set this if you want this provider to be used by default // and you have other Caching Module Providers registered. is_default: true, options: { url: "http://example.com", // provider options... } }, ] } } ] }) ``` --- ## 5. Test it Out To test out your Caching Module Provider, create a simple API route that retrieves cached data with Query: ```ts title="src/api/test-caching/route.ts" import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http" export const GET = async (req: MedusaRequest, res: MedusaResponse) => { const query = req.scope.resolve("query") const { data } = await query.graph({ entity: "product", fields: ["id", "title"], }, { cache: { enable: true, providers: ["my-caching"], // use your provider id here } }) res.status(200).json({ data }) } ``` Then, start your Medusa server with the following command: ```bash npm2yarn npm run dev ``` Next, send a `GET` request to `http://localhost:9000/test-caching`: ```bash curl http://localhost:9000/test-caching ``` You will receive a response with the list of products. The first time you make this request, the products will be fetched from the database and cached in memory. Subsequent requests will retrieve the products from the cache, which improves performance. --- ## Useful Guides - [How to Use Caching Module](/references/caching-service)