<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Çağatay Kaydır</title>
    <description>The latest articles on DEV Community by Çağatay Kaydır (@cugatay).</description>
    <link>https://dev.to/cugatay</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F715954%2Fc0e7fe24-24c1-44a0-ba9a-fd03d526d818.jpg</url>
      <title>DEV Community: Çağatay Kaydır</title>
      <link>https://dev.to/cugatay</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/cugatay"/>
    <language>en</language>
    <item>
      <title>7 Best Practices of File Upload With JavaScript &amp; React</title>
      <dc:creator>Çağatay Kaydır</dc:creator>
      <pubDate>Mon, 03 Mar 2025 17:26:08 +0000</pubDate>
      <link>https://dev.to/cugatay/7-best-practices-of-file-upload-with-typescript-react-5bbb</link>
      <guid>https://dev.to/cugatay/7-best-practices-of-file-upload-with-typescript-react-5bbb</guid>
      <description>&lt;p&gt;I've been working on StorageBowl, a modern all-in-one storage bucket that includes placeholder images, media streaming, shadcn-like components, and much more, for months now. As you can guess, it requires knowing the best practices for uploading functionalities. In one of my previous blogs, I said "Uploading functionality is not a one-time to-do list, it's recursive. You'll need to come again and again throughout scaling your app to meet your needs" One thing I can do to help you to come back less is to give you real actionable best practices, including codes below. Following these practices will increase the performance of your websites and the speed of your uploading functionality in an instant, only by copying &amp;amp; pasting the example codes I give.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Before we start, StorageBowl is giving up to 100GB of free storage for life! We gifted a terabyte of storage already to lots of our users, so get yours or see how much storage we gifted at &lt;a href="https://storagebowl.net" rel="noopener noreferrer"&gt;https://storagebowl.net&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  1. Optimize Your Images
&lt;/h2&gt;

&lt;p&gt;One important thing to remember when building an uploading functionality is that users don't care about image formats. They don't even know the differences between various image extensions. Poorly optimized files not only result in a higher bill but also greatly reduce your site's performance, so you'll need to fix your users' ignorance. Think about these two when you fix it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;What will be the image size/sizes you'll use in your application?&lt;/strong&gt; If it's a profile image for example, what is the biggest size you'll use in your app?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Which image format will work best for you?&lt;/strong&gt; The answer will almost always be WebP since it's supported in almost every browser, encodes images efficiently resulting in smaller file sizes, and supports alpha channel (which means that it supports transparent images too).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you're writing in JavaScript, you can optimize images using sharp, an npm package for image processing. Here's a small code snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;optimizedImage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;sharp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resize&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;kernel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;sharp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;kernel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nearest&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="c1"&gt;// Max size that I'll use for a profile picture&lt;/span&gt;
 &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name.webp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Saves image. If you don't want to save, use toBuffer() instead&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But 2 important notes here:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Even though the sharp package is written astonishingly, JavaScript is not the most efficient language you can use for image processing.&lt;/li&gt;
&lt;li&gt;Optimizing images on the client side before sending them to your backend and checking if they're optimized on the backend is much more efficient than doing optimization on your backend. It decreases bandwidth usage, upload times, and needed processing power on your backend.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;StorageBowl provides ready-to-use components that include WebAssembly written in Rust to ensure the best efficiency.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Set Boundaries
&lt;/h2&gt;

&lt;p&gt;This is a well-known one. However, people sometimes implement it poorly. Don't forget to check properties like min and max size, width and height, file count, file formats, etc.&lt;br&gt;
Sharp provides a solution for this one too:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;metadata&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;sharp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
 &lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hasAlpha&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;File doesn't match the requirements&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Metadata has lots of properties you can use alongside &lt;code&gt;hasAlpha&lt;/code&gt;, &lt;code&gt;width&lt;/code&gt;, and &lt;code&gt;height&lt;/code&gt;. It's full of stuff, isn't it? But the same note is valid here too: JavaScript might not be an effective solution when you need performance to scale up.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Use Placeholders
&lt;/h2&gt;

&lt;p&gt;One of the best solutions to make your website faster is to use placeholder images. There is more than one solution to create placeholders: 16x16 blurry WebP, BlurHash, and ThumbHash are the usual suspects. I can write a blog covering the advantages of each one. Let me know in the comments if you want it. However, to avoid getting off-topic, I'll just cover ThumbHash.&lt;/p&gt;

&lt;p&gt;ThumbHash is one of the most effective algorithms to generate hash strings of blurred images. To put it more simply, it takes your image and turns it into a string, and you can use this string as a blurred placeholder using ThumbHash's converter. This solution results in a smaller binary size than you could have with resizing images.&lt;/p&gt;

&lt;p&gt;To learn how to use ThumbHash, you can visit its &lt;a href="https://github.com/evanw/thumbhash" rel="noopener noreferrer"&gt;GitHub page&lt;/a&gt; or you can take a look at some examples &lt;a href="https://evanw.github.io/thumbhash/" rel="noopener noreferrer"&gt;here&lt;/a&gt;. ThumbHash is available in Rust, Swift, and Java as well as JavaScript.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Empower Users
&lt;/h2&gt;

&lt;p&gt;You can help users, and they can help you back. Using tools like cropping lets users have a better experience when they choose an image and, at the same time allows you to store these images in smaller spaces.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Send Before Pressing Send
&lt;/h2&gt;

&lt;p&gt;This is one of the oldest tricks in the book and feels like playing mind games to your users. So, this one is cool, but again, it's not like we've discovered quantum mechanics. When users finish selecting a picture, you don't need to wait for them to press send, you already have the information you need. Use onChange to trigger a pre-upload function, and when a user presses the send button, you then validate these files. This one is a bit tricky on the setup process, you'll need endpoints to upload unvalidated files, you'll need to validate these files when the user presses the send button, and you'll also need to delete the ones that aren't validated. While being tricky, providing this on StorageBowl for our users increased their website efficiency significantly.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Upload in Parallel
&lt;/h2&gt;

&lt;p&gt;This will increase your uploading speed a lot. JavaScript has a parallel promise support, meaning that you'll increase efficiency without any trouble. Here's an example to upload in parallel:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;inputElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Assume 5 files are selected&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;uploadPromises&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;formData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FormData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
 &lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;file&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;uploadPromise&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/upload-endpoint&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="p"&gt;});&lt;/span&gt;
 &lt;span class="nx"&gt;uploadPromises&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;uploadPromise&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;responses&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;uploadPromises&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
 &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;All files uploaded successfully&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Uploading failed:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It seems okay, isn't it? But to make this step much more efficient, we'll combine it with the next one.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Slice Big Files
&lt;/h2&gt;

&lt;p&gt;Just like arrays, JavaScript file blobs have a &lt;code&gt;slice(start, end)&lt;/code&gt; function. Look at the metadata of each file, if any one of them is larger than, let's say 20MB, slice that into smaller ones and add it to your files array with a name "${bigFileName}-chunk-${number}". Combining this with the previous step will increase the speed of upload significantly for any kind of file, of any size. Trust me, your users will notice it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Uploading is a deep topic that has been around for decades. It was an important problem to fix for early computing, and it still is for any kind of application to keep users engaged without losing interest. The goal of this blog was to provide real actionable steps to increase performance. All other blogs I saw were either too beginner-focused or didn't provide actionable steps with code you could copy. Even though I believe I achieved my goal, this is still just the infancy steps of an efficient uploading functionality. You'll need a flexible structure to meet users' needs, a streaming infrastructure, a CDN, and more. If you don't want to spend lots of time creating a fast uploading functionality, check out StorageBowl. It has many tools for many languages and is focused on uploading and storing your files as efficiently as possible. Check it out to get your 100GB of free storage today.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>node</category>
      <category>architecture</category>
    </item>
    <item>
      <title>A Passion for Recreating Storage Buckets</title>
      <dc:creator>Çağatay Kaydır</dc:creator>
      <pubDate>Fri, 28 Feb 2025 15:45:56 +0000</pubDate>
      <link>https://dev.to/cugatay/a-passion-for-recreating-storage-buckets-3i3a</link>
      <guid>https://dev.to/cugatay/a-passion-for-recreating-storage-buckets-3i3a</guid>
      <description>&lt;p&gt;I always hear people say: “Reinventing the wheel is a bad, really bad idea” But the truth is, reinventing has grown me up as an engineer, taught me engineering in the first place, and more importantly, helped me love engineering again in tough times. It was a priceless gift that I forgot along the way, and got back when I decided to reinvent some wheels. After wrestling with Bluetooth and a JPEG algorithm, I decided to dive deep into modern storage buckets, and that’s what I’ve been doing for the last 4 months: A storage bucket for the 21st century: StorageBowl, sounds cool right? I thought sharing a vision for a modern way of handling media could be useful to anyone, whether one uses the thing I built or not. So, it would be a sin not to write about it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Before we start, this is the only promotion you’ll see here: StorageBowl is open and gives up to 100GB of free storage away for a lifetime. The number of people we gave storage became way more than I could even dream of, even before I finished writing this blog. We gifted almost a terabyte of free space! So I’ll have to close this system soon. Get your free storage, or see how much storage we gifted to people at &lt;a href="https://storagebowl.com" rel="noopener noreferrer"&gt;https://storagebowl.com&lt;/a&gt;!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What’s Wrong With Storage Buckets
&lt;/h2&gt;

&lt;p&gt;Actually, nothing! Modern storage buckets are capable enough to let you implement any feature you want. However, the problem itself lies in the process of implementation. The problematic nature of maintaining an upload functionality is that it’s easy to cut corners in the beginning, but becomes rough to keep it functional as you scale and gain real users. The evidence of this is that every team I’ve worked in has gone through the same cycle of iterations as the application scaled up:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Let’s implement a basic upload functionality!&lt;/li&gt;
&lt;li&gt;Users start requesting some basic features like cropping and focusing only on a part of their pictures.

&lt;ul&gt;
&lt;li&gt;Nudge the designer.&lt;/li&gt;
&lt;li&gt;Backend starts implementing the functionality using a JavaScript library, not without digging a grave for performance.&lt;/li&gt;
&lt;li&gt;Frontend brings these features to life using these designs and endpoints.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Product manager asks why our homepage takes a whole goddamn 15 secs to load. You decide to implement a placeholder mechanism and run it on the images people already uploaded. A few workweeks later, you’re good to go!&lt;/li&gt;

&lt;li&gt;Boss says he’ll fire you if you can’t fix the 8k storage bill. You know he’s serious this time after some guy convinced him to switch from good old servers to edge functions, costing 15k+ bill. You write an image optimization function in Rust because turns out JavaScript wasn’t a good choice for image processing. But this led to a salary increase for genius Tom, since he is the only one with Rust experience.&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;This process is a loop that introduces many problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each iteration cycle blocks multiple teams (backend, UI/UX, etc.) simultaneously.&lt;/li&gt;
&lt;li&gt;It becomes a burden to maintain some parts of your code, think about what happens when Tom leaves the company.&lt;/li&gt;
&lt;li&gt;Uploading is not a one-step process. Over time, you notice that it is only a step of this pipeline:

&lt;ul&gt;
&lt;li&gt;Upload: Implement helper tools, and reimplement them for mobile again.&lt;/li&gt;
&lt;li&gt;Store: Create optimization middlewares for best performance and lowest cost, check for malware, and check for prohibited content.&lt;/li&gt;
&lt;li&gt;Send back: Create placeholder images, stream video and audio if necessary, protect your media from unauthorized access, and make sure the optimizations are enough so your app loads fast.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;The only solution to this endless loop of improvement cycles is having a team that predicts future needs, and one that never cuts corners. This is impossible, or at least too hard in a world where human beings are neither perfect nor seek perfection at work, since in many places unfortunately finishing a feature seemingly fast and coming back many times makes people received as smarter than finishing it once and for good. The only way to fix this humane flaw is to agree with Andrew Kelley: Make the lazy way the right way, so we programmers will do it correctly on the first try.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Did I Fix It?
&lt;/h2&gt;

&lt;p&gt;So, this is the vision for StorageBowl: Making the lazy way the right way. The only solution to provide a lazy way that fixes uploading flaws is making the product itself focused on uploading solutions itself! This way, cutting corners would mean under-delivering to customers, which makes it unacceptable instantly.&lt;/p&gt;

&lt;p&gt;So let’s talk about the three pillars of my vision for easy and flawless file storage:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Toggle a Switch Instead of Week-Long Huddles
&lt;/h3&gt;

&lt;p&gt;I know, this smacks too much of copywriting. But it’s the only way to describe it. Instead of creating configuration files, StorageBowl provides a simple interface where you choose the features you want to enable. This way, you can implement any feature without writing a dime of code. If you enable streaming, then your video component will get your video as a stream, simple, isn’t it? This is the modern way of storage, and it’s a philosophical difference from any other storage provider that enables scaling and adding new features to StorageBowl, without anything new to learn, just toggle!&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Folders are All You Need
&lt;/h3&gt;

&lt;p&gt;A folder, that’s right. Just like you don’t put a PDF file in your travel photos folder, in your app you don’t put an audio in your profile-photos folder. So in every storage bucket, folder structure is the main tool for organization. It was nothing more than a naming tool before, but in StorageBowl you organize your whole media requirements only using folders. Think about the profile-photo example. You want it to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Accept only common image formats.&lt;/li&gt;
&lt;li&gt;Optimize and compress the image down for 32x32 size, if that’s the max size you specified for your avatar component.&lt;/li&gt;
&lt;li&gt;Enable placeholder images, you can even choose between showing a blurred version of the whole image or just a predefined image for your avatars!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You achieve these needs when you create the folder: Click create and choose your whips.&lt;/p&gt;

&lt;p&gt;One important thing to notice is that when the product itself becomes the solution to this single task, it becomes flexible like a Lego brick. For example: At some point, if you change your mind and decide to use blurry images instead of a pre-defined one, you’d need to go through all of your files to create blurry hashes. But with StorageBowl, it’s just a toggle! The same thing is valid for each use case. You don’t need to write any more code if you change your mind at some point. This is the flexibility we aimed for when we decided to fix this problem.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. A Powerful, Doughy Foundation
&lt;/h3&gt;

&lt;p&gt;StorageBowl uses the most flexible structure possible, and that’s the main pillarstone of the project. I call it the Doughy Foundation. This means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can integrate StorageBowl to any backend with any language out there. It’s designed in a way that’s so flexible that even building tools for different languages to help you build applications took minimal effort.&lt;/li&gt;
&lt;li&gt;Components are designed in a Shadcn-like fashion, meaning you have your components as if you’ve written them. This not only makes customization possible but makes it as if you had written it down to every pixel already.&lt;/li&gt;
&lt;li&gt;The tools are developed in a way to understand the tech stack you use for your projects. e.g. If you use React with Tailwind, you’ll automatically have components that are adapted for them. If you use plain CSS, you don’t have to follow any more steps, when you install a component it’ll automatically detect this and be installed accordingly.&lt;/li&gt;
&lt;li&gt;This flexibility made multi-platform support possible. Besides, you can adapt it to any backend language and framework you might use, StorageBowl currently supports React &amp;amp; React Native with Vite, NextJS, and Expo; and I’m extending its reach to even Flutter! I’ll continue to extend it even further to be usable with any technology you can imagine soon. This makes writing a full-fledged family of applications possible, using the same technology for any platform and device.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These were the three most important topics I wanted to improve for developers, and I hope to continue doing a meaningful job for people who like the process of building just for the sake of creation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;At the end of the day, creating StorageBowl was a huge fun and it’s becoming a success as we can see the number of free storage we’ve given/are still giving is beyond my best guesses!&lt;/p&gt;

&lt;p&gt;I must say that building the things you’re passionate about is important, and reinventing the wheel is so much fun! If you love the building part of programming, please don’t deprive yourself of it like I did for quite some time. Trust me, my friend, it gets depressing as hell. Starting this project was an escape from many things to me, and it felt like the water of life. I hope you find your passion. And of course, if your passion requires a storage option, Better Call Bowl!&lt;/p&gt;

</description>
      <category>bucket</category>
      <category>webdev</category>
      <category>storage</category>
    </item>
  </channel>
</rss>
