The only real free external media storage you'll need!
Zyrianov Viacheslav
Posted on December 19, 2023
The problem
I have Nuxt3/ExpressJS project. I need to store images somewhere. I had two options:
- 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 💩
- 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:
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.
- Create an
input
withtype="file"
, for it to accept files. - Add handler, that will create
new FormData()
and append image frominput
into newly createdFormData
. To get image frominput
you can simply doconst [file] = fileInput.target.files
, checks and validations are on your own for now. - Send it to your api.
Server side
Now more interesting part, how do we send and store image to imagekit.io from node?
- Install package express-fileupload That will allow us to work with a bit more comfortable.
- Do
const fileUpload = require('express-fileupload')
in your main file, it'sapp.js
by default. - Add
app.use(fileUpload())
below. - Install package imagekit
-
Create in your
/utils
folder (or anywhere, but I would recommend this approach) fileimagekit.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 })
If you use another framework or library, check page https://imagekit.io/dashboard/developer/api-keys for another configurations.
In your controllers, import that imagekit by doing
const imagekit = require('../utils/imagekit')
-
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).
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.-
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)
-
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 :)
Posted on December 19, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.