<?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: jigz</title>
    <description>The latest articles on DEV Community by jigz (@jigz_dev).</description>
    <link>https://dev.to/jigz_dev</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%2F3843181%2F1ca1efba-ece9-4838-8f21-5b88065399fd.jpg</url>
      <title>DEV Community: jigz</title>
      <link>https://dev.to/jigz_dev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jigz_dev"/>
    <language>en</language>
    <item>
      <title>Build a PDF to Image Converter in Next.js</title>
      <dc:creator>jigz</dc:creator>
      <pubDate>Fri, 29 May 2026 16:38:00 +0000</pubDate>
      <link>https://dev.to/jigz_dev/build-a-pdf-to-image-converter-in-nextjs-1ga2</link>
      <guid>https://dev.to/jigz_dev/build-a-pdf-to-image-converter-in-nextjs-1ga2</guid>
      <description>&lt;p&gt;This tutorial walks through the &lt;strong&gt;PDF to Images&lt;/strong&gt; feature in a Next.js template. You'll learn how to use it from the UI, and how it works under the hood using browser-based PDF rendering and image export.&lt;/p&gt;




&lt;h2&gt;
  
  
  What This Tool Does
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;PDF to Images&lt;/strong&gt; tool converts every page of an uploaded PDF into one or more image files.&lt;/p&gt;

&lt;p&gt;Supported output formats:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;PNG&lt;/code&gt; — lossless, great for diagrams and documents with sharp lines&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;JPG&lt;/code&gt; — smaller file sizes, ideal for photographs and sharing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can also control:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Quality&lt;/strong&gt; for JPG output&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DPI&lt;/strong&gt; for rendering resolution&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Step-by-Step User Tutorial
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Open the PDF to Images tool
&lt;/h3&gt;

&lt;p&gt;From the sidebar, select the &lt;strong&gt;PDF to Images&lt;/strong&gt; tool.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Upload a PDF file
&lt;/h3&gt;

&lt;p&gt;Use the upload area and drag or choose a PDF file.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The tool only accepts &lt;code&gt;.pdf&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;You can upload one file at a time&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Choose the output format
&lt;/h3&gt;

&lt;p&gt;Select either &lt;code&gt;PNG&lt;/code&gt; or &lt;code&gt;JPG&lt;/code&gt; from the format dropdown.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;PNG&lt;/code&gt; keeps image transparency and delivers crisp results.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;JPG&lt;/code&gt; produces smaller files and uses white backgrounds automatically.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Set the quality and DPI
&lt;/h3&gt;

&lt;p&gt;Adjust the sliders:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Quality&lt;/strong&gt; controls JPEG compression.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DPI&lt;/strong&gt; controls the rendering scale.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Higher DPI produces sharper images but uses more memory and takes longer.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Start conversion
&lt;/h3&gt;

&lt;p&gt;Click the &lt;strong&gt;Convert to Images&lt;/strong&gt; button.&lt;/p&gt;

&lt;p&gt;The progress indicator updates while the pages are rendered one by one.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Preview converted pages
&lt;/h3&gt;

&lt;p&gt;After conversion, the first page appears as a preview.&lt;/p&gt;

&lt;p&gt;A list of all converted pages appears below, with download buttons for each image.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Download images
&lt;/h3&gt;

&lt;p&gt;Use the &lt;strong&gt;Download All&lt;/strong&gt; button to save all pages at once, or download individual images.&lt;/p&gt;

&lt;p&gt;Each output file is named like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;document-page-1.png&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;document-page-2.jpg&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  How It Works Under the Hood
&lt;/h2&gt;

&lt;p&gt;This is a Next.js implementation, where the interactive UI lives in a client component and the conversion helper lives in a shared &lt;code&gt;lib&lt;/code&gt; module.&lt;/p&gt;

&lt;p&gt;The feature is implemented in two main places:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;components/tools/pdf-to-images-tool.tsx&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;lib/pdf-to-image-client.ts&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  1. Client-side app UI
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;pdf-to-images-tool.tsx&lt;/code&gt; handles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Uploading the PDF file&lt;/li&gt;
&lt;li&gt;Validating file type&lt;/li&gt;
&lt;li&gt;Reading settings: output format, quality, DPI&lt;/li&gt;
&lt;li&gt;Showing progress, preview, and download controls&lt;/li&gt;
&lt;li&gt;Calling the conversion helper&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When the user clicks &lt;code&gt;Convert to Images&lt;/code&gt;, the tool calls:&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;images&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;convertPdfToImages&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;sourceFile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;format&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;quality&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dpi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onProgress&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. PDF rendering with &lt;code&gt;pdfjs-dist&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;The actual conversion happens in &lt;code&gt;lib/pdf-to-image-client.ts&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This file dynamically imports &lt;code&gt;pdfjs-dist&lt;/code&gt; and sets up the worker like this:&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;pdfjs&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;loadPdfJs&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nx"&gt;pdfjs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GlobalWorkerOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;workerSrc&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;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pdfjs-dist/legacy/build/pdf.worker.min.mjs&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="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then it loads the PDF file and creates a document object:&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;pdfData&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;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;arrayBuffer&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;pdf&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;pdfjs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getDocument&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;pdfData&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nx"&gt;promise&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Rendering pages onto a canvas
&lt;/h3&gt;

&lt;p&gt;The conversion loop renders each PDF page one at a time:&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;for &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;pageNumber&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="nx"&gt;pageNumber&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;numPages&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;pageNumber&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="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;page&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;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getPage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pageNumber&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;viewport&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getViewport&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;scale&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;canvas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;canvas&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;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2d&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;alpha&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;format&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;png&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="nx"&gt;canvas&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="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ceil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;viewport&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;canvas&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="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ceil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;viewport&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&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;format&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jpg&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="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fillStyle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#ffffff&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fillRect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&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;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;canvasContext&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;viewport&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nx"&gt;promise&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;blob&lt;/span&gt; &lt;span class="o"&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="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Blob&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toBlob&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="o"&gt;=&amp;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="o"&gt;!&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;reject&lt;/span&gt;&lt;span class="p"&gt;(&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="nf"&gt;resolve&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="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;mimeType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;format&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;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;normalizedQuality&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Key details:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;viewport&lt;/code&gt; is scaled by &lt;code&gt;dpi / 72&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;canvas.toBlob()&lt;/code&gt; converts the rendered page into PNG or JPG data&lt;/li&gt;
&lt;li&gt;For JPG, the code first paints a white background because JPEG does not support transparency&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Exporting images as downloadable files
&lt;/h3&gt;

&lt;p&gt;Each rendered page becomes a &lt;code&gt;Blob&lt;/code&gt;, which is converted into a browser object URL:&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;function&lt;/span&gt; &lt;span class="nf"&gt;createObjectUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;blob&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Blob&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createObjectURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;blob&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;That URL is stored and later used for preview and downloads.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Downloading files
&lt;/h3&gt;

&lt;p&gt;The UI uses this helper to trigger downloads:&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;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;downloadObjectUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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;link&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;
  &lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;download&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fileName&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;link&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;This creates a temporary anchor tag and simulates a click so the browser downloads the image.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Cleaning up memory
&lt;/h3&gt;

&lt;p&gt;After conversion, object URLs are revoked to free browser memory:&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;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;revokeConvertedImages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;images&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ConvertedPdfImage&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;images&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;revokeObjectURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&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;This is important because every converted page creates an in-memory image blob.&lt;/p&gt;




&lt;h2&gt;
  
  
  Practical Notes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Best settings for quality and speed
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;PNG&lt;/strong&gt; is best for text, charts, and sharp document pages&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JPG&lt;/strong&gt; is best for smaller downloads and photographic PDF content&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DPI 150&lt;/strong&gt; is a solid default: good sharpness without excessive memory use&lt;/li&gt;
&lt;li&gt;If your PDF is large, convert only what you need or split it first&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why this approach is powerful
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;It runs entirely in the browser&lt;/li&gt;
&lt;li&gt;No server upload or backend processing is required&lt;/li&gt;
&lt;li&gt;Files stay private on the user’s device&lt;/li&gt;
&lt;li&gt;The experience is instant and responsive&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Example Next.js Workflow
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Open the &lt;strong&gt;PDF to Images&lt;/strong&gt; tool in the app&lt;/li&gt;
&lt;li&gt;Upload &lt;code&gt;report.pdf&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Choose &lt;code&gt;JPG&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Set quality to &lt;code&gt;85%&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;DPI 150&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Convert to Images&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Preview the first page&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Download All&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You now have one image file per page, ready for use in presentations, websites, or screenshots.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where This Lives in the Template
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Component: &lt;code&gt;components/tools/pdf-to-images-tool.tsx&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Conversion helper: &lt;code&gt;lib/pdf-to-image-client.ts&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Tool entry in config: &lt;code&gt;lib/tools-config.ts&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Route mapping: &lt;code&gt;app/tools/[id]/page.tsx&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want to modify the feature, those are the files to edit.&lt;/p&gt;




&lt;h2&gt;
  
  
  Support the Template
&lt;/h2&gt;

&lt;p&gt;If you'd like the full Next.js template or want to support this build, grab it on Gumroad:&lt;br&gt;
&lt;a href="https://jignesh60.gumroad.com/l/file-utility-dashboard-nextjs-template" rel="noopener noreferrer"&gt;https://jignesh60.gumroad.com/l/file-utility-dashboard-nextjs-template&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Replace that link with your own product page to make it the primary purchase location.&lt;/p&gt;




&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;This PDF to Images feature is a great example of how a Next.js app turns browser APIs into a real product capability. It combines &lt;code&gt;pdfjs-dist&lt;/code&gt; rendering, canvas export, and browser downloads to give you a fast, client-side PDF conversion feature without any backend.&lt;/p&gt;

</description>
      <category>pdf</category>
      <category>nextjs</category>
      <category>imagetool</category>
    </item>
    <item>
      <title>I Built a File Utility Tool for PDFs, Images &amp; OCR</title>
      <dc:creator>jigz</dc:creator>
      <pubDate>Fri, 29 May 2026 16:04:09 +0000</pubDate>
      <link>https://dev.to/jigz_dev/i-built-a-file-utility-tool-for-pdfs-images-ocr-204l</link>
      <guid>https://dev.to/jigz_dev/i-built-a-file-utility-tool-for-pdfs-images-ocr-204l</guid>
      <description>&lt;p&gt;I remember the exact moment it clicked. I was watching a friend fork over &lt;strong&gt;$14.99&lt;/strong&gt; for a monthly iLovePDF subscription just to merge a few PDF files and compress a handful of images. They used the service for maybe 5 minutes total and didn't touch it again for weeks.&lt;/p&gt;

&lt;p&gt;That same month, I noticed a constant stream of the same burning questions across various online communities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;"Is there a free way to convert my PDFs to images?"&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;"How can I compress these photos without losing quality?"&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;"I need to split this massive PDF but I don't want to pay."&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It hit me hard: companies were making serious money by putting a paywall around relatively simple file operations that have been technically possible for years. The standard industry pricing? &lt;strong&gt;$10-15 per month&lt;/strong&gt; for tools that do exactly what I knew I could build myself.&lt;/p&gt;

&lt;p&gt;So, I decided to do something about it. I built &lt;strong&gt;File Craft&lt;/strong&gt;—a completely free, lightning-fast, and user-friendly file processing application that puts an end to expensive subscriptions. I'm releasing it to the world so everyone can stop paying for tools that should be entirely free.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is File Craft?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;File Craft&lt;/strong&gt; is a modern, all-in-one file processing suite that runs entirely in your browser. It completely eliminates subscriptions, watermarks, data tracking, and artificial limits (outside of your own browser's memory).&lt;/p&gt;

&lt;h3&gt;
  
  
  Core Capabilities
&lt;/h3&gt;

&lt;h4&gt;
  
  
  📄 PDF Tools
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;✂️ &lt;strong&gt;Split PDFs:&lt;/strong&gt; Extract specific pages or divide massive PDF documents into smaller chunks.&lt;/li&gt;
&lt;li&gt;🔗 &lt;strong&gt;Merge PDFs:&lt;/strong&gt; Effortlessly combine multiple PDFs into a single document (up to 50 files at once!).&lt;/li&gt;
&lt;li&gt;🗜️ &lt;strong&gt;Compress PDFs:&lt;/strong&gt; Drastically reduce file sizes while maintaining professional visual quality.&lt;/li&gt;
&lt;li&gt;📸 &lt;strong&gt;Convert PDFs to Images:&lt;/strong&gt; Instantly transform PDF pages into high-quality JPG or PNG files.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  🖼️ Image Tools
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;🖼️ &lt;strong&gt;Compress Images:&lt;/strong&gt; Minimize image file sizes without sacrificing your visual clarity.&lt;/li&gt;
&lt;li&gt;🎨 &lt;strong&gt;Convert Images:&lt;/strong&gt; Seamlessly transform formats between JPG, PNG, WebP, and more.&lt;/li&gt;
&lt;li&gt;📏 &lt;strong&gt;Resize Images:&lt;/strong&gt; Scale images to exact custom dimensions or use optimized social media presets.&lt;/li&gt;
&lt;li&gt;👁️ &lt;strong&gt;Extract Text (OCR):&lt;/strong&gt; Utilize advanced optical character recognition to digitize scanned documents and text within images.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Why I Built It (Besides Being Tired of Paying)
&lt;/h2&gt;

&lt;p&gt;The inspiration behind File Craft goes deeper than just my frustration with predatory pricing models:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Accessibility:&lt;/strong&gt; Vital file processing tools shouldn't be gatekept behind a paywall. Whether you are a student, a freelancer, or just someone who occasionally needs to edit a document, you shouldn't be forced into a monthly subscription.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Absolute Privacy:&lt;/strong&gt; Most online SaaS tools require you to upload files to their servers, raising valid security and privacy concerns. With File Craft, everything runs entirely client-side. Your files never leave your device.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Blazing Speed:&lt;/strong&gt; Say goodbye to upload bottlenecks and server processing queues. Because it operates locally in your browser, execution happens almost instantly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Engineering Challenge:&lt;/strong&gt; I wanted to push my technical boundaries. Engineering a browser-based application that seamlessly handles heavy PDF manipulation, image processing, and OCR forced me to master complex web APIs and intricate file structures.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Community Impact:&lt;/strong&gt; I wanted to contribute something genuinely useful. If File Craft saves a single user $10 a month, that's $120 saved a year. Multiplied across thousands of users, that is a massive, tangible impact.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  The Tech Stack: Modern Web Development Done Right
&lt;/h2&gt;

&lt;p&gt;To build a high-performance, client-side file processor that runs smoothly across all modern browsers, I had to carefully select a cutting-edge technical stack.&lt;/p&gt;

&lt;h3&gt;
  
  
  Framework &amp;amp; Language
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Next.js 16.2.6:&lt;/strong&gt; The React framework of choice for production-grade, highly performant applications.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;React 19:&lt;/strong&gt; Utilizing the latest React features for optimized rendering and advanced hook architectures.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TypeScript 5.7.3:&lt;/strong&gt; Strict type safety across the entire development pipeline, which caught dozens of bugs early in production.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  UI &amp;amp; Aesthetics
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tailwind CSS 4.2.0:&lt;/strong&gt; A utility-first CSS framework allowing for rapid, fully responsive layout design.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Radix UI:&lt;/strong&gt; Completely accessible, unstyled component primitives that serve as a rock-solid UI foundation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lucide React:&lt;/strong&gt; A beautiful, clean, and highly consistent icon library.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Client-Side Processing Engines
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;pdf-lib 1.17.1:&lt;/strong&gt; Handles advanced PDF operations like secure merging and splitting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;pdfjs-dist 5.7.284:&lt;/strong&gt; Drives high-fidelity PDF rendering and image conversion.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;jsPDF 4.2.1:&lt;/strong&gt; Powers custom PDF generation and manipulation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tesseract.js 7.0.0:&lt;/strong&gt; A powerful, local OCR engine that extracts text from images without server interaction.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;jszip 3.10.1:&lt;/strong&gt; Manages archive creation and extraction for high-volume batch processing.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  UX, Forms &amp;amp; State
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;React Hook Form 7.54.1:&lt;/strong&gt; Highly performant form management with minimal re-renders.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zod 3.24.1:&lt;/strong&gt; Robust runtime type validation and strict schema definitions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sonner 1.7.1:&lt;/strong&gt; Sleek, non-intrusive toast notifications for real-time user feedback.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;next-themes 0.4.6:&lt;/strong&gt; Flawless, native dark mode support right out of the box.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recharts 2.15.0:&lt;/strong&gt; A reliable React charting library integrated to power future local analytics.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Feature Breakdown: Everything You Get
&lt;/h2&gt;

&lt;h3&gt;
  
  
  📄 Comprehensive PDF Toolkit
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Merge PDFs
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Problem:&lt;/strong&gt; You have multiple separate documents—like reports, invoices, or application forms—that need to be combined into a single, cohesive file.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The File Craft Solution:&lt;/strong&gt; Upload up to 50 PDFs at a time, arrange them in any sequence using an intuitive drag-and-drop interface, and merge them instantly for a one-click download.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why It Matters:&lt;/strong&gt; Most commercial tools charge users per merge operation. File Craft allows unlimited merges without ever asking for a credit card.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Split PDFs
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Problem:&lt;/strong&gt; You have a massive 50-page document but only need pages 10–15, or you need to divide a single document into individual files.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The File Craft Solution:&lt;/strong&gt; Upload your PDF and choose your strategy: extract exact custom page ranges (e.g., 1-5, 10-15) or split the document evenly by specifying the desired number of files.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why It Matters:&lt;/strong&gt; Paid platforms love to charge per transaction. Split your files as many times as your workflow demands.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Compress PDFs
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Problem:&lt;/strong&gt; Your PDF file size is too massive to attach to an email or upload to a state portal, but you cannot afford to lose readability.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The File Craft Solution:&lt;/strong&gt; Upload your file and pick your compression tier: &lt;em&gt;Low&lt;/em&gt; (maximum quality), &lt;em&gt;Medium&lt;/em&gt; (the recommended sweet spot), or &lt;em&gt;High&lt;/em&gt; (smallest possible footprint). You even get a real-time size comparison before processing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pro Tip:&lt;/strong&gt; Modern digital PDFs compress remarkably well, meaning you can often achieve massive space savings with zero visible quality loss.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  PDF to Images
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Problem:&lt;/strong&gt; You need to extract specific PDF pages as standalone images to use in slide decks, websites, or digital archives.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The File Craft Solution:&lt;/strong&gt; Upload the PDF, select your output format (JPG or PNG), choose your quality profile (Low, Medium, High), define your page range, and instantly extract them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why It Matters:&lt;/strong&gt; Skip the per-conversion paywalls found elsewhere. Convert entire books into image strings effortlessly.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  🖼️ High-Performance Image Toolkit
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Compress Images
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Problem:&lt;/strong&gt; High-resolution photos are clogging up your storage or slowing down your website's load times.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The File Craft Solution:&lt;/strong&gt; Drop your images in, adjust the precise quality slider, instantly view the before-and-after file sizes, and download the optimized results.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real Impact:&lt;/strong&gt; A heavy 5MB photo can routinely be compressed down to 500KB–1MB with absolutely imperceptible changes to the naked eye.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Convert Images
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Problem:&lt;/strong&gt; You have a PNG that needs to be a JPG for a specific upload form, or you want to embrace modern WebP formats for web optimization.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The File Craft Solution:&lt;/strong&gt; Bulk upload your photos, choose your target format, and download the converted files instantly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Supported Formats:&lt;/strong&gt; Fully supports JPG, PNG, WebP, GIF, BMP, and more.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Resize Images
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Problem:&lt;/strong&gt; You need to scale photos to exact dimensions for social media banners, website thumbnails, or UI assets.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The File Craft Solution:&lt;/strong&gt; Upload your imagery and choose between entering precise pixel dimensions (width × height) or utilizing instant built-in presets while locking or unlocking the aspect ratio.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Included Presets:&lt;/strong&gt; Instagram (1080×1080), Twitter/X (1200×627), Facebook (1200×630), standard mobile screens, and various universal desktop aspect ratios.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Image to Text (OCR)
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Problem:&lt;/strong&gt; You are staring at a scanned document, a screenshot, or a textbook photo, and you desperately need to extract the text without retyping it manually.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The File Craft Solution:&lt;/strong&gt; Upload your image, let the integrated local engine analyze the shapes, and instantly copy the text to your clipboard or download it as a clean text file.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why It Matters:&lt;/strong&gt; Premium OCR services charge users strictly &lt;em&gt;per page&lt;/em&gt; or hide the feature behind recurring tiers. File Craft lets you digitize unlimited documents completely free.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Key Features &amp;amp; Why They Matter
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;🚀 &lt;strong&gt;Blazingly Fast:&lt;/strong&gt; Because processing happens locally within your browser sandbox, there are no file upload delays or server wait times. It is instant.&lt;/li&gt;
&lt;li&gt;🔒 &lt;strong&gt;Absolute Privacy:&lt;/strong&gt; Your data belongs to you. Unlike cloud-based alternatives, your files are never transmitted to an external server. They stay safely on your machine.&lt;/li&gt;
&lt;li&gt;🎨 &lt;strong&gt;Beautiful, Intuitive UI:&lt;/strong&gt; Styled with Tailwind CSS and backed by Radix UI, the interface is modern, clean, and highly polished—no learning curve required.&lt;/li&gt;
&lt;li&gt;🌓 &lt;strong&gt;Native Dark Mode:&lt;/strong&gt; Protect your eyes during late-night work sessions with automatic, seamless dark mode integration.&lt;/li&gt;
&lt;li&gt;📱 &lt;strong&gt;Fully Responsive:&lt;/strong&gt; Whether you are working on a massive desktop monitor, an iPad, or a smartphone on the go, the interface adapts perfectly.&lt;/li&gt;
&lt;li&gt;♿ &lt;strong&gt;Accessible Design:&lt;/strong&gt; Accessibility is engineered directly into the core using Radix primitives. Enjoy robust keyboard navigation, full screen-reader compliance, and comprehensive ARIA labeling.&lt;/li&gt;
&lt;li&gt;🆓 &lt;strong&gt;Completely Free:&lt;/strong&gt; No hidden micro-transactions, no premium features locked behind paywalls, and no annoying watermarks stamped on your hard work.&lt;/li&gt;
&lt;li&gt;🔄 &lt;strong&gt;Fluid Drag-and-Drop:&lt;/strong&gt; Intuitive file handling that lets you effortlessly multi-select files, drop them into the browser window, and reorder PDFs on the fly.&lt;/li&gt;
&lt;li&gt;📊 &lt;strong&gt;Real-Time Previews:&lt;/strong&gt; Take the guesswork out of optimization by previewing changes, text extractions, and exact file reductions before downloading.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Numbers: What File Craft Replaces
&lt;/h2&gt;

&lt;p&gt;Let's look at the financial math. Here is how File Craft stacks up against the current SaaS landscape:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Feature Set&lt;/th&gt;
&lt;th&gt;Average Monthly Cost&lt;/th&gt;
&lt;th&gt;File Craft Cost&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;iLovePDF&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Merge PDFs&lt;/td&gt;
&lt;td&gt;$11.99 / mo&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;FREE&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;iLovePDF&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Compress PDFs&lt;/td&gt;
&lt;td&gt;$11.99 / mo&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;FREE&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;iLovePDF&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;PDF to Images&lt;/td&gt;
&lt;td&gt;$11.99 / mo&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;FREE&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;iLovePDF&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Full Merge + Compress + Convert Suite&lt;/td&gt;
&lt;td&gt;$11.99 - $14.99 / mo&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;FREE&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SmallPDF&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Identical Document Suite&lt;/td&gt;
&lt;td&gt;$9.99 - $14.99 / mo&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;FREE&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Online-Convert&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Image Conversion Utilities&lt;/td&gt;
&lt;td&gt;Often $2 - $5 / conversion&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;FREE&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Tinypng&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Image Compression Engine&lt;/td&gt;
&lt;td&gt;Strict free-tier limits&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;FREE&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Adobe Acrobat DC&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Professional PDF Suite&lt;/td&gt;
&lt;td&gt;$14.99+ / mo&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;FREE&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;TOTAL FOR PARITY&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Multiple Subscriptions&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$30 - $50+ / month&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;FREE&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;By switching your workflow to File Craft, you save up to $50 in your very first month. Over a year? That is &lt;strong&gt;$360 to $600+ back in your pocket&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  How File Craft is Delivered
&lt;/h2&gt;

&lt;p&gt;File Craft is built with transparency in mind, offering flexibility in how you choose to deploy and use it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Self-Host:&lt;/strong&gt; Easily deploy the codebase directly to your own private server or Vercel account.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Run Locally:&lt;/strong&gt; Clone the repository to your machine and spin it up instantly via &lt;code&gt;npm run dev&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Access Online:&lt;/strong&gt; A fully hosted, web-accessible version is coming soon for instant browser access.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Everything is open-source and entirely transparent. You retain total control over your own data and infrastructure.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Future Roadmap
&lt;/h2&gt;

&lt;p&gt;This initial release is just the foundation. I have big plans to expand File Craft into an even more powerful workstation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🎥 &lt;strong&gt;Video Processing:&lt;/strong&gt; Compress, transcode, clip, and merge video files locally.&lt;/li&gt;
&lt;li&gt;🎵 &lt;strong&gt;Audio Processing:&lt;/strong&gt; Trim, convert, and compress audio tracks.&lt;/li&gt;
&lt;li&gt;📄 &lt;strong&gt;Document Conversion:&lt;/strong&gt; Seamlessly turn Word docs to PDFs, Excel sheets to CSVs, and more.&lt;/li&gt;
&lt;li&gt;⚡ &lt;strong&gt;Advanced Batch Processing:&lt;/strong&gt; Automate workflows across hundreds of files simultaneously.&lt;/li&gt;
&lt;li&gt;🌐 &lt;strong&gt;Expanded OCR:&lt;/strong&gt; Introduce multi-language support and advanced handwriting recognition algorithms.&lt;/li&gt;
&lt;li&gt;🔌 &lt;strong&gt;Developer API Access:&lt;/strong&gt; Expose the client-side processing architecture for integration into your own apps.&lt;/li&gt;
&lt;li&gt;☁️ &lt;strong&gt;Optional Cloud Sync:&lt;/strong&gt; Secure, opt-in cloud storage for users who want to sync file history across devices.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Who is File Craft For?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;### For Students&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Stop wasting your budget on restrictive premium subscriptions. Process your research papers, group projects, and slide decks without caps or watermarks.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;### For Freelancers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Eliminate arbitrary per-operation fees. Handle massive client assets day in and day out without adding another recurring bill to your monthly overhead.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;### For Small Businesses&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Slash software operational costs while upgrading your data security posture by keeping all sensitive document processing entirely in-house.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;### For Anyone Who Works With Files&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Never pay to edit a basic file again. File Craft provides you with enterprise-grade utility suites completely free of charge.&lt;/p&gt;




&lt;h2&gt;
  
  
  Get File Craft
&lt;/h2&gt;

&lt;p&gt;Ready to break free from expensive monthly file-processing paywalls?&lt;/p&gt;

&lt;p&gt;🎁 &lt;strong&gt;&lt;a href="https://gumroad.com/" rel="noopener noreferrer"&gt;Get File Craft on Gumroad&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;By downloading, you directly support ongoing development, gain early access to priority updates, and contribute to a platform built by someone who simply wanted a fairer internet.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Building File Craft was a masterclass in turning developer frustration into open creation. I was tired of watching people pay for foundational operations, so I built an alternative. The stack is optimized, the features are comprehensive, and the price is permanently right: &lt;strong&gt;free&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Whether you need to merge three PDFs for a meeting, shrink a photo gallery, or extract text from a scanned receipt, File Craft handles it all—without the subscriptions, without the server privacy leaks, and without compromising on speed.&lt;/p&gt;

&lt;p&gt;Welcome to the no-subscription future. Welcome to File Craft. 🚀&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Have questions? Need a specific feature? Want to help write code? Reach out!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;File Craft — The file processing tool that respects your time, your money, and your privacy.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>pdf</category>
      <category>imagetool</category>
    </item>
    <item>
      <title>How to Download Your Entire Supabase Storage Bucket Locally</title>
      <dc:creator>jigz</dc:creator>
      <pubDate>Sun, 03 May 2026 09:23:02 +0000</pubDate>
      <link>https://dev.to/jigz_dev/how-to-download-your-entire-supabase-storage-bucket-locally-31g5</link>
      <guid>https://dev.to/jigz_dev/how-to-download-your-entire-supabase-storage-bucket-locally-31g5</guid>
      <description>&lt;p&gt;If you've been building with Supabase, you know their Storage API is fantastic for web apps. But sometimes, you just need your files on your local machine—whether for a manual backup, bulk editing, or migrating data.&lt;/p&gt;

&lt;p&gt;While you could write a script using the Supabase SDK, there is a much faster, "no-code" way to manage your files like a Pro: &lt;strong&gt;Cyberduck&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Cyberduck is an &lt;strong&gt;official Supabase partner integration&lt;/strong&gt;. It is a secure, open-source tool that Supabase explicitly recommends for managing storage via the S3 protocol. You can find the &lt;a href="https://supabase.com/partners/integrations/cyberduck" rel="noopener noreferrer"&gt;official integration page here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  Phase 1: Generate Your S3 Credentials
&lt;/h3&gt;

&lt;p&gt;Before opening Cyberduck, you need to give it permission to talk to your Supabase project via the S3 protocol.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Log in to your &lt;strong&gt;Supabase Dashboard&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; Navigate to the &lt;strong&gt;S3 Settings&lt;/strong&gt; tab in the sidebar (under Storage).&lt;/li&gt;
&lt;li&gt; Under &lt;strong&gt;Access Keys&lt;/strong&gt;, click &lt;strong&gt;Create Access Key&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; Give it a description (e.g., "Local Backup") and click &lt;strong&gt;Create&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Important:&lt;/strong&gt; Copy your &lt;strong&gt;Access Key ID&lt;/strong&gt; and &lt;strong&gt;Secret Access Key&lt;/strong&gt; immediately. You won't be able to see the secret again!&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Phase 2: Configure the Cyberduck Profile
&lt;/h3&gt;

&lt;p&gt;Cyberduck needs a specific "handshake" configuration to understand Supabase’s structure.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Download Cyberduck:&lt;/strong&gt; Get the latest version from their &lt;a href="https://cyberduck.io/download/" rel="noopener noreferrer"&gt;official download page&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Create the Profile:&lt;/strong&gt; Create a file on your computer named &lt;code&gt;supabase.cyberduckprofile&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Paste the following code&lt;/strong&gt; into that file:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;plist&lt;/span&gt; &lt;span class="na"&gt;version=&lt;/span&gt;&lt;span class="s"&gt;"1.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;dict&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;Protocol&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;s3&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;Vendor&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;Supabase Storage S3&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;Scheme&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;https&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;Description&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;Supabase Storage (S3)&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;Default Hostname&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;YOUR_PROJECT_REF.supabase.co&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;Default Port&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;443&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;Region&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;YOUR_REGION&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;Properties&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;array&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;s3.storage.class.options=STANDARD&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;s3.bucket.virtualhost.disable=true&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/array&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;Context&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;/storage/v1/s3&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/dict&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/plist&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Edit the file:&lt;/strong&gt; Replace &lt;code&gt;YOUR_PROJECT_REF&lt;/code&gt; with your project ID (found in your Supabase URL) and &lt;code&gt;YOUR_REGION&lt;/code&gt; (e.g., &lt;code&gt;ap-south-1&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Save and Run:&lt;/strong&gt; Double-click the file. Cyberduck will open and ask for your credentials. Enter the &lt;strong&gt;Access Key ID&lt;/strong&gt; and &lt;strong&gt;Secret Access Key&lt;/strong&gt; you generated earlier.&lt;/li&gt;
&lt;/ol&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%2Fowbielrqjz09opb8l64v.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%2Fowbielrqjz09opb8l64v.png" alt="Cyberduck" width="800" height="979"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Phase 3: Downloading Your Bucket
&lt;/h3&gt;

&lt;p&gt;Once connected, you will see your Supabase buckets listed just like folders on your computer.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Select your Bucket:&lt;/strong&gt; Locate the folder you wish to bring local.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Download:&lt;/strong&gt; Right-click the bucket and select &lt;strong&gt;Download&lt;/strong&gt;. You can choose the destination folder on your machine, and Cyberduck will handle the transfer.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Sync/Mirror:&lt;/strong&gt; If you want to keep your local folder updated with the latest changes from the cloud without re-downloading everything, use the &lt;strong&gt;Mirror&lt;/strong&gt; feature. This compares the local and remote folders and only transfers the differences.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Other Powerful Use Cases
&lt;/h3&gt;

&lt;p&gt;Connecting via S3 is about more than just backups. Here’s what else you can do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Bulk Uploads:&lt;/strong&gt; Drag and drop thousands of assets (like product images or icons) directly into Supabase. It’s much more stable than using a browser-based dashboard for large volumes.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Direct Media Editing:&lt;/strong&gt; Some editors allow you to open a file directly from Cyberduck, edit it, and save it back to the cloud instantly.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Cross-Cloud Migration:&lt;/strong&gt; If you are moving files from AWS S3 or Cloudflare R2 into Supabase (or vice-versa), you can open two windows in Cyberduck and simply drag-and-drop between the two services.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Infrastructure Testing:&lt;/strong&gt; It's an excellent way for developers to verify that their S3 policies and IAM-style permissions are working correctly before writing a single line of frontend code.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>supabase</category>
      <category>s3</category>
      <category>storage</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>What is GEO (Generative Engine Optimization)? How to Implement It in Next.js</title>
      <dc:creator>jigz</dc:creator>
      <pubDate>Wed, 25 Mar 2026 12:52:35 +0000</pubDate>
      <link>https://dev.to/jigz_dev/what-is-geo-generative-engine-optimization-how-to-implement-it-in-nextjs-23d6</link>
      <guid>https://dev.to/jigz_dev/what-is-geo-generative-engine-optimization-how-to-implement-it-in-nextjs-23d6</guid>
      <description>&lt;p&gt;If you search something today, you’ll notice a shift.&lt;/p&gt;

&lt;p&gt;Instead of just showing links, search tools are now giving direct answers. Tools like ChatGPT, Perplexity, and Google AI Overviews generate responses instead of listing pages.&lt;/p&gt;

&lt;p&gt;Those answers come from somewhere.&lt;/p&gt;

&lt;p&gt;That’s where GEO comes in.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is GEO?
&lt;/h2&gt;

&lt;p&gt;GEO stands for Generative Engine Optimization.&lt;/p&gt;

&lt;p&gt;It means structuring your content so AI tools can understand it and use it inside their generated answers.&lt;/p&gt;

&lt;p&gt;Earlier, the goal was to rank on search engines.&lt;/p&gt;

&lt;p&gt;Now, the goal is to be part of the answer itself.&lt;/p&gt;

&lt;p&gt;So instead of optimizing just for clicks, you’re optimizing for visibility inside AI responses.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why GEO Matters
&lt;/h2&gt;

&lt;p&gt;When someone asks a question to an AI tool, they usually get a complete answer instantly.&lt;/p&gt;

&lt;p&gt;Most users don’t click further.&lt;/p&gt;

&lt;p&gt;If your content is not included in that answer, it doesn’t get seen.&lt;/p&gt;

&lt;p&gt;That’s the main shift.&lt;/p&gt;

&lt;p&gt;It’s no longer just about ranking. It’s about being referenced.&lt;/p&gt;




&lt;h2&gt;
  
  
  How GEO is Different
&lt;/h2&gt;

&lt;p&gt;Traditional SEO focuses on ranking pages.&lt;/p&gt;

&lt;p&gt;GEO focuses on clarity and structure.&lt;/p&gt;

&lt;p&gt;AI systems don’t care about keyword stuffing. They care about how clearly you explain something.&lt;/p&gt;

&lt;p&gt;The better your explanation, the higher the chance it gets picked.&lt;/p&gt;




&lt;h2&gt;
  
  
  How to Implement GEO in Next.js
&lt;/h2&gt;

&lt;p&gt;You don’t need complex setups. Most of it comes down to how you write and structure content.&lt;/p&gt;

&lt;p&gt;Here’s how you can do it.&lt;/p&gt;




&lt;h3&gt;
  
  
  1. Add Structured Data (JSON-LD)
&lt;/h3&gt;

&lt;p&gt;Structured data helps machines understand your content.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Page&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;schema&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="s2"&gt;@context&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="s2"&gt;https://schema.org&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="s2"&gt;@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="s2"&gt;SoftwareApplication&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="s2"&gt;name&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="s2"&gt;Your App Name&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="s2"&gt;description&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="s2"&gt;Short explanation of what your app does&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="s2"&gt;applicationCategory&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="s2"&gt;DeveloperApplication&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="s2"&gt;offers&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@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="s2"&gt;Offer&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="s2"&gt;price&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="s2"&gt;0&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;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"application/ld+json"&lt;/span&gt;
        &lt;span class="na"&gt;dangerouslySetInnerHTML&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;__html&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;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;h3&gt;
  
  
  2. Write Answer-First Content
&lt;/h3&gt;

&lt;p&gt;Start with the answer.&lt;/p&gt;

&lt;p&gt;Don’t delay it with long introductions.&lt;/p&gt;

&lt;p&gt;AI tools prefer content that gives clear, direct answers immediately.&lt;/p&gt;


&lt;h3&gt;
  
  
  3. Use FAQ Sections
&lt;/h3&gt;

&lt;p&gt;FAQ format works well because it matches how people ask questions.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;faqs&lt;/span&gt; &lt;span class="o"&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;q&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;How do I generate a PDF in Next.js?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;You can use Puppeteer or jsPDF depending on your use case.&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;h3&gt;
  
  
  4. Add llms.txt
&lt;/h3&gt;

&lt;p&gt;Create a simple file in your public folder:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Your Website&lt;/span&gt;
&lt;span class="gt"&gt;
&amp;gt; Short explanation&lt;/span&gt;

&lt;span class="gu"&gt;## Features&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Feature one
&lt;span class="p"&gt;-&lt;/span&gt; Feature two

&lt;span class="gu"&gt;## Use cases&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Example one
&lt;span class="p"&gt;-&lt;/span&gt; Example two
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This helps AI tools understand your site faster.&lt;/p&gt;


&lt;h3&gt;
  
  
  5. Create “What is” and Comparison Content
&lt;/h3&gt;

&lt;p&gt;Write content that answers real questions.&lt;/p&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What is something&lt;/li&gt;
&lt;li&gt;How something works&lt;/li&gt;
&lt;li&gt;Comparison between tools&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is exactly what AI tools look for.&lt;/p&gt;


&lt;h3&gt;
  
  
  6. Use Static Generation
&lt;/h3&gt;

&lt;p&gt;Make your pages easy to crawl.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&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;generateStaticParams&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;posts&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;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slug&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;h3&gt;
  
  
  7. Keep Language Simple
&lt;/h3&gt;

&lt;p&gt;Write like you speak.&lt;/p&gt;

&lt;p&gt;Avoid complex words and long sentences.&lt;/p&gt;

&lt;p&gt;Clear and simple explanations work better.&lt;/p&gt;


&lt;h2&gt;
  
  
  What Actually Matters
&lt;/h2&gt;

&lt;p&gt;A few things make the biggest difference:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clear answers at the start&lt;/li&gt;
&lt;li&gt;Simple language&lt;/li&gt;
&lt;li&gt;Structured content&lt;/li&gt;
&lt;li&gt;Real examples&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You don’t need tricks. You need clarity.&lt;/p&gt;


&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;GEO is not replacing SEO.&lt;/p&gt;

&lt;p&gt;It’s building on top of it.&lt;/p&gt;

&lt;p&gt;Search is moving toward answers instead of links.&lt;/p&gt;

&lt;p&gt;That changes how content gets discovered.&lt;/p&gt;

&lt;p&gt;If your content explains things clearly, it has a higher chance of being used.&lt;/p&gt;

&lt;p&gt;That’s the core idea.&lt;/p&gt;


&lt;h2&gt;
  
  
  Original Blog
&lt;/h2&gt;

&lt;p&gt;Read the full version here:&lt;br&gt;
&lt;/p&gt;
&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://www.jigz.dev/blogs/what-is-geo-how-to-implement-it-in-nextjs" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjmooenpadbidpkpgwgqu.supabase.co%2Fstorage%2Fv1%2Fobject%2Fpublic%2Fblogs%2Fwhat-is-geo-how-to-implement-it-in-nextjs-1774442640007.jpg" height="auto" class="m-0"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://www.jigz.dev/blogs/what-is-geo-how-to-implement-it-in-nextjs" rel="noopener noreferrer" class="c-link"&gt;
            What is GEO? How to Implement It in Next.js
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            If you search something today, you might notice a shift.Instead of just seeing links, you often get a direct answer.Tools like ChatGPT, Perplexity, and Google AI Overviews don’t just show results, the...
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.jigz.dev%2Ffavicon.svg"&gt;
          jigz.dev
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



</description>
      <category>ai</category>
      <category>seo</category>
      <category>nextjs</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
