# Streamline Your File Uploads with Cloudinary and NestJS

Cloudinary is a powerful serverless cloud-based storage infrastructure that allows easy file uploading for NestJS projects. In this article, we will explore the various methods of file uploading to Cloudinary and how to set it up in your NestJS project. Whether you are uploading file buffers, file URLs, or Base64 encoded strings, the Cloudinary NodeJS SDK and the steps outlined in this article make it easy to incorporate advanced file uploading into your NestJS project.

If you don't know how to handle file upload in NestJs, this [article](https://thecodeway.hashnode.dev/mastering-file-upload-and-validation-in-nestjs-with-multer) explains how to efficiently incorporate file upload and validation into your NestJS project.

## Creating a Cloudinary Module

One way to easily set it up in your NestJs projects is by creating a module for it. This allows you to use Dependency Injection design to use it in other providers or controllers.

**Installation**

Install Cloudinary NodeJs SDK

```bash
npm install cloudinary
```

Create a new module, `cloudinary`.

Create file `constants.ts`.

```typescript
export const CLOUDINARY = 'Cloudinary';
```

Add file `cloudinary.provider.ts`, paste the code below into the file.

```typescript

import { ConfigService } from '@nestjs/config';
import { v2 } from 'cloudinary';
import { CLOUDINARY } from './constants';

export const CloudinaryProvider = {
  provide: CLOUDINARY,
  useFactory: (config: ConfigService) => {
    return v2.config({
      cloud_name: config.get('CLOUDINARY_CLOUD_NAME'),
      api_key: config.get('CLOUDINARY_API_KEY'),
      api_secret: config.get('CLOUDINARY_API_SECRET'),
    });
  },
  inject: [ConfigService],
};
```

[ConfigService](https://docs.nestjs.com/techniques/configuration) is used to assess keys in your secret file. For example, a `.env` file.

Don't know how to set up env configurations in NestJs? [Read more](https://docs.nestjs.com/techniques/configuration).

Don't know how to create factory providers in NestJs? [Read more](https://docs.nestjs.com/fundamentals/custom-providers#factory-providers-usefactory).

The `CloudinaryProvider` provider is a Factory Provider. The `useFactory` allows you to create providers dynamically. You can also inject other module-imported services into the `useFactory` function.

**Create the Cloudinary Service Injectable**

Add a new file, `cloudinary.service.ts`

```typescript
import { Injectable } from '@nestjs/common';


@Injectable()
export class CloudinaryService {   
}
```

This service will contain methods for uploading files to Cloudinary.

**Create the module file**

Add a new file, `cloudinary.module.ts`

```typescript
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { CloudinaryProvider } from './cloudinary.provider';
import { CloudinaryService } from './cloudinary.service';

@Module({
    imports: [ConfigModule],
    providers: [CloudinaryProvider, CloudinaryService],
    exports: [CloudinaryProvider, CloudinaryService],
})
export class CloudinaryModule {}
```

The `ConfigModule` is added to the module imports because `ConfigService` in the `CloudinaryProvider`.

**Setup .env file**

Create a `.env` in your root folder. Depending on how you structure your project, a general root folder could be the folder containing your `package.json` file or where you run the command to start your server.

```plaintext
CLOUDINARY_CLOUD_NAME=test
CLOUDINARY_API_KEY=test
CLOUDINARY_API_SECRET=test
```

Now you need to [create a free Cloudinary account](https://cloudinary.com/documentation/how_to_integrate_cloudinary). After creating your account, you can follow this [guide](https://cloudinary.com/documentation/how_to_integrate_cloudinary#:~:text=during%20Q1%202023.-,Product%20Environment%20Credentials,-The%20Product%20Environment) to get your API key, secret and cloud name.

**Setup ConfigModule**

In your `app.module.ts` you will need to configure the `ConfigModule`. This makes sure it finds the `.env` file and populate itself with the keys and values, thereby making you access them with `ConfigService`.

```typescript
import {
  Module,
  NestModule,
} from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ConfigModule } from '@nestjs/config';

@Module({
  imports: [
    ConfigModule.forRoot(),
  ],
  controllers: [AppController],
  providers: [
    AppService,
  ],
})
export class AppModule implements NestModule {
}
```

## Using Form data - File Buffers

### Single File Upload

Now that you have your `CloudinaryService`. When you create a route that [accepts file buffers](https://thecodeway.hashnode.dev/mastering-file-upload-and-validation-in-nestjs-with-multer#heading-accepting-files) using Multer. You can upload this file using the service. You just have to integrate the upload method from the Cloudinary package.

Add the method below to your service.

```typescript
async uploadFile(
  file: Express.Multer.File,
): Promise<UploadApiResponse | UploadApiErrorResponse> {
  return new Promise((resolve, reject) => {
    v2.uploader.upload_stream(
      {
        resource_type: 'auto',
      },
      (error, result) => {
        if (error) return reject(error);
        resolve(result);
      }
    ).end(file.buffer)
  })
}
```

This simple method uses `v2.uploader.upload_stream` to upload your file to Cloudinary in chunks, which is good for uploading large files in chunks instead of one long request.

An `UploadApiResponse` or `UploadApiErrorResponse` is returned by the function. You can use this to know if the file was successfully uploaded or not.

To access your uploaded file URL, use the example of a route for single file upload below to understand the process.

```typescript
import { UploadedFile, UseInterceptors } from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';

@Post('upload/single')
@UseInterceptors(FileInterceptor('file'))
@ApiOkResponse({ description: 'Upload image', type: String })
public async uploadSingleImage(@UploadedFile() file: Express.Multer.File) {
  const result = await this.cloudinaryService.uploadFile(file);
  return result.secure_url;
}
```

The `secure_url` property is the URL for the file uploaded.

### Uploading multiple file buffers

Loop through all the files and upload each one after the other. The response is the list of secure URLs.

```typescript
async uploadFiles(
  files: Express.Multer.File[],
) {
  const urls = await Promise.all(files.map(async (file): Promise<string> => {
    const { secure_url } = await this.uploadFile(file);
    return secure_url;
  }));
  return urls
}
```

The files were [mapped over](https://www.w3schools.com/jsref/jsref_map.asp) and uploaded, and their URLs were returned by the [map callback function](https://www.w3schools.com/jsref/jsref_map.asp).

## Uploading File with URLs

What if you have a file URL and not a file buffer? It's simpler to upload that using Cloudinary.

```typescript
async uploadFileFromUrl(
  url: string,
): Promise<UploadApiResponse | UploadApiErrorResponse> {
  return v2.uploader.upload(url)
}
```

The URL passed to this would be uploaded to Cloudinary, which will then return a response containing the `secure_url` if successful.

### Uploading multiple file urls

By following the same idea from uploading multiple file buffers. You can map through the urls, upload each and return the `secure_url` for each. Then the function will return a list of URLs.

```typescript
async uploadFilesFromUrl(
  urls: string[],
) {
  return Promise.all(urls.map(async (url: string): Promise<string> => {
    const { secure_url } = await this.uploadFileFromUrl(url);
    return secure_url;
  }));
}
```

## Uploading Base64 encoded strings

Base64 is a binary-to-text encoding scheme that represents binary data in an American Standard Code for Information Interchange (ASCII) string format. An example of binary data is an image. Base64 can be uploaded too as a file, it's a string and not a buffer, which makes it easier to parse and upload to Cloudinary than file buffers.

By utilizing the `upload` function from the Cloudinary package, a base64 string can be uploaded to Cloudinary and get a URL for the uploaded file.

```typescript
async uploadFileFromBase64(
  data: string,
): Promise<UploadApiResponse | UploadApiErrorResponse> {
  return v2.uploader.upload(data)
}

async uploadManyBase64(
  files: string[],
) {
  const urls = await Promise.all(files.map(async (file): Promise<string> => {
    const { secure_url } = await this.uploadFileFromBase64(file);
    return secure_url;
  }));
  return urls
}
```

## Conclusion

In conclusion, Cloudinary is a powerful tool for file uploading and storage in NestJS projects. With the help of the Cloudinary NodeJS SDK and the steps outlined in this article, developers can easily set up a module for Cloudinary and upload files using various available methods including file buffers, file URLs, and Base64 encoded strings. While Cloudinary is free to set up initially, developers may need to pay for used services once they start using it past some limit.

I'd love to connect ❤️ with you on [**Twitter**](https://twitter.com/netrobeweb) | [**LinkedIn**](https://www.linkedin.com/in/ayomide-ayanwola/) | [**GitHub**](http://github.com/devvspaces) | [**Portfolio**](https://netrobe.vercel.app/)

See you in my next blog article. Take care!!!
