<?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: Roman Klymenko</title>
    <description>The latest articles on DEV Community by Roman Klymenko (@roman_klymenko_39f1198f16).</description>
    <link>https://dev.to/roman_klymenko_39f1198f16</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3726667%2Fe91ee531-7201-4095-8c61-156baa96484b.png</url>
      <title>DEV Community: Roman Klymenko</title>
      <link>https://dev.to/roman_klymenko_39f1198f16</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/roman_klymenko_39f1198f16"/>
    <language>en</language>
    <item>
      <title>Node.js Image Compression: A Complete API Integration Guide</title>
      <dc:creator>Roman Klymenko</dc:creator>
      <pubDate>Tue, 28 Jul 2026 12:31:04 +0000</pubDate>
      <link>https://dev.to/roman_klymenko_39f1198f16/nodejs-image-compression-a-complete-api-integration-guide-2843</link>
      <guid>https://dev.to/roman_klymenko_39f1198f16/nodejs-image-compression-a-complete-api-integration-guide-2843</guid>
      <description>&lt;p&gt;Tired of bloated images slowing down your app? Let's fix that with &lt;strong&gt;Node.js image compression&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Every KB counts. Uncompressed images can drain bandwidth and kill user experience. An effective &lt;strong&gt;image compression API&lt;/strong&gt; solves this instantly—compress images up to 90% without quality loss.&lt;/p&gt;

&lt;p&gt;Here's how to set up image compression in Node.js using a REST API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;axios&lt;/span&gt;&lt;span class="dl"&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;fs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;compressImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;imagePath&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;imageBuffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;imagePath&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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
 &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.pixozip.com/compress&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="nx"&gt;imageBuffer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;image/jpeg&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="p"&gt;);&lt;/span&gt;

 &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;compressed.jpg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&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;Image compressed 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="nf"&gt;compressImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./photo.jpg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;90% compression&lt;/strong&gt; without visible quality loss&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Free image compression API&lt;/strong&gt; tier available&lt;/li&gt;
&lt;li&gt;Works with &lt;strong&gt;image resize API&lt;/strong&gt; features&lt;/li&gt;
&lt;li&gt;Perfect for &lt;strong&gt;PHP image compression&lt;/strong&gt; too&lt;/li&gt;
&lt;li&gt;Acts as your &lt;strong&gt;image CDN&lt;/strong&gt; alternative&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Need batch processing? Use &lt;strong&gt;nodejs image compression&lt;/strong&gt; with async/await:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&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="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;img1.jpg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;img2.png&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;img3.webp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&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;files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;compressImage&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Cache compressed results—no need to re-compress&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>AVIF vs WebP: Which Format Should Developers Choose in 2026?</title>
      <dc:creator>Roman Klymenko</dc:creator>
      <pubDate>Tue, 21 Jul 2026 12:31:48 +0000</pubDate>
      <link>https://dev.to/roman_klymenko_39f1198f16/avif-vs-webp-which-format-should-developers-choose-in-2026-4gff</link>
      <guid>https://dev.to/roman_klymenko_39f1198f16/avif-vs-webp-which-format-should-developers-choose-in-2026-4gff</guid>
      <description>&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;AVIF&lt;/th&gt;
&lt;th&gt;WebP&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Compression&lt;/td&gt;
&lt;td&gt;25-35% better&lt;/td&gt;
&lt;td&gt;Industry standard&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Browser Support&lt;/td&gt;
&lt;td&gt;95%+ modern browsers&lt;/td&gt;
&lt;td&gt;96%+ coverage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Encoding Speed&lt;/td&gt;
&lt;td&gt;Slower&lt;/td&gt;
&lt;td&gt;Faster&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Quality at Low Bitrate&lt;/td&gt;
&lt;td&gt;Excellent&lt;/td&gt;
&lt;td&gt;Very good&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Animation Support&lt;/td&gt;
&lt;td&gt;Yes (AVIC)&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Maturity&lt;/td&gt;
&lt;td&gt;Newer, still optimizing&lt;/td&gt;
&lt;td&gt;Battle-tested&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;WebP dominated the last five years. It's fast, widely supported, and genuinely better than JPEG/PNG. Most developers standardized on it and called it a day.&lt;/p&gt;

&lt;p&gt;But AVIF changes the equation. It compresses better—often 25-35% smaller than WebP at identical visual quality. For image-heavy sites, that's real performance gain. Real user experience improvement.&lt;/p&gt;

&lt;p&gt;The catch? AVIF takes longer to encode. Your build pipeline slows. And fallbacks matter—older browsers still exist, even if they're shrinking.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here's the practical take for 2026:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Use AVIF as primary, WebP as fallback, JPEG/PNG as safety net. Modern picture elements handle this effortlessly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;picture&amp;gt;&lt;/span&gt;
 &lt;span class="nt"&gt;&amp;lt;source&lt;/span&gt; &lt;span class="na"&gt;srcset=&lt;/span&gt;&lt;span class="s"&gt;"image.avif"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"image/avif"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
 &lt;span class="nt"&gt;&amp;lt;source&lt;/span&gt; &lt;span class="na"&gt;srcset=&lt;/span&gt;&lt;span class="s"&gt;"image.webp"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"image/webp"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
 &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"image.jpg"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"description"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/picture&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Browser support is now solid enough—95%+ of modern browsers speak AVIF natively. The "too new, too risky" argument doesn't hold anymore.&lt;/p&gt;

&lt;p&gt;Start converting your heaviest images.&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>performance</category>
      <category>ux</category>
      <category>webdev</category>
    </item>
    <item>
      <title>PNG to WebP: The Complete Developer's Conversion Guide</title>
      <dc:creator>Roman Klymenko</dc:creator>
      <pubDate>Thu, 16 Jul 2026 12:43:29 +0000</pubDate>
      <link>https://dev.to/roman_klymenko_39f1198f16/png-to-webp-the-complete-developers-conversion-guide-7cj</link>
      <guid>https://dev.to/roman_klymenko_39f1198f16/png-to-webp-the-complete-developers-conversion-guide-7cj</guid>
      <description>&lt;p&gt;&lt;strong&gt;Quick TL;DR – Convert PNG to WebP in 30 seconds:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;
convert image.png image.webp

cwebp &lt;span class="nt"&gt;-q&lt;/span&gt; 80 image.png &lt;span class="nt"&gt;-o&lt;/span&gt; image.webp

const sharp &lt;span class="o"&gt;=&lt;/span&gt; require&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'sharp'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
sharp&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'image.png'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;.webp&lt;span class="o"&gt;({&lt;/span&gt; quality: 80 &lt;span class="o"&gt;})&lt;/span&gt;.toFile&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'image.webp'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;WebP isn't just hype—it's a legitimate game-changer for web performance. If you're still serving PNG files in 2024, you're leaving ~30-40% file size reduction on the table.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why PNG to WebP matters:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;PNG files are lossless, which is great for quality but brutal on bandwidth. WebP delivers the same visual fidelity at a fraction of the size. A typical PNG converts to WebP with 25-35% compression, sometimes hitting 50%+ on complex images.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The conversion reality:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Quality trade-off:&lt;/strong&gt; Minimal. Most developers can't spot the difference at quality 75-85.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Browser support:&lt;/strong&gt; 96%+ of modern browsers. Fallbacks are your friend for legacy users.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tools that actually work:&lt;/strong&gt; cwebp (Google's official), ImageMagick, FFmpeg, or Node.js libraries like Sharp.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Real-world impact:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A 500KB PNG becomes ~150KB WebP. On a site with 50 images, that's 17.5MB saved per page load. Multiply by monthly visitors—your hosting bills and user experience both improve.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best practice:&lt;/strong&gt; Use WebP as primary with PNG fallback via `&amp;lt;picture&lt;/p&gt;

</description>
      <category>cli</category>
      <category>performance</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Core Web Vitals &amp; LCP Image Guide — Dev.to Repost</title>
      <dc:creator>Roman Klymenko</dc:creator>
      <pubDate>Thu, 16 Jul 2026 12:42:57 +0000</pubDate>
      <link>https://dev.to/roman_klymenko_39f1198f16/core-web-vitals-lcp-image-guide-devto-repost-nbj</link>
      <guid>https://dev.to/roman_klymenko_39f1198f16/core-web-vitals-lcp-image-guide-devto-repost-nbj</guid>
      <description>&lt;p&gt;Your images might be killing your LCP score. Here's why: unoptimized images delay the Largest Contentful Paint, tanking your Core Web Vitals and SEO rankings.&lt;/p&gt;

&lt;p&gt;The fix? Smart image optimization for web. Before diving into lazy-loading and next-gen formats, compress ruthlessly. Most devs waste 60-80% of image file size unnecessarily.&lt;/p&gt;

&lt;p&gt;Three quick wins:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Optimize images without losing quality&lt;/strong&gt; — Modern compressors (like WebP) cut file sizes by 30-50% while keeping visuals sharp. Your users won't notice the difference.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Automate it&lt;/strong&gt; — Manual optimization kills productivity. Automatic image optimization in your build pipeline means every image gets optimized before deployment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Test your LCP&lt;/strong&gt; — Use PageSpeed Insights. If an image is your LCP element, that's your bottleneck. Prioritize optimizing it.&lt;/p&gt;

&lt;p&gt;Image optimization best practices? Start here: measure, compress, format-switch, cache aggressively. Done right, you'll shave 1-2 seconds off page load time alone.&lt;/p&gt;

&lt;p&gt;The deeper analysis lives on our blog — check the canonical link for the full breakdown on image optimization for website performance.&lt;/p&gt;

&lt;p&gt;TL;DR: Optimize your images. Your Core Web Vitals (and users) will thank you.&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>performance</category>
      <category>seo</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Ultimate Guide to Image Compression: Reduce Image Size Without Losing Quality</title>
      <dc:creator>Roman Klymenko</dc:creator>
      <pubDate>Thu, 16 Jul 2026 12:42:51 +0000</pubDate>
      <link>https://dev.to/roman_klymenko_39f1198f16/ultimate-guide-to-image-compression-reduce-image-size-without-losing-quality-15bl</link>
      <guid>https://dev.to/roman_klymenko_39f1198f16/ultimate-guide-to-image-compression-reduce-image-size-without-losing-quality-15bl</guid>
      <description>&lt;p&gt;Tired of images bloating your web projects? Learn how to compress images without sacrificing quality—essential for every developer's toolkit.&lt;/p&gt;

&lt;p&gt;Every kilobyte counts. Large unoptimized images slow page load times, kill Core Web Vitals, and frustrate users. Lossless compression removes metadata and redundant data while keeping your visuals pixel-perfect.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lossless compression&lt;/strong&gt; preserves all image data—perfect for screenshots, logos, and anything demanding clarity. &lt;strong&gt;Lossy compression&lt;/strong&gt; strategically reduces colors and details, ideal for photos where minor quality loss is invisible.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Choose the right format (WebP beats PNG/JPG)&lt;/li&gt;
&lt;li&gt;Resize before compressing&lt;/li&gt;
&lt;li&gt;Batch compress to save time&lt;/li&gt;
&lt;li&gt;Use online tools for quick workflows&lt;/li&gt;
&lt;li&gt;Automate in your build pipeline&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Modern online image compressors handle bulk operations instantly. A solid free image compressor should offer batch image compression, preserving quality while slashing file sizes by 50-90%.&lt;/p&gt;

&lt;p&gt;Quality compression shrinks a 2MB photo to 300KB with zero visible difference. That's faster loading, happier users, better SEO ranking.&lt;/p&gt;

&lt;p&gt;Start optimizing today—your website's performance (and your users) will thank you.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on pixozip.com/blog&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>PNG vs WebP vs AVIF — Dev.to Repost</title>
      <dc:creator>Roman Klymenko</dc:creator>
      <pubDate>Tue, 07 Jul 2026 12:00:37 +0000</pubDate>
      <link>https://dev.to/roman_klymenko_39f1198f16/png-vs-webp-vs-avif-devto-repost-1f92</link>
      <guid>https://dev.to/roman_klymenko_39f1198f16/png-vs-webp-vs-avif-devto-repost-1f92</guid>
      <description>&lt;p&gt;Ever wondered which image format actually saves bandwidth without sacrificing quality? Let's break it down.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PNG&lt;/strong&gt; is your reliable friend—lossless, great for graphics, but bloated for photos. &lt;strong&gt;WebP&lt;/strong&gt; cuts file sizes by 25-35% and supports transparency. &lt;strong&gt;AVIF&lt;/strong&gt; is the newcomer crushing it with 50%+ smaller files than PNG, but browser support isn't universal yet.&lt;/p&gt;

&lt;p&gt;The real win? Use WebP for most cases—solid browser support and size savings. AVIF when you can afford a fallback. PNG for simple graphics or when you need maximum compatibility.&lt;/p&gt;

&lt;p&gt;Pro tip: automate this with tools that handle format conversion and serve the right file to the right browser. Your users (and hosting bill) will thank you.&lt;/p&gt;

&lt;p&gt;Which format dominates your stack?&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>performance</category>
      <category>webdesign</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How to Automate Image Compression with an API: A Node.js &amp; PHP Guide</title>
      <dc:creator>Roman Klymenko</dc:creator>
      <pubDate>Mon, 22 Jun 2026 09:37:05 +0000</pubDate>
      <link>https://dev.to/roman_klymenko_39f1198f16/how-to-automate-image-compression-with-an-api-a-nodejs-php-guide-24m3</link>
      <guid>https://dev.to/roman_klymenko_39f1198f16/how-to-automate-image-compression-with-an-api-a-nodejs-php-guide-24m3</guid>
      <description>&lt;p&gt;Images are still the single heaviest asset on most web pages, and one unoptimized hero shot can wreck your &lt;strong&gt;Largest Contentful Paint (LCP)&lt;/strong&gt; before a line of your JavaScript even runs. The catch is that &lt;em&gt;manual&lt;/em&gt; optimization — dragging files through a desktop tool before every deploy — simply does not scale. The moment your users start uploading their own avatars, products, or listings, compression has to happen &lt;strong&gt;automatically, on the server, in real time&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That is exactly what an image optimization API is for. In this guide we wire one into a real backend using the &lt;a href="https://pixozip.com" rel="noopener noreferrer"&gt;Pixozip&lt;/a&gt; API, with working &lt;strong&gt;Node.js&lt;/strong&gt; and &lt;strong&gt;PHP&lt;/strong&gt; examples, plus the async patterns you actually need in production.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. How an Image Optimization API Works
&lt;/h2&gt;

&lt;p&gt;The flow is simpler than it looks. Instead of bundling &lt;code&gt;sharp&lt;/code&gt;, &lt;code&gt;libvips&lt;/code&gt;, or ImageMagick into every service and fighting native build dependencies in CI, you POST the raw image bytes to a stateless HTTP endpoint and get an optimized file back.&lt;/p&gt;

&lt;p&gt;A typical request lifecycle looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Upload&lt;/strong&gt; — your backend sends the raw image buffer to &lt;code&gt;POST /v1/shrink&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Queue&lt;/strong&gt; — the gateway authenticates your API key, validates the payload, and enqueues a job.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Process&lt;/strong&gt; — a horizontally-scaled worker re-encodes the image to WebP, AVIF, or JPEG XL.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deliver&lt;/strong&gt; — you receive metadata plus a short-lived URL to download the optimized bytes.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Because the heavy lifting runs on dedicated workers, your application servers stay light: no CPU spikes from &lt;code&gt;sharp&lt;/code&gt;, no memory pressure, and no native modules to compile.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concern&lt;/th&gt;
&lt;th&gt;In-process (sharp/IM)&lt;/th&gt;
&lt;th&gt;Optimization API&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Native build deps&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Required in every image&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CPU / memory load&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;On your app servers&lt;/td&gt;
&lt;td&gt;Offloaded to workers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Horizontal scaling&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Manual&lt;/td&gt;
&lt;td&gt;Built-in queue&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Modern formats&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Manual per-codec&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;webp&lt;/code&gt; / &lt;code&gt;avif&lt;/code&gt; / &lt;code&gt;jxl&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  2. Node.js Integration
&lt;/h2&gt;

&lt;p&gt;The official &lt;code&gt;@pixozip/sdk&lt;/code&gt; is &lt;strong&gt;dependency-free&lt;/strong&gt; — it runs on native &lt;code&gt;fetch&lt;/code&gt; and streams, so it adds almost nothing to your bundle. Install it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @pixozip/sdk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then compress a local file and write the result to disk:&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Pixozip&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@pixozip/sdk&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fs/promises&lt;/span&gt;&lt;span class="dl"&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;zip&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;Pixozip&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PIXOZIP_API_KEY&lt;/span&gt;&lt;span class="o"&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;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;original-photo.jpg&lt;/span&gt;&lt;span class="dl"&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shrink&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="na"&gt;contentType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;image/jpeg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;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;// "auto" | "webp" | "avif" | "jpeg" | "png" | "jxl"&lt;/span&gt;
  &lt;span class="na"&gt;qualityTier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;balanced&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="c1"&gt;// "fast" | "balanced" | "max"&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="s2"&gt;`Saved &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ratio&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&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;optimized&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;download&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;optimized.webp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;optimized&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;result&lt;/code&gt; object carries everything you need: &lt;code&gt;jobId&lt;/code&gt;, &lt;code&gt;outputBytes&lt;/code&gt;, the compression &lt;code&gt;ratio&lt;/code&gt;, and a &lt;code&gt;download()&lt;/code&gt; helper that fetches the final bytes from the short-lived storage URL. You can also resize on the fly:&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="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shrink&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="na"&gt;contentType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;image/png&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;avif&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;resize&lt;/span&gt;&lt;span class="p"&gt;:&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;1200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;fit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;inside&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// cover | contain | fill | inside | outside&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  3. PHP Integration
&lt;/h2&gt;

&lt;p&gt;For Laravel, WordPress, or plain PHP backends, the &lt;code&gt;pixozip/sdk&lt;/code&gt; Composer package mirrors the same API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer require pixozip/sdk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Pixozip\Pixozip&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$zip&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;Pixozip&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'apiKey'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'PIXOZIP_API_KEY'&lt;/span&gt;&lt;span class="p"&gt;)]);&lt;/span&gt;

&lt;span class="nv"&gt;$bytes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;file_get_contents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'upload.jpg'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nv"&gt;$result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$zip&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;shrink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$bytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s1"&gt;'contentType'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'image/jpeg'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'output'&lt;/span&gt;      &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'webp'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'qualityTier'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'balanced'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="c1"&gt;// $result is an array: ['jobId' =&amp;gt; ..., 'outputBytes' =&amp;gt; ..., 'ratio' =&amp;gt; ...]&lt;/span&gt;
&lt;span class="nv"&gt;$optimized&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$zip&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;download&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'downloadUrl'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="nb"&gt;file_put_contents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'optimized.webp'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$optimized&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both SDKs throw a typed error (&lt;code&gt;PixozipError&lt;/code&gt; in Node, &lt;code&gt;PixozipException&lt;/code&gt; in PHP) that exposes the HTTP &lt;code&gt;status&lt;/code&gt; and the gateway &lt;code&gt;body&lt;/code&gt; so you can branch on &lt;code&gt;rate_limit_exceeded&lt;/code&gt;, &lt;code&gt;file_too_large&lt;/code&gt;, and friends.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Raw REST — No SDK Required
&lt;/h2&gt;

&lt;p&gt;Under the hood it is just one authenticated POST. The image goes in the request body as raw bytes; the options ride along in an &lt;code&gt;x-options&lt;/code&gt; JSON header:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://api.pixozip.com/v1/shrink &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer img_live_your_key"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/octet-stream"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'x-options: {"output":"webp","qualityTier":"balanced"}'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--data-binary&lt;/span&gt; @photo.jpg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This portability is the whole point of an API: any language that can make an HTTP request — Go, Python, Ruby, Rust — can optimize images with no native dependencies at all.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Going Async at Scale
&lt;/h2&gt;

&lt;p&gt;Synchronous calls are perfect for single uploads, but for &lt;strong&gt;batch imports&lt;/strong&gt; or large payloads you should not hold an HTTP connection open while a worker grinds. Pass &lt;code&gt;async: true&lt;/code&gt; and the API returns instantly with a &lt;code&gt;jobId&lt;/code&gt; you poll:&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;job&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shrink&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="na"&gt;contentType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;image/jpeg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;async&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;job&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;queued&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;processing&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;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getJob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;jobId&lt;/span&gt;&lt;span class="p"&gt;);&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;status&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;completed&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;await&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;out.webp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;download&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;Two more endpoints make life easier: &lt;code&gt;POST /v1/shrink-from-url&lt;/code&gt; pulls a remote image directly (no need to buffer it yourself), and &lt;code&gt;POST /v1/srcset&lt;/code&gt; returns a full set of responsive variants in one call — ideal for feeding a &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; element.&lt;/p&gt;




&lt;h2&gt;
  
  
  6. Production Best Practices
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Always send an &lt;code&gt;idempotencyKey&lt;/code&gt;.&lt;/strong&gt; Network retries are inevitable; an idempotency key guarantees a flaky connection never bills you — or processes the same image — twice.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use &lt;code&gt;output: "auto"&lt;/code&gt;&lt;/strong&gt; to let the API negotiate the best modern format per image instead of hard-coding one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Strip metadata by default.&lt;/strong&gt; Leave &lt;code&gt;keepMetadata&lt;/code&gt; off unless you genuinely need EXIF/GPS — it shaves extra bytes and removes a privacy leak.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Go async for anything batch.&lt;/strong&gt; Queue-and-poll keeps your request workers free and your timeouts sane.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Start free.&lt;/strong&gt; Every account gets &lt;strong&gt;500 optimizations per month&lt;/strong&gt; at no cost, and an unauthenticated &lt;code&gt;POST /v1/public/shrink&lt;/code&gt; endpoint allows 5 test compressions per IP per day — enough to prototype before you ever add a key.&lt;/li&gt;
&lt;/ul&gt;




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

&lt;p&gt;Build-time tooling optimizes the images &lt;em&gt;you&lt;/em&gt; ship. An API optimizes the images &lt;em&gt;everyone else&lt;/em&gt; uploads — automatically, at scale, without dragging native codecs into your stack. With a dependency-free SDK for Node.js and PHP and a plain REST endpoint for everything else, wiring it in is a single function call.&lt;/p&gt;

&lt;p&gt;Grab a free API key, keep your 500 monthly optimizations, and stop shipping heavy images. &lt;a href="https://pixozip.com" rel="noopener noreferrer"&gt;&lt;strong&gt;Start with Pixozip →&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>node</category>
      <category>php</category>
      <category>api</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How to Build a High-Performance Image Optimization Pipeline in 5 Minutes</title>
      <dc:creator>Roman Klymenko</dc:creator>
      <pubDate>Mon, 25 May 2026 14:22:09 +0000</pubDate>
      <link>https://dev.to/roman_klymenko_39f1198f16/how-to-build-a-high-performance-image-optimization-pipeline-in-5-minutes-41nc</link>
      <guid>https://dev.to/roman_klymenko_39f1198f16/how-to-build-a-high-performance-image-optimization-pipeline-in-5-minutes-41nc</guid>
      <description>&lt;p&gt;Images make up over 60% of average web page weight. If you're serving unoptimized, raw JPEGs or PNGs to mobile clients, your site's Largest Contentful Paint (LCP) score is taking a massive hit.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F98q2bn8latw4dofdm6oe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F98q2bn8latw4dofdm6oe.png" alt=" " width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this quick guide, we’ll show you how to automate image compression using the Pixozip SDK to convert images to AVIF/WebP on the fly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why AVIF over traditional JPEG?
&lt;/h3&gt;

&lt;p&gt;Traditional JPEG compression is linear. AVIF uses intra-frame video compression algorithms that analyze texture patterns. This allows AVIF to shrink file sizes by 70-90% compared to legacy JPEG while keeping the same visual clarity.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Install the SDK
&lt;/h3&gt;

&lt;p&gt;Install the official Node.js SDK:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @pixozip/sdk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Initialize and Compress
&lt;/h3&gt;

&lt;p&gt;Import the library, supply your API key, and call the &lt;code&gt;.shrink()&lt;/code&gt; method. It handles error catching, request formatting, and automatic retries with exponential backoff internally:&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Pixozip&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@pixozip/sdk&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fs/promises&lt;/span&gt;&lt;span class="dl"&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;zip&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;Pixozip&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;YOUR_API_KEY&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Load the image file into a buffer&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;imageBuffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./hero_banner.png&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Compress and convert to AVIF&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shrink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;imageBuffer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;contentType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;image/png&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;avif&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;           &lt;span class="c1"&gt;// Automatically converts png to avif&lt;/span&gt;
  &lt;span class="na"&gt;qualityTier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;balanced&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;// Targets visually lossless quality (SSIM &amp;gt; 0.995)&lt;/span&gt;
  &lt;span class="na"&gt;resize&lt;/span&gt;&lt;span class="p"&gt;:&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;1200&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;   &lt;span class="c1"&gt;// Scales down layout resolutions&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Download and write the optimized image&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;optimizedBuffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;download&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./hero_banner.opt.avif&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;optimizedBuffer&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="s2"&gt;`Optimized! Saved &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ratio&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;% of bytes.`&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="s2"&gt;`Download URL: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;downloadUrl&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Async Operations for High Volume
&lt;/h3&gt;

&lt;p&gt;If you are processing batches of images, blocking your server thread synchronously is not ideal. You can trigger an asynchronous job and receive a webhook callback when it's done:&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;job&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shrink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;imageBuffer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;contentType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;image/jpeg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;webp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;async&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="c1"&gt;// Gateway returns 202 immediately&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="s2"&gt;`Job queued with ID: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;jobId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;By adding a few lines of code to your upload pipeline, you can drastically decrease bandwidth consumption, reduce AWS S3 storage bills, and improve page speed rankings.&lt;/p&gt;

&lt;p&gt;Get a free API key with 500 free optimizations per month at &lt;a href="https://pixozip.pretzl.dev" rel="noopener noreferrer"&gt;pixozip&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
