In this document, you’ll learn how to create a File Module Provider and the methods you must implement in its main service.
As you implement your File 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 S3 File Module Provider in the Medusa repository.
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-file
.
If you're creating the module provider in a plugin, create it under the src/providers
directory. For example, src/providers/my-file
.
src/modules/my-file
directory as an example.Create the file src/modules/my-file/service.ts
that holds the implementation of the module provider's main service. It must extend the AbstractFileProviderService
class imported from @medusajs/framework/utils
:
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 the constructor.
1import { Logger } from "@medusajs/framework/types"2import { AbstractFileProviderService } from "@medusajs/framework/utils"3 4type InjectedDependencies = {5 logger: Logger6}7 8type Options = {9 apiKey: string10}11 12class MyFileProviderService extends AbstractFileProviderService {13 protected logger_: Logger14 protected options_: Options15 static identifier = "my-file"16 // assuming you're initializing a client17 protected client18 19 constructor (20 { logger }: InjectedDependencies,21 options: Options22 ) {23 super()24 25 this.logger_ = logger26 this.options_ = options27 28 // assuming you're initializing a client29 this.client = new Client(options)30 }31}32 33export default MyFileProviderService
Each file provider has a unique ID used to identify it. The provider's ID
will be stored as fs_{identifier}_{id}
, where {id}
is the provider's id
property in the medusa-config.ts
.
This method deletes the file from storage. It's used when an admin user deletes a product image, or other custom file deletions.
1class MyFileProviderService extends AbstractFileProviderService {2 // ...3 async delete(file: ProviderDeleteFileDTO): Promise<void> {4 // TODO logic to remove the file from storage5 // Use the `file.fileKey` to delete the file, which is the identifier of the file6 // in the provider's storage.7 // for example:8 this.client.delete(file.fileKey)9 }10}
Promise
Promise<void>This method retrieves an uploaded file as a buffer. This is useful when you want to process the entire file in memory or send it as a response.
v2.8.0
.1class MyFileProviderService extends AbstractFileProviderService {2 // ...3 async getAsBuffer(file: ProviderDeleteFileDTO): Promise<Buffer> {4 // TODO logic to get the file as a buffer5 // Use the `file.fileKey` to get the file, which is the identifier of the file6 // in the provider's storage.7 // for example:8 this.client.getAsBuffer(file.fileKey)9 }10}
fileData
ProviderGetFileDTOPromise
Promise<Buffer>This method retrieves an uploaded file as a stream. This is useful when streaming a file to clients or you want to process the file in chunks.
v2.8.0
.1class MyFileProviderService extends AbstractFileProviderService {2 // ...3 async getAsStream(file: ProviderDeleteFileDTO): Promise<Readable> {4 // TODO logic to get the file as a stream5 // Use the `file.fileKey` to get the file, which is the identifier of the file6 // in the provider's storage.7 // for example:8 this.client.getAsStream(file.fileKey)9 }10}
fileData
ProviderGetFileDTOPromise
Promise<Readable>This method is used to retrieve a download URL of the file. For some providers, such as S3, a presigned URL indicates a temporary URL to get access to a file.
If your provider doesn’t perform or offer a similar functionality, you can return the URL to download the file.
1class MyFileProviderService extends AbstractFileProviderService {2 // ...3 async getPresignedDownloadUrl(4 fileData: ProviderGetFileDTO5 ): Promise<string> {6 // TODO logic to get the presigned URL7 // Use the `file.fileKey` to delete the file, which is the identifier of the file8 // in the provider's storage.9 // for example:10 return this.client.getPresignedUrl(fileData.fileKey)11 }12}
fileData
ProviderGetFileDTOPromise
Promise<string>This method is used to get a presigned upload URL for a file. For some providers, such as S3, a presigned URL indicates a temporary URL to get upload a file.
If your provider doesn’t perform or offer a similar functionality, you don't have to implement this method. Instead, an error is thrown when the method is called.
1class MyFileProviderService extends AbstractFileProviderService {2 // ...3 async getPresignedUploadUrl(4 fileData: ProviderGetPresignedUploadUrlDTO5 ): Promise<ProviderFileResultDTO> {6 // TODO logic to get the presigned upload URL7 // for example:8 return this.client.getPresignedUploadUrl(fileData.filename, fileData.mimeType)9 }10}
fileData
ProviderGetPresignedUploadUrlDTOPromise
Promise<ProviderFileResultDTO>This method uploads a file using your provider's custom logic. In this method, you can upload the file into your provider's storage, and return the uploaded file's details.
This method will be used when uploading product images, CSV files for imports, or other custom file uploads.
1class MyFileProviderService extends AbstractFileProviderService {2 // ...3 async upload(4 file: ProviderUploadFileDTO5 ): Promise<ProviderFileResultDTO> {6 // TODO upload file to third-party provider7 // or using custom logic8 // for example:9 this.client.upload(file)10 11 return {12 url: "some-url.com",13 key: "file-name-or-id"14 }15 }16}
Promise
Promise<ProviderFileResultDTO>This method validates the options of the provider set in medusa-config.ts
.
Implementing this method is optional. It's useful if your provider requires custom validation.
If the options aren't valid, throw an error.
options
Record<any, any>Create the file src/modules/my-file/index.ts
with the following content:
This exports the module provider's definition, indicating that the MyFileProviderService
is the module provider's service.
To use your File Module Provider, add it to the providers
array of the File Module in medusa-config.ts
:
1module.exports = defineConfig({2 // ...3 modules: [4 {5 resolve: "@medusajs/medusa/file",6 options: {7 providers: [8 // default provider9 {10 resolve: "@medusajs/medusa/file-local",11 id: "local",12 },13 {14 // if module provider is in a plugin, use `plugin-name/providers/my-file`15 resolve: "./src/modules/my-file",16 id: "my-file",17 options: {18 // provider options...19 },20 },21 ],22 },23 },24 ]25})
To test out your File Module Provider, use the Medusa Admin or the Upload API route to upload a file.