<?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: Chilam Chan</title>
    <description>The latest articles on DEV Community by Chilam Chan (@chilam_chan_68a518a731328).</description>
    <link>https://dev.to/chilam_chan_68a518a731328</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%2F4126468%2F43aa359e-1b8b-4f2d-bc35-ed6beca8920a.png</url>
      <title>DEV Community: Chilam Chan</title>
      <link>https://dev.to/chilam_chan_68a518a731328</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/chilam_chan_68a518a731328"/>
    <language>en</language>
    <item>
      <title>How I built 15 browser tools with zero backend</title>
      <dc:creator>Chilam Chan</dc:creator>
      <pubDate>Wed, 16 Sep 2026 04:06:18 +0000</pubDate>
      <link>https://dev.to/chilam_chan_68a518a731328/how-i-built-15-browser-tools-with-zero-backend-4ffi</link>
      <guid>https://dev.to/chilam_chan_68a518a731328/how-i-built-15-browser-tools-with-zero-backend-4ffi</guid>
      <description>&lt;p&gt;Every "free online tool" I reached for wanted an upload, an account, or both. So I built 15 that need neither — and the constraint that made that possible turned out to be the best decision in the project: no backend at all.&lt;/p&gt;

&lt;p&gt;Here's what runs where.&lt;/p&gt;

&lt;h2&gt;
  
  
  The browser can do more than we give it credit for
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Image work (HEIC→JPG, compress, resize, strip EXIF): &lt;code&gt;&amp;lt;canvas&amp;gt;&lt;/code&gt; + &lt;code&gt;createImageBitmap&lt;/code&gt;, and WASM (&lt;code&gt;heic2any&lt;/code&gt;) for formats the browser can't decode natively.&lt;/li&gt;
&lt;li&gt;PDF split/merge: &lt;code&gt;pdf-lib&lt;/code&gt;, entirely client-side.&lt;/li&gt;
&lt;li&gt;QR codes, password generation, JSON formatting, word counting: plain JS + &lt;code&gt;crypto.getRandomValues&lt;/code&gt; and &lt;code&gt;Intl.Segmenter&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nothing touches a server. "Your files never leave your device" isn't a privacy promise you have to trust — it's just how the thing works. Open DevTools → Network and watch: no request fires when you convert a file.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why no-backend is a superpower for a solo dev
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;$0 to run.&lt;/strong&gt; A zero-dependency static site generator emits plain HTML; Cloudflare Pages serves it free. 272 pages (15 tools × 16 languages + hub) cost nothing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nothing to operate.&lt;/strong&gt; No servers, no uploads to secure, no data to leak, no scaling. The whole "ops" surface is a git push.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It's genuinely private&lt;/strong&gt;, which is a real differentiator when every competitor uploads your file to "process" it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The tradeoffs (being honest)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;No accounts, no cross-device sync, no server-side history. For utilities, that's fine — you do one thing and leave.&lt;/li&gt;
&lt;li&gt;Some formats (TIFF, exotic codecs) the browser just won't decode; you draw the line and say so.&lt;/li&gt;
&lt;li&gt;SEO is the whole growth engine, since there's no viral loop. That's the part I'm still figuring out.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're sitting on a "should this be a SaaS or just a tool" decision: a surprising amount can be &lt;em&gt;just a tool&lt;/em&gt;, and shipping it that way is faster, cheaper, and more private.&lt;/p&gt;

&lt;p&gt;Tools are here if useful: &lt;a href="https://boring-tools-6ip.pages.dev" rel="noopener noreferrer"&gt;https://boring-tools-6ip.pages.dev&lt;/a&gt; — happy to go deeper on any part of the stack in the comments.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>privacy</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Stop pasting sensitive JSON into random online formatters</title>
      <dc:creator>Chilam Chan</dc:creator>
      <pubDate>Tue, 15 Sep 2026 17:04:58 +0000</pubDate>
      <link>https://dev.to/chilam_chan_68a518a731328/stop-pasting-sensitive-json-into-random-online-formatters-26e1</link>
      <guid>https://dev.to/chilam_chan_68a518a731328/stop-pasting-sensitive-json-into-random-online-formatters-26e1</guid>
      <description>&lt;p&gt;Every developer has done it: you get an ugly one-line JSON blob back from an API, and you paste it into the first "JSON formatter online" result to make it readable.&lt;/p&gt;

&lt;p&gt;Here's the problem. Half the time that blob is a real response from &lt;em&gt;your&lt;/em&gt; system — it can contain access tokens, internal IDs, customer emails, signed URLs, session data. The moment you paste it into a random web tool, you've sent that data to a server you don't control. You don't know if it's logged, cached, or sitting in someone's analytics pipeline.&lt;/p&gt;

&lt;p&gt;For a side project, maybe you shrug. Inside a company with a compliance team, that's the kind of thing that ends up in an incident review.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fix: format JSON in the browser, not on a server
&lt;/h2&gt;

&lt;p&gt;You don't need a server to pretty-print JSON. Everything — parsing, formatting, validating, minifying — can happen entirely client-side with &lt;code&gt;JSON.parse&lt;/code&gt; / &lt;code&gt;JSON.stringify&lt;/code&gt;. The data never has to leave the tab.&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="c1"&gt;// This is the whole "backend" of a JSON formatter:&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pretty&lt;/span&gt; &lt;span class="o"&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;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&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="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A tool built this way can even work offline once the page has loaded, because there's nothing to call home to.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to check if a tool is actually client-side
&lt;/h2&gt;

&lt;p&gt;Don't take a site's word for it. Open DevTools → Network tab, paste your JSON, hit format, and watch:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No new request fires&lt;/strong&gt; → the work happened locally. Safe.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A request goes out with your JSON in the payload&lt;/strong&gt; → your data just left the building.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do this once with any "online" dev tool that eats sensitive input (JSON, JWT decoders, "beautifiers", diff tools). You'll be surprised how many phone home.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I ended up using
&lt;/h2&gt;

&lt;p&gt;I got tired of doing that Network-tab check every time, so I built a JSON formatter that's 100% client-side — format, validate, minify, nothing uploaded, no signup:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://boring-tools-6ip.pages.dev/json-formatter/" rel="noopener noreferrer"&gt;https://boring-tools-6ip.pages.dev/json-formatter/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's part of a small set of no-upload browser utilities I'm building solo. If you deal with sensitive payloads regularly, the "does this leave my machine?" habit is worth building regardless of which tool you land on.&lt;/p&gt;

&lt;p&gt;What's your rule of thumb for pasting real data into third-party dev tools? Curious how others draw the line.&lt;/p&gt;

</description>
      <category>json</category>
      <category>webdev</category>
      <category>privacy</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
