---
slug: /references/file-provider-module
---

import { TypeList } from "docs-ui"

# How to Create a File Provider Module

In this document, you’ll learn how to create a file provider module and the methods you must implement in its main service.

---

## 1. Create Module Directory

Start by creating a new directory for your module. For example, `src/modules/my-file`.

---

## 2. Create the File Provider Service

Create the file `src/modules/my-file/service.ts` that holds the implementation of the module's main service. It must extend the `AbstractFileProviderService` class imported from `@medusajs/framework/utils`:

```ts title="src/modules/my-file/service.ts"
import { AbstractFileProviderService } from "@medusajs/framework/utils"

class MyFileProviderService extends AbstractFileProviderService {
  // TODO implement methods
}

export default MyFileProviderService
```

### 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 the constructor.

#### Example

```ts
import { Logger } from "@medusajs/framework/types"
import { AbstractFileProviderService } from "@medusajs/framework/utils"

type InjectedDependencies = {
  logger: Logger
}

type Options = {
  apiKey: string
}

class MyFileProviderService extends AbstractFileProviderService {
  protected logger_: Logger
  protected options_: Options
  static identifier = "my-file"
  // assuming you're initializing a client
  protected client

  constructor (
    { logger }: InjectedDependencies,
    options: Options
  ) {
    super()

    this.logger_ = logger
    this.options_ = options

    // assuming you're initializing a client
    this.client = new Client(options)
  }
}

export default MyFileProviderService
```

### identifier

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`.

#### Example

```ts
class MyFileProviderService extends AbstractFileProviderService {
  static identifier = "my-file"
  // ...
}
```

### validateOptions

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.

#### Example

```ts
class MyFileProviderService extends AbstractFileProviderService {
  static validateOptions(options: Record<any, any>) {
    if (!options.apiKey) {
      throw new MedusaError(
        MedusaError.Types.INVALID_DATA,
        "API key is required in the provider's options."
      )
    }
  }
}
```

#### Parameters

<TypeList types={[{"name":"options","type":"`Record<any, any>`","description":"The provider's options.","optional":false,"defaultValue":"","expandable":false,"children":[]}]} expandUrl="https://docs.medusajs.com/learn/fundamentals/data-models/manage-relationships#retrieve-records-of-relation" sectionTitle="validateOptions"/>

### upload

This method uploads a file using your provider's custom logic.

#### Example

```ts
class MyFileProviderService extends AbstractFileProviderService {
  // ...
  async upload(
    file: ProviderUploadFileDTO
  ): Promise<ProviderFileResultDTO> {
    // TODO upload file to third-party provider
    // or using custom logic

    return {
      url: "some-url.com",
      key: "file-name"
    }
  }
}
```

#### Parameters

<TypeList types={[{"name":"file","type":"[ProviderUploadFileDTO](../../../types/FileTypes/interfaces/types.FileTypes.ProviderUploadFileDTO/page.mdx)","description":"The file to upload","optional":false,"defaultValue":"","expandable":false,"children":[{"name":"filename","type":"`string`","description":"The filename of the uploaded file","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"mimeType","type":"`string`","description":"The mimetype of the uploaded file","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"content","type":"`string`","description":"The file content as a binary-encoded string","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"access","type":"`\"public\"` \\| `\"private\"`","description":"The access level of the file. Defaults to private if not passed","optional":true,"defaultValue":"","expandable":false,"children":[]}]}]} expandUrl="https://docs.medusajs.com/learn/fundamentals/data-models/manage-relationships#retrieve-records-of-relation" sectionTitle="upload"/>

#### Returns

<TypeList types={[{"name":"Promise","type":"Promise&#60;[ProviderFileResultDTO](../../../types/FileTypes/interfaces/types.FileTypes.ProviderFileResultDTO/page.mdx)&#62;","optional":false,"defaultValue":"","description":"The uploaded file's details.","expandable":false,"children":[{"name":"ProviderFileResultDTO","type":"[ProviderFileResultDTO](../../../types/FileTypes/interfaces/types.FileTypes.ProviderFileResultDTO/page.mdx)","optional":false,"defaultValue":"","description":"","expandable":false,"children":[{"name":"url","type":"`string`","description":"The file's URL.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"key","type":"`string`","description":"The file's key.","optional":false,"defaultValue":"","expandable":false,"children":[]}]}]}]} expandUrl="https://docs.medusajs.com/learn/fundamentals/data-models/manage-relationships#retrieve-records-of-relation" sectionTitle="upload"/>

### delete

This method deletes the file from storage.

#### Example

```ts
class MyFileProviderService extends AbstractFileProviderService {
  // ...
  async delete(file: ProviderDeleteFileDTO): Promise<void> {
    // TODO logic to remove the file from storage
    // Use the `file.fileKey` to delete the file
    // for example:
    this.client.delete(file.fileKey)
  }
}
```

#### Parameters

<TypeList types={[{"name":"file","type":"[ProviderDeleteFileDTO](../../../types/FileTypes/interfaces/types.FileTypes.ProviderDeleteFileDTO/page.mdx)","description":"The details of the file to delete.","optional":false,"defaultValue":"","expandable":false,"children":[{"name":"fileKey","type":"`string`","description":"The file's key. When uploading a file, the\nreturned key is used here.","optional":false,"defaultValue":"","expandable":false,"children":[]}]}]} expandUrl="https://docs.medusajs.com/learn/fundamentals/data-models/manage-relationships#retrieve-records-of-relation" sectionTitle="delete"/>

#### Returns

<TypeList types={[{"name":"Promise","type":"Promise&#60;void&#62;","optional":false,"defaultValue":"","description":"Resolves when the file is deleted.","expandable":false,"children":[]}]} expandUrl="https://docs.medusajs.com/learn/fundamentals/data-models/manage-relationships#retrieve-records-of-relation" sectionTitle="delete"/>

### getPresignedDownloadUrl

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.

#### Example

```ts
class MyFileProviderService extends AbstractFileProviderService {
  // ...
  async getPresignedDownloadUrl(
    fileData: ProviderGetFileDTO
  ): Promise<string> {
    // TODO logic to get the presigned URL
    // Use the `file.fileKey` to delete the file
    // for example:
    return this.client.getPresignedUrl(fileData.fileKey)
  }
}
```

#### Parameters

<TypeList types={[{"name":"fileData","type":"[ProviderGetFileDTO](../../../types/FileTypes/interfaces/types.FileTypes.ProviderGetFileDTO/page.mdx)","description":"The details of the file to get its\npresigned URL.","optional":false,"defaultValue":"","expandable":false,"children":[{"name":"fileKey","type":"`string`","description":"The file's key.","optional":false,"defaultValue":"","expandable":false,"children":[]}]}]} expandUrl="https://docs.medusajs.com/learn/fundamentals/data-models/manage-relationships#retrieve-records-of-relation" sectionTitle="getPresignedDownloadUrl"/>

#### Returns

<TypeList types={[{"name":"Promise","type":"Promise&#60;string&#62;","optional":false,"defaultValue":"","description":"The file's presigned URL.","expandable":false,"children":[{"name":"string","type":"`string`","optional":false,"defaultValue":"","description":"","expandable":false,"children":[]}]}]} expandUrl="https://docs.medusajs.com/learn/fundamentals/data-models/manage-relationships#retrieve-records-of-relation" sectionTitle="getPresignedDownloadUrl"/>

---

## 3. Create Module Definition File

Create the file `src/modules/my-file/index.ts` with the following content:

```ts title="src/modules/my-file/index.ts"
import MyFileProviderService from "./service"
import { 
  ModuleProvider, 
  Modules
} from "@medusajs/framework/utils"

export default ModuleProvider(Modules.FILE, {
  services: [MyFileProviderService],
})
```

This exports the module's definition, indicating that the `MyFileProviderService` is the module's service.

---

## 4. Use Module

To use your File Module Provider, add it to the `providers` array of the File Module in `medusa-config.ts`:

<Note>

The File Module accepts one provider only.

</Note>

```ts title="medusa-config.ts"
module.exports = defineConfig({
  // ...
  modules: [
    {
      resolve: "@medusajs/medusa/file",
      options: {
        providers: [
          // default provider
          {
            resolve: "@medusajs/medusa/file-local",
            id: "local",
          },
          {
            resolve: "./src/modules/my-file",
            id: "my-file",
            options: {
              // provider options...
            },
          },
        ],
      },
    },
  ]
})
```

---

## 5. Test it Out

To test out your file provider, use the Medusa Admin or the [Upload API route](https://docs.medusajs.com/v2/api/admin#uploads_postuploads) to upload a file.
