DEV Community

Zyrianov Viacheslav
Zyrianov Viacheslav

Posted on

The only real free external media storage you'll need!

The problem

I have Nuxt3/ExpressJS project. I need to store images somewhere. I had two options:

  1. Store as Base64 in my SQL database. Pros - no external storage, cons - storing Base64 in SQL isn't quite a good practice :D And if I do like that, I will have to compress my images on client side to, let's say, 128kb max. That will cause images to look like, you know 💩
  2. Use external storage. Pros - images will be perfect, plus these storages often give you some optimization on your images and thumbnails and more cool stuff. Cons - most of them are paid. So after few hours of investigation and work, I've decided to share with you my experience about implementing external media storage for my app. Spoiler - it's free :)

What to choose?

I've browser through some of them and imagekit.io grabbed my attention. There was the most free gigabytes of media storage (20GB at the moment) so I've decided to try out that one.

Implementation

First of what i want to say - docs are amazingly understandable. They have SDKs for all popular frameworks and libraries:
Image description
I've encountered lots of docs and the were not so good, haha. So, where from do we start?

Client side

That would be quite easy and nothing special if you've worked with images and FormData before, but I still gonna wrap it up.

  1. Create an input with type="file", for it to accept files.
  2. Add handler, that will create new FormData() and append image from input into newly created FormData. To get image from input you can simply do const [file] = fileInput.target.files, checks and validations are on your own for now.
  3. Send it to your api.

Server side

Now more interesting part, how do we send and store image to imagekit.io from node?

  1. Install package express-fileupload That will allow us to work with a bit more comfortable.
  2. Do const fileUpload = require('express-fileupload') in your main file, it's app.js by default.
  3. Add app.use(fileUpload()) below.
  4. Install package imagekit
  5. Create in your /utils folder (or anywhere, but I would recommend this approach) file imagekit.js with basic configuration for our imagekit:

    const ImageKit = require('imagekit')
    
    module.exports = new ImageKit({
      publicKey: process.env.IMAGEKIT_PUBLIC_KEY,
      privateKey: process.env.IMAGEKIT_PRIVATE_KEY,
      urlEndpoint: process.env.IMAGEKIT_URL_ENDPOINT
    })
    
  6. If you use another framework or library, check page https://imagekit.io/dashboard/developer/api-keys for another configurations.

  7. In your controllers, import that imagekit by doing const imagekit = require('../utils/imagekit')

  8. I've wrote very basic snippet, that's responsible for uploading files to imagekit and returns Promise. It looks like that:

    const uploadImageToStorage = (file, params) => {
      const uploadOptions = {
        file: file.data,
        fileName: file.name,
        ...params
    }
      return imagekit.upload(uploadOptions)
        .then(response => response)
        .catch(error => error)
    }
    

    You can write it in utils and import it to any controller file where you need to upload files, but I've temporarily wrote it right inside controller file (not good, gonna fix it later).

  9. Now use that snippet! But how? As you see, i have params in my snippet. I won't write about all parameters imagekit provides, for now I've needed only one - folder.

    For now, I've decided to store images structured by folders with user id. How to do it? Easy.

  10. I've created params object:

    const uploadImageParams = {
      folder: `user-${user.id}`
    }
    

    And made a variable with result of uploading that file:
    const uploadedImageResult = await uploadImageToStorage(req.files.image, uploadImageParams)

  11. If your request succeeded, it will return object that looks like this:

    {
      fileId: '6581e02044c257da433888de',
      name: 'somefilename.jpg',
      size: 2508483,
      versionInfo: { id: '6581e02044c257da433888de', name: 'Version 1' },
      filePath: '/user-3/somefilename.jpg',
      url: 'https://ik.imagekit.io/${storageName}/user-3/somefilename.jpg',
      fileType: 'image',
      height: 1560,
      width: 1302,
      thumbnailUrl: 'https://ik.imagekit.io/leera/tr:n-ik_ml_thumbnail/user-3/somefilename.jpg'',
      AITags: null
    }
    

The most needed basic props we need from here are url and thumbnailUrl to display image on client side.

Conclusion

Definitely one of the most comfortable and easy-to-use bucket for files, very friendly DX and tons of free features.

P.S.

Also it can add tags to your images, optimize 'em, connect external buckets (like AWS, etc.) and do lots of custom stuff.

I hope you will find it useful and will never struggle in searching for free image storage again :)

Top comments (0)