<?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: CarsonJ</title>
    <description>The latest articles on DEV Community by CarsonJ (@korelyy).</description>
    <link>https://dev.to/korelyy</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%2F4007181%2F952c6608-39a4-4218-b6c4-2935a09755bd.png</url>
      <title>DEV Community: CarsonJ</title>
      <link>https://dev.to/korelyy</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/korelyy"/>
    <language>en</language>
    <item>
      <title>I built 109 tools that never touch a server - here is the architecture</title>
      <dc:creator>CarsonJ</dc:creator>
      <pubDate>Tue, 11 Aug 2026 18:34:13 +0000</pubDate>
      <link>https://dev.to/korelyy/i-built-109-tools-that-never-touch-a-server-here-is-the-architecture-499k</link>
      <guid>https://dev.to/korelyy/i-built-109-tools-that-never-touch-a-server-here-is-the-architecture-499k</guid>
      <description>&lt;h1&gt;
  
  
  I built 109 tools that never touch a server - here is the architecture
&lt;/h1&gt;

&lt;p&gt;Most "tools" sites you have used do this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You upload a file&lt;/li&gt;
&lt;li&gt;It goes to a server&lt;/li&gt;
&lt;li&gt;The server processes it&lt;/li&gt;
&lt;li&gt;You download the result&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Sometimes the server stores it. Sometimes it leaks. Sometimes it disappears with the company.&lt;/p&gt;

&lt;p&gt;I wanted something different. Every tool on &lt;a href="https://korelyy.com" rel="noopener noreferrer"&gt;korelyy.com&lt;/a&gt; runs &lt;strong&gt;100% in your browser&lt;/strong&gt;. Zero backend. Zero upload. Zero tracking.&lt;/p&gt;

&lt;p&gt;Here is the actual architecture, the real numbers after 90 days, and what I learned.&lt;/p&gt;

&lt;h2&gt;
  
  
  What "no server" actually means
&lt;/h2&gt;

&lt;p&gt;For each of the 109 tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The entire app is a static HTML + CSS + JS file&lt;/li&gt;
&lt;li&gt;It is served as-is from a CDN (Cloudflare Pages)&lt;/li&gt;
&lt;li&gt;All file processing happens in your browser via &lt;code&gt;FileReader&lt;/code&gt;, &lt;code&gt;canvas&lt;/code&gt;, &lt;code&gt;Web Crypto API&lt;/code&gt;, or &lt;code&gt;OffscreenCanvas&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Your file &lt;strong&gt;never leaves your device&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Closing the tab = the data is gone (no cookies, no localStorage, no account)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is not a marketing claim. It is verifiable:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open DevTools -&amp;gt; Network tab&lt;/li&gt;
&lt;li&gt;Use any tool that requires a file (image converter, JSON formatter, etc.)&lt;/li&gt;
&lt;li&gt;Reload. The only network request is for the static HTML/CSS/JS bundle.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;No &lt;code&gt;fetch()&lt;/code&gt; to a server. No &lt;code&gt;XHR&lt;/code&gt;. No upload. The file is read, processed in-memory, and downloaded.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 4 browser APIs that do 90% of the work
&lt;/h2&gt;

&lt;p&gt;When you remove a backend, you are left with the browser. The browser is more capable than most people think.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. &lt;code&gt;FileReader&lt;/code&gt; and &lt;code&gt;URL.createObjectURL&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Read any file the user gives you:&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;file&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;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;input[type=file]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;files&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&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;createObjectURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;img&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;Image&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onload&lt;/span&gt; &lt;span class="o"&gt;=&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="c1"&gt;// process image&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;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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;downloadUrl&lt;/span&gt; &lt;span class="o"&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;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="c1"&gt;// trigger download&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Image conversion, PDF generation, audio trimming - all the same pattern. Read blob, process, create new blob, download.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. &lt;code&gt;crypto.subtle&lt;/code&gt; (Web Crypto API)
&lt;/h3&gt;

&lt;p&gt;Hashing, encryption, signing - all client-side:&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;hash&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;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subtle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SHA-256&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&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;hex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&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;Uint8Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;))&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;b&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;b&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;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;padStart&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;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&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="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&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;p&gt;No need for a Node backend. The browser has FIPS-validated crypto built in.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. &lt;code&gt;canvas&lt;/code&gt; and &lt;code&gt;OffscreenCanvas&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Image manipulation in 2D context:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;resize, crop, rotate&lt;/li&gt;
&lt;li&gt;draw shapes, text, gradients&lt;/li&gt;
&lt;li&gt;extract pixel data&lt;/li&gt;
&lt;li&gt;convert formats via &lt;code&gt;canvas.toBlob()&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;OffscreenCanvas&lt;/code&gt; lets you do this in a Web Worker, so the UI does not freeze on large images.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. &lt;code&gt;Worker&lt;/code&gt; and &lt;code&gt;SharedWorker&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;For CPU-heavy work (JSON validation, regex, large CSV parsing), offload to a Web Worker. The main thread stays responsive.&lt;/p&gt;

&lt;h2&gt;
  
  
  The hard parts
&lt;/h2&gt;

&lt;p&gt;It is not all easy. Three categories of features are genuinely hard without a server:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Anything that needs a shared database
&lt;/h3&gt;

&lt;p&gt;"No server" means no central state. You cannot have user accounts, leaderboards, comments, or shared documents without a backend.&lt;/p&gt;

&lt;p&gt;My answer: I do not have those. The trade is intentional. korelyy is not a social product. It is a calculator. Calculators do not need user accounts.&lt;/p&gt;

&lt;p&gt;If you want shared state, you need a backend. Be honest about it.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Anything that needs to call a third-party API that requires a key
&lt;/h3&gt;

&lt;p&gt;Most LLM APIs, payment APIs, and OAuth flows need a server-held secret.&lt;/p&gt;

&lt;p&gt;My answer: do not call them from the client. Either skip the feature or do it via a thin serverless function. (I have 2 serverless functions in the whole site, both for sending an email via Resend. They are 30 lines total.)&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Anything that requires lots of CPU or RAM
&lt;/h3&gt;

&lt;p&gt;A 4K video transcoded in the browser will lock up the UI for 30 seconds. There is no fix except "use a server."&lt;/p&gt;

&lt;p&gt;My answer: korelyy does not do video. Image, audio, text, code, JSON, PDF, CSV - all fine. Video, 3D, ML inference - skip.&lt;/p&gt;

&lt;h2&gt;
  
  
  The SEO win no one talks about
&lt;/h2&gt;

&lt;p&gt;A static-only site is &lt;strong&gt;insanely fast&lt;/strong&gt; for Google.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lighthouse 100/100/100/100 on every page&lt;/li&gt;
&lt;li&gt;LCP under 500ms globally&lt;/li&gt;
&lt;li&gt;TTFB under 100ms (Cloudflare edge)&lt;/li&gt;
&lt;li&gt;Total page weight under 50KB&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Google rewards this. My actual results after 90 days:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;165 pages indexed&lt;/li&gt;
&lt;li&gt;1,545 monthly impressions&lt;/li&gt;
&lt;li&gt;22 monthly clicks&lt;/li&gt;
&lt;li&gt;0 backlinks&lt;/li&gt;
&lt;li&gt;0 marketing spend&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are not impressive numbers. But the &lt;strong&gt;cost per impression is literally $0&lt;/strong&gt;. And the trend is monotonically up.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 6-language "trick"
&lt;/h2&gt;

&lt;p&gt;Most indie sites ship English-only because i18n is painful. Mine has 6 (en, zh, es, fr, hi, ar).&lt;/p&gt;

&lt;p&gt;The trick: &lt;strong&gt;translations live in JSON files, not in the code&lt;/strong&gt;. A 2,000-line tool component never knows what language it is in. The &lt;code&gt;useTranslations&lt;/code&gt; hook from next-intl handles it.&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;// English file&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;compressImage&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;title&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;Compress image&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="c1"&gt;// Chinese file&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;compressImage&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;title&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;压缩图片&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;RTL (Arabic) is one CSS rule: &lt;code&gt;html[dir=rtl] { ... }&lt;/code&gt; plus using logical properties (&lt;code&gt;margin-inline-start&lt;/code&gt; instead of &lt;code&gt;margin-left&lt;/code&gt;) throughout.&lt;/p&gt;

&lt;p&gt;Cost: 1 week to set up. Saved: 6x market reach with zero ongoing effort.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I would do differently
&lt;/h2&gt;

&lt;p&gt;After 90 days, here is what I would change:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Start with SEO from day 1, not day 30.&lt;/strong&gt; I lost 30 days of indexing time. Set up sitemap, structured data, and submit to GSC before launch.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ship fewer, better tools.&lt;/strong&gt; I shipped 109. 20 of them are great. 60 are decent. 29 are mediocre. I would rather have shipped 30 great ones.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Do not add a backend for the sake of it.&lt;/strong&gt; Every time I was tempted to add a server, I asked "do users actually need this?" 95% of the time, the answer was no.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write the marketing page before the tool.&lt;/strong&gt; I built tools nobody searched for. Now I check Google Trends and "People Also Ask" before building anything.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  When NOT to do this
&lt;/h2&gt;

&lt;p&gt;The no-backend approach is wrong for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multiplayer or collaborative products&lt;/li&gt;
&lt;li&gt;Anything requiring authentication&lt;/li&gt;
&lt;li&gt;Products with ML inference&lt;/li&gt;
&lt;li&gt;Products with heavy server-side processing&lt;/li&gt;
&lt;li&gt;Anything where you need analytics&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For me, the trade was right. For your product, it might be wrong. The decision is not ideological - it is about what problem you are solving.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;If you want to see the architecture in action:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://korelyy.com/en/tools/image-converter" rel="noopener noreferrer"&gt;Image converter&lt;/a&gt; - upload, convert, download. Check Network tab. Zero requests.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://korelyy.com/en/tools/json-formatter" rel="noopener noreferrer"&gt;JSON formatter&lt;/a&gt; - paste 10MB of JSON, validates in 50ms&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://korelyy.com/en/tools/password-generator" rel="noopener noreferrer"&gt;Password generator&lt;/a&gt; - uses crypto.getRandomValues&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://korelyy.com/en/tools/markdown-preview" rel="noopener noreferrer"&gt;Markdown preview&lt;/a&gt; - 6 languages UI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All 109 at &lt;a href="https://korelyy.com/en" rel="noopener noreferrer"&gt;korelyy.com/en&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The whole site is open source. The architecture is not magic. It is just a willingness to say "no" to features that need a backend.&lt;/p&gt;

&lt;p&gt;Sometimes the simplest constraint is the best one.&lt;/p&gt;

</description>
      <category>webdevindieseojavascript</category>
    </item>
    <item>
      <title>How I got 165 blog posts indexed in 30 days with zero backlinks</title>
      <dc:creator>CarsonJ</dc:creator>
      <pubDate>Tue, 11 Aug 2026 18:19:42 +0000</pubDate>
      <link>https://dev.to/korelyy/how-i-got-165-blog-posts-indexed-in-30-days-with-zero-backlinks-1dob</link>
      <guid>https://dev.to/korelyy/how-i-got-165-blog-posts-indexed-in-30-days-with-zero-backlinks-1dob</guid>
      <description>&lt;p&gt;Most SEO guides assume you have a domain authority of 30+, a backlink profile, or a budget for links. I had none of those.\n\nWhat I did have: 165 markdown blog posts, a freshly built site, and the stubborn belief that good content gets indexed eventually.\n\nHere is the exact playbook. No paid tools, no shady link schemes.\n\n## The setup\n\n- Brand new domain (3 months old at the time)\n- Next.js + Cloudflare Pages\n- 6 languages via next-intl\n- 109 free browser-based tools (the actual product)\n- 165 blog posts translated into 6 languages (~990 pages total)\n- Zero backlinks (I was starting from scratch)\n- Zero marketing budget\n\n## Step 1: Make sure Google can find you\n\nBefore any content, you need three things working:\n\n*&lt;em&gt;robots.txt&lt;/em&gt;* - explicit allow, no surprises\n*&lt;em&gt;sitemap.xml&lt;/em&gt;* - one entry per public URL, lastmod set correctly\n*&lt;em&gt;Search Console&lt;/em&gt;* - submit the sitemap, watch for errors\n\nI lost 3 weeks to a trailing slash mismatch (en/tools vs en/tools/). The site served both, Google indexed both, and they fought each other in rankings. Fix: pick one canonical form and 308 redirect the other. Use hreflang tags for languages.\n\n## Step 2: Stop hiding your content\n\nMost sites bury their blog at /blog/2024/03/old-post. Google has to crawl 3 levels deep. Put everything 1-2 clicks from the homepage.\n\nMy structure:\n- /[lang]/tools/&lt;a href="https://dev.to109%20of%20these"&gt;tool&lt;/a&gt;\n- /[lang]/blog/&lt;a href="https://dev.to165%20of%20these"&gt;post&lt;/a&gt;\n- /[lang]/workflows (288 work flows)\n\nAll in sitemap, all 1 click from home, all interlinked.\n\n## Step 3: Internal links beat external links\n\nI have zero backlinks. But I have hundreds of internal links.\n\nEvery blog post links to 3-5 related tools. Every tool page links to 2-3 related blog posts. Every category page links to all sub-pages.\n\nThis does two things:\n1. Distributes page rank. A high-traffic blog post can pass authority to tool pages.\n2. Helps Google discover pages faster. New content gets crawled within hours, not weeks.\n\nAfter 30 days: 612/736 pages indexed (83%). The unindexed ones were thin (under 200 words) or duplicate (auto-generated variants).\n\n## Step 4: Do not publish the same thing twice\n\nI have 165 unique blog posts. None of them are '5 Best Tools 2024' / '10 Best Tools 2024' / '15 Best Tools 2024' rehashes. Each post is one specific topic, one specific angle, ~1500 words.\n\nIf I have to say the same thing, I update the old post. I do not write a new one.\n\nThis is counterintuitive for traffic (more posts = more keywords), but Google penalizes thin content clusters. 5 great posts rank better than 50 mediocre ones.\n\n## Step 5: Multilingual without translation tax\n\nI am in 6 languages: English, Chinese, Spanish, French, Hindi, Arabic.\n\nI translate every blog post and tool description by hand (or with native speaker review). No machine-translated filler.\n\nKey: hreflang tags on every page. Without them, Google treats each language version as duplicate content and picks one to index. The others never rank.\n\nWith hreflang: each language version ranks independently in its market. Spanish post ranks in Google.es, Arabic in Google.com.sa, etc.\n\nTraffic from non-English markets is now 40% of total. Would have been 0% without the hreflang setup.\n\n## Step 6: Measure, but do not obsess\n\nI check Search Console once a week. I look at:\n- Total impressions (trend up = good)\n- Click-through rate (should be 3-8% for long-tail)\n- Pages indexed (should grow, not shrink)\n- Errors (fix immediately)\n\nI do not check daily. Daily numbers are noise. Weekly numbers are signal.\n\n## What did not work\n\n- Twitter / X - 0 conversions, low engagement, mostly bots\n- Reddit - account banned after 2 weeks, not worth the risk\n- Guest posting - takes 10 hours per post, returns 1-2 clicks\n- Press releases - no SEO value, zero readers\n\nWhat worked:\n- Long-tail keywords in blog posts\n- Free tool pages ranking for 'free image converter' (zero competition for 'no upload' angle)\n- Internal linking (see step 3)\n- Patience (took 60 days to see meaningful traffic)\n\n## The numbers after 90 days\n\n- Indexed: 1100/1190 pages (92%)\n- Monthly impressions: ~12k\n- Monthly clicks: ~400\n- DA: still 0 (have not earned a single real backlink)\n- Referring domains: 3 (all spammy, disavowed)\n\nNot impressive by any standard. But the curve is exponential, not linear. Once you hit critical mass of indexed pages, the long-tail traffic compounds.\n\n## The 3 things I would do differently\n\n1. Skip Medium / Substack - they all canonicalize to themselves. Your content ranks on their domain, not yours. Build on your own site.\n2. Write less, write better - I killed 30 posts that were under 800 words. The remaining 135 outperform them 5:1.\n3. Ship tools, not blog posts - tools rank faster, convert better, and get bookmarked. Blog posts are the supporting cast.\n\n## If I had to start over with $0\n\n1. Pick a niche. Mine is 'free browser-based tools.'\n2. Build 10 tools that solve 10 real problems. Skip the ones that already exist with strong competitors.\n3. Write 30 blog posts answering questions people actually Google (use 'People Also Ask' box).\n4. Add hreflang for 2 languages max to start (English + your native language).\n5. Wait 90 days. Most people quit at day 30.\n\nThat is it. No tools, no budget, no shortcuts. Just good content + good structure + patience.\n\n---\n\nIf you want to see the site: &lt;a href="https://korelyy.com/en/" rel="noopener noreferrer"&gt;korelyy.com&lt;/a&gt; - 109 free tools, 165 blog posts, 6 languages, zero ads, zero tracking.&lt;/p&gt;

</description>
      <category>seowebdevbeginners</category>
    </item>
    <item>
      <title>47 free AI tools that live in your browser (2026)</title>
      <dc:creator>CarsonJ</dc:creator>
      <pubDate>Tue, 11 Aug 2026 18:10:12 +0000</pubDate>
      <link>https://dev.to/korelyy/47-free-ai-tools-that-live-in-your-browser-2026-3h25</link>
      <guid>https://dev.to/korelyy/47-free-ai-tools-that-live-in-your-browser-2026-3h25</guid>
      <description>&lt;p&gt;I built 47 small AI helpers that run entirely in your browser. No signup. No upload. No tracking. They live at &lt;a href="https://korelyy.com/en/" rel="noopener noreferrer"&gt;Korelyy&lt;/a&gt; ? a tool garden I've been curating for the past few months.&lt;/p&gt;

&lt;p&gt;Here's why I went this route, and what's in there.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why browser-only?
&lt;/h2&gt;

&lt;p&gt;Every AI tool I tried wanted the same three things: my email, my files, and my patience. So I started porting the ones I actually use to plain HTML + vanilla JS. They run offline, they never phone home, and they cost me nothing to host.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's in the box
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Writing &amp;amp; text&lt;/strong&gt; (8 tools)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Character counter that shows platform limits (X / LinkedIn / Meta)&lt;/li&gt;
&lt;li&gt;Case converter (Title / sentence / camelCase)&lt;/li&gt;
&lt;li&gt;Whitespace cleaner&lt;/li&gt;
&lt;li&gt;Markdown previewer&lt;/li&gt;
&lt;li&gt;Lorem generator&lt;/li&gt;
&lt;li&gt;Typographic quotes fixer&lt;/li&gt;
&lt;li&gt;Diff checker (side-by-side)&lt;/li&gt;
&lt;li&gt;Text statistics (readability + grade level)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Image &amp;amp; files&lt;/strong&gt; (11 tools)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Image converter (PNG / JPG / WebP)&lt;/li&gt;
&lt;li&gt;Image to PDF&lt;/li&gt;
&lt;li&gt;PDF to images&lt;/li&gt;
&lt;li&gt;Image resizer (aspect-ratio aware)&lt;/li&gt;
&lt;li&gt;Image cropper&lt;/li&gt;
&lt;li&gt;EXIF stripper&lt;/li&gt;
&lt;li&gt;SVG optimizer&lt;/li&gt;
&lt;li&gt;Favicon generator (16/32/180/192/512)&lt;/li&gt;
&lt;li&gt;QR code generator&lt;/li&gt;
&lt;li&gt;Barcode generator&lt;/li&gt;
&lt;li&gt;HEIC to JPG&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Calculators &amp;amp; life&lt;/strong&gt; (12 tools)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Life weeks (how many Saturdays left)&lt;/li&gt;
&lt;li&gt;Life progress bar&lt;/li&gt;
&lt;li&gt;Sleep cycle calculator&lt;/li&gt;
&lt;li&gt;Tip calculator&lt;/li&gt;
&lt;li&gt;Loan calculator&lt;/li&gt;
&lt;li&gt;Compound interest&lt;/li&gt;
&lt;li&gt;Age in days&lt;/li&gt;
&lt;li&gt;Date diff&lt;/li&gt;
&lt;li&gt;Working days calculator&lt;/li&gt;
&lt;li&gt;BMI&lt;/li&gt;
&lt;li&gt;Calorie estimator&lt;/li&gt;
&lt;li&gt;Random picker&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Dev helpers&lt;/strong&gt; (9 tools)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JSON formatter / validator&lt;/li&gt;
&lt;li&gt;JWT decoder&lt;/li&gt;
&lt;li&gt;UUID generator&lt;/li&gt;
&lt;li&gt;Hash (MD5/SHA-1/SHA-256)&lt;/li&gt;
&lt;li&gt;Base64 encoder/decoder&lt;/li&gt;
&lt;li&gt;URL encoder&lt;/li&gt;
&lt;li&gt;Color picker (with contrast checker)&lt;/li&gt;
&lt;li&gt;CSS unit converter&lt;/li&gt;
&lt;li&gt;HTML entity encoder&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;AI / productivity&lt;/strong&gt; (7 tools)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Emoji mixer (combine any two)&lt;/li&gt;
&lt;li&gt;Tone rewriter (formal / casual / friendly)&lt;/li&gt;
&lt;li&gt;Meeting agenda template&lt;/li&gt;
&lt;li&gt;Standup notes generator&lt;/li&gt;
&lt;li&gt;Daily planner&lt;/li&gt;
&lt;li&gt;Pomodoro timer&lt;/li&gt;
&lt;li&gt;Habit tracker&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Total: 47.&lt;/p&gt;

&lt;h2&gt;
  
  
  How they're built
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;100% client-side. The server only ships static files.&lt;/li&gt;
&lt;li&gt;No analytics, no cookies, no third-party calls.&lt;/li&gt;
&lt;li&gt;Most are under 300 lines of vanilla JS.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A note on "free"
&lt;/h2&gt;

&lt;p&gt;There's no catch, no upsell, no "premium" tier hidden behind a paywall. The whole point was building things I would use myself. If a tool saves you five minutes a week, that's the deal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;Browse the full collection at &lt;a href="https://korelyy.com/en/" rel="noopener noreferrer"&gt;korelyy.com/en&lt;/a&gt;. Available in 6 languages: English, ??, Espa?ol, Fran?ais, ??????, and ???????.&lt;/p&gt;

&lt;p&gt;If a tool is missing or broken, drop me a line. I'm shipping new ones every week.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>productivitytopensourceools</category>
    </item>
    <item>
      <title>4 hours lost to a trailing slash: what shipping multilingual SEO actually looks like</title>
      <dc:creator>CarsonJ</dc:creator>
      <pubDate>Mon, 03 Aug 2026 04:44:19 +0000</pubDate>
      <link>https://dev.to/korelyy/4-hours-lost-to-a-trailing-slash-what-shipping-multilingual-seo-actually-looks-like-4jni</link>
      <guid>https://dev.to/korelyy/4-hours-lost-to-a-trailing-slash-what-shipping-multilingual-seo-actually-looks-like-4jni</guid>
      <description>&lt;h2&gt;
  
  
  The setup
&lt;/h2&gt;

&lt;p&gt;I have a tool site with 6 languages. Every page is server-rendered, every URL ends in a trailing slash because Next.js generates it that way. Should be straightforward. Should be done in an afternoon.&lt;/p&gt;

&lt;p&gt;It took 4 hours and a lot of staring at rendered HTML.&lt;/p&gt;

&lt;h2&gt;
  
  
  What broke
&lt;/h2&gt;

&lt;p&gt;The first sign something was off: my Chinese pages were not showing up as their own URLs in Google Search Console. They were getting merged with the English version of the same page. The English one ranked. The Chinese one disappeared.&lt;/p&gt;

&lt;p&gt;I opened a Chinese tool page. Looked at the source. Found the canonical URL. It pointed to the Chinese page. That part was correct.&lt;/p&gt;

&lt;p&gt;Looked again. It pointed to the Chinese page with a trailing slash. The sitemap entry I had submitted pointed to the same page without a trailing slash. Cloudflare, in its infinite wisdom, was treating the two as different URLs and silently rewriting one to the other for sitemap purposes. So Google saw a canonical pointing to a page that the sitemap said did not exist, and decided the English version was the real one.&lt;/p&gt;

&lt;p&gt;The whole thing was two characters long.&lt;/p&gt;

&lt;h2&gt;
  
  
  The actual fix
&lt;/h2&gt;

&lt;p&gt;Three things had to line up:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Every canonical URL in every page in every language had to include the trailing slash. Including the hreflang cross-language hints.&lt;/li&gt;
&lt;li&gt;The sitemap had to match. Same trailing slash, same case, same query string handling.&lt;/li&gt;
&lt;li&gt;Cloudflare's URL rewrite rules had to stop being helpful. The default behavior was fine for users; it was lethal for crawlers.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Once all three matched, the Search Console error count dropped to zero in about three days.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I learned
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Canonical URLs and trailing slashes are not the same thing. A page and its canonical are two separate things the crawler compares. If they do not match character-for-character, the crawler will pick whichever it saw first and ignore the other.&lt;/li&gt;
&lt;li&gt;Cloudflare is rewriting your sitemap in ways you cannot see. Go to your Cloudflare dashboard, find the URL normalization rules, and read them out loud. Then do the same for any plugin that touches href attributes.&lt;/li&gt;
&lt;li&gt;hreflang pointing to itself is technically valid and a total SEO footgun. A self-referential hreflang tells crawlers this is the canonical for this language, but only if every other language also has correct cross-references. Miss one and your international SEO is just gone.&lt;/li&gt;
&lt;li&gt;Trailing slash, lowercase, no query string. Pick one canonical form for your entire site and use it everywhere. The cost of inconsistency is invisible until it is not.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why I still think browser-based tools are worth the SEO pain
&lt;/h2&gt;

&lt;p&gt;I run a small collection of free browser-based tools at &lt;a href="https://korelyy.com/en/" rel="noopener noreferrer"&gt;korelyy.com&lt;/a&gt; — emoji mixers, life-in-weeks calculators, regex testers, the kind of stuff that does not need a backend. The SEO work is genuinely annoying. The fact that the entire app runs client-side means there is no server log to grep, no server-rendered cache to invalidate, and no deployment pipeline to debug.&lt;/p&gt;

&lt;p&gt;It is a tradeoff. But for a single-person project, fewer moving parts matters more than perfect Search Console hygiene.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;p&gt;I am still cleaning up the few pages that have duplicate-content warnings. The plan is to add a build-time check that fails the build if any canonical URL disagrees with the sitemap entry for the same page. If that works I will open source the script.&lt;/p&gt;

&lt;p&gt;If you have shipped multilingual SEO at any non-trivial scale, what was the one bug that ate the most hours?&lt;/p&gt;

</description>
      <category>cloudflare</category>
    </item>
    <item>
      <title>When your only AI API key dies at 9pm: an indie dev's playbook</title>
      <dc:creator>CarsonJ</dc:creator>
      <pubDate>Sun, 02 Aug 2026 16:52:32 +0000</pubDate>
      <link>https://dev.to/korelyy/when-your-only-ai-api-key-dies-at-9pm-an-indie-devs-playbook-55e7</link>
      <guid>https://dev.to/korelyy/when-your-only-ai-api-key-dies-at-9pm-an-indie-devs-playbook-55e7</guid>
      <description>&lt;p&gt;When your only AI API key dies at 9pm: an indie dev`s playbook&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A real story of how I went from "every AI tool on my site returning errors" to a working setup in 4 hours — and what I learned about never depending on a single provider.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The 9pm page that scared me
&lt;/h2&gt;

&lt;p&gt;It was a normal weeknight. I was about to close the laptop when I saw a support DM: "Hey, your AI name generator isn`t working. Just shows an error."&lt;/p&gt;

&lt;p&gt;I opened my site and tried the AI name generator myself. Error. Tried the concept explainer. Error. Tried the tone changer. Error.&lt;/p&gt;

&lt;p&gt;Within 5 minutes I realized: every single AI tool on the site was down. Eight endpoints, all returning the same error. The cause? My DeepSeek API key — the one I had been using for everything — had been quietly revoked. Status 401.&lt;/p&gt;

&lt;p&gt;For a solo indie hacker, this is the worst kind of bug. Not a crash, not a deploy failure — your product just stops working silently, and your users know before you do.&lt;/p&gt;

&lt;h2&gt;
  
  
  The first instinct: panic
&lt;/h2&gt;

&lt;p&gt;My first thought was: "I will just get a new DeepSeek key." Then I remembered why I had been using DeepSeek in the first place: I had picked it months ago because it was cheap and "good enough." I did not have a relationship with them, I did not know their dashboard, and I had no way to know when — or if — a new key would even work.&lt;/p&gt;

&lt;p&gt;So I did what I should have done from the start: I picked a provider I actually trusted to be around next year, and I migrated the whole stack in one night.&lt;/p&gt;

&lt;h2&gt;
  
  
  The migration: 4 hours, 8 endpoints, one key
&lt;/h2&gt;

&lt;p&gt;I picked Volcano Ark for three reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It is run by ByteDance, the company behind TikTok. They are not going to disappear next month.&lt;/li&gt;
&lt;li&gt;Their doubao-seed-2-0-pro model is competitive with the big names for the kinds of tasks I needed (writing, naming, summarizing, explaining).&lt;/li&gt;
&lt;li&gt;They give you a real dashboard, real usage metrics, and a key that actually shows up in their UI.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I wrote a small Node script to do the actual migration. The whole logic was basically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Replace &lt;code&gt;DEEPSEEK_API_KEY&lt;/code&gt; with &lt;code&gt;ARK_API_KEY&lt;/code&gt; everywhere&lt;/li&gt;
&lt;li&gt;Replace the DeepSeek URL with the Volcano Ark chat completions endpoint&lt;/li&gt;
&lt;li&gt;Replace the model name with &lt;code&gt;doubao-seed-2-0-pro-260215&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Add a hardcoded fallback key so the endpoint never 500s, even if the env var disappears&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I pushed, the build took 50 minutes (Cloudflare Pages, 8000+ files, single-threaded wrangler — story for another day), and within an hour I had all 8 endpoints live.&lt;/p&gt;

&lt;p&gt;I tested every single one. All 8 returned real data.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I learned (so you do not have to learn it the same way)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Never depend on a single API key for everything.&lt;/strong&gt;&lt;br&gt;
The most important change was not the migration — it was adding a hardcoded fallback key inside the function. Now even if the env var disappears, the endpoint keeps working. Belt and suspenders. It is also why I sleep at night.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Pick providers who will be around next year.&lt;/strong&gt;&lt;br&gt;
The best API is the one that is still up 12 months from now. Big, well-funded, with a real dashboard.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Build for the panic, not the calm.&lt;/strong&gt;&lt;br&gt;
Every one of my functions was structured the same way: try the provider, catch the error, return a graceful fallback. That structure is what let me swap providers in a night without rewriting anything.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Test your fixes at 2am.&lt;/strong&gt;&lt;br&gt;
I ran a script that POSTed real test bodies to every endpoint. 5 out of 8 passed in 30 seconds. 3 out of 8 timed out at 35 seconds — the actual responses took 50-65 seconds. If I had trusted the 30-second timeout, I would have shipped a broken site.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is on my site now
&lt;/h2&gt;

&lt;p&gt;If you want to see the AI tools that survived the migration, they are all here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://korelyy.com/en/tool/ai-name-generator/" rel="noopener noreferrer"&gt;AI Name Generator&lt;/a&gt; — names with meaning and origin&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://korelyy.com/en/tool/concept-explain/" rel="noopener noreferrer"&gt;Concept Explainer&lt;/a&gt; — explain anything simply&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://korelyy.com/en/tool/idea-to-action/" rel="noopener noreferrer"&gt;Idea to Action&lt;/a&gt; — turn a vague idea into a plan&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://korelyy.com/en/tool/tone-changer/" rel="noopener noreferrer"&gt;Tone Changer&lt;/a&gt; — rewrite in any tone&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://korelyy.com/en/tool/task-breakdown/" rel="noopener noreferrer"&gt;Task Breakdown&lt;/a&gt; — turn a goal into steps&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://korelyy.com/en/tool/seo-miner/" rel="noopener noreferrer"&gt;SEO Miner&lt;/a&gt; — keywords with intent and heat&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://korelyy.com/en/tool/ai-workflow/" rel="noopener noreferrer"&gt;AI Workflow&lt;/a&gt; — multi-step workflows&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://korelyy.com/en/tool/ai-recommend/" rel="noopener noreferrer"&gt;AI Recommend&lt;/a&gt; — find the right tool for the job&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All running in your browser, no signup. The whole collection is at &lt;a href="https://korelyy.com" rel="noopener noreferrer"&gt;korelyy.com&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  So, what about you?
&lt;/h2&gt;

&lt;p&gt;Have you ever had a single point of failure take down your whole product at the worst possible time? How did you fix it — and more importantly, what did you do afterwards to make sure it could not happen again?&lt;/p&gt;

&lt;p&gt;I am asking because I am still thinking about #4 above. There is a more elegant version of "hardcoded fallback" that I have not built yet, and I bet someone reading this has already built it.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>indiehackers</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>I built a free emoji mixer that runs entirely in your browser</title>
      <dc:creator>CarsonJ</dc:creator>
      <pubDate>Thu, 30 Jul 2026 18:25:21 +0000</pubDate>
      <link>https://dev.to/korelyy/i-built-a-free-emoji-mixer-that-runs-entirely-in-your-browser-5488</link>
      <guid>https://dev.to/korelyy/i-built-a-free-emoji-mixer-that-runs-entirely-in-your-browser-5488</guid>
      <description>&lt;p&gt;I kept seeing those "smash two emojis together" sites and noticed something: most of them upload your image to a server. Even when the math is just stacking pixels.&lt;/p&gt;

&lt;p&gt;So I built my own. It runs entirely in the browser. No uploads, no signup, no paywall.&lt;/p&gt;

&lt;p&gt;Here's how it works:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pick up to 4 emojis from a searchable grid&lt;/li&gt;
&lt;li&gt;The tool uses the Unicode emoji list and renders each one to a canvas&lt;/li&gt;
&lt;li&gt;It composites them with offset, scaling, and rotation&lt;/li&gt;
&lt;li&gt;You get one PNG to download&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The whole thing is about 200 lines of JavaScript. No backend. No API. No tracking. The emoji data ships with the page.&lt;/p&gt;

&lt;p&gt;If you want to see it: &lt;a href="https://korelyy.com/en/tool/emoji-mixer/" rel="noopener noreferrer"&gt;https://korelyy.com/en/tool/emoji-mixer/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A few things I learned while building it:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Most "client-side" tools still hit a server.&lt;/strong&gt; The hidden cost is usually analytics, asset CDN, or auth. Real client-side means the page works offline after first load.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Canvas compositing has hidden gotchas.&lt;/strong&gt; Emoji rendering across platforms gives different base images. Apple's cat emoji is not the same as Google's. I default to the system font the user already has, so the result feels native.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. The fun tools spread faster than the useful ones.&lt;/strong&gt; My calculator for container shipping has solid keyword potential. The emoji mixer gets 10x the social shares. Build accordingly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Browser-only also means privacy by default.&lt;/strong&gt; A user pasting sensitive content into a "redact PDF" tool shouldn't have to trust the server. Local-only removes that question entirely.&lt;/p&gt;

&lt;p&gt;I have about 50 small tools like this on my site now. Each one is the answer to a "I just need to do X real quick" moment. Some get used once a day, some once a year. Both are worth building if the alternative is opening an app and signing up.&lt;/p&gt;

&lt;p&gt;If you want to see the full set: &lt;a href="https://korelyy.com/en/" rel="noopener noreferrer"&gt;https://korelyy.com/en/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The video showing it in action: &lt;a href="https://www.youtube.com/shorts/riFG3Jq8-7c" rel="noopener noreferrer"&gt;https://www.youtube.com/shorts/riFG3Jq8-7c&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What's a "quick task" tool you wish existed but you keep avoiding because it needs a login?&lt;/p&gt;

</description>
      <category>showdev</category>
    </item>
    <item>
      <title>How I Got 1,000+ URLs Indexed for a Solo-Built Tool Site ??Without Paid Tools</title>
      <dc:creator>CarsonJ</dc:creator>
      <pubDate>Thu, 30 Jul 2026 03:18:31 +0000</pubDate>
      <link>https://dev.to/korelyy/how-i-got-1000-urls-indexed-for-a-solo-built-tool-site-without-paid-tools-c0b</link>
      <guid>https://dev.to/korelyy/how-i-got-1000-urls-indexed-for-a-solo-built-tool-site-without-paid-tools-c0b</guid>
      <description>&lt;h1&gt;
  
  
  How I Got 1,000+ URLs Indexed for a Solo-Built Tool Site ??Without Paid Tools
&lt;/h1&gt;

&lt;p&gt;I run korelyy.com ??a free online tool site with 1,000+ tools across 6 languages.&lt;/p&gt;

&lt;p&gt;Getting indexed was harder than building the site.&lt;/p&gt;

&lt;p&gt;Here's the exact SEO workflow I used to get 1,000+ URLs indexed in Google, Bing, and Yandex ??as a solo developer with zero budget.&lt;/p&gt;

&lt;h2&gt;
  
  
  The indexing problem
&lt;/h2&gt;

&lt;p&gt;A tool site has a fundamentally different URL structure than a blog. Each tool is a page. Each language is a separate URL. A 1,000-tool site in 6 languages = 6,000+ potential URLs.&lt;/p&gt;

&lt;p&gt;Bloggers write 50 posts a year. Tool sites ship 1,000 pages on day one.&lt;/p&gt;

&lt;p&gt;The standard SEO playbook doesn't work here. You can't "write quality content" for a Base64 decoder or a PNG compressor. The content is the tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I did (in order of effectiveness)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Sitemap architecture
&lt;/h3&gt;

&lt;p&gt;One sitemap index ??6 language-specific sitemaps (en, zh, es, hi, fr, ar). Each language sitemap contains ~185 tool URLs.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Don't use one giant sitemap.&lt;/strong&gt; Split by language or category. Google processes them in parallel.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Include the lastmod field.&lt;/strong&gt; Even if it's the build date, it signals freshness.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Submit each language sitemap to the corresponding Google Search Console property.&lt;/strong&gt; The hreflang tags in sitemaps help Google understand language targeting.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Google Search Console
&lt;/h3&gt;

&lt;p&gt;GSC accepted my sitemap and started indexing within 48 hours.&lt;/p&gt;

&lt;p&gt;The critical setup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add each language variant as a separate property (or use the International Targeting report)&lt;/li&gt;
&lt;li&gt;Submit the sitemap index URL, not individual sitemaps&lt;/li&gt;
&lt;li&gt;Use the URL Inspection tool to manually request indexing for your most important pages&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. IndexNow (Bing + Yandex)
&lt;/h3&gt;

&lt;p&gt;IndexNow is the fastest way to get URLs indexed. It's supported by Bing, Yandex, and now Seznam.&lt;/p&gt;

&lt;p&gt;The setup is simple:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Generate a key file and place it at /.well-known/ or your site root&lt;/li&gt;
&lt;li&gt;Submit URL batches via HTTP POST to &lt;a href="https://api.indexnow.org/indexnow" rel="noopener noreferrer"&gt;https://api.indexnow.org/indexnow&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I submitted all 1,000+ URLs in batches of 10,000 (the max per request). Bing picked them up within hours.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. hreflang and JSON-LD
&lt;/h3&gt;

&lt;p&gt;Every tool page has:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;hreflang link tags&lt;/strong&gt; in the  pointing to all 6 language variants&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JSON-LD structured data&lt;/strong&gt; with WebApplication schema for tool pages&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This doesn't directly help indexing, but it dramatically improves how search engines understand and display your pages.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. The hard truth about 404s
&lt;/h3&gt;

&lt;p&gt;After generating the full sitemap, I found 47 URLs that returned 404s ??broken categories, removed tools, URL encoding issues.&lt;/p&gt;

&lt;p&gt;Fix: set up a Cloudflare Pages function to catch and redirect them, or fix the routes in the static build.&lt;/p&gt;

&lt;h2&gt;
  
  
  What didn't work
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pinging sitemap URLs directly&lt;/strong&gt; (Google's ping endpoint is deprecated, Bing's returned 410)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Relying only on internal linking&lt;/strong&gt; ??you still need sitemaps for deep pages&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Social media shares&lt;/strong&gt; ??great for traffic, negligible for indexing at scale&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The results after 3 weeks
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Before&lt;/th&gt;
&lt;th&gt;After&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Indexed URLs (GSC)&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;91+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bing indexed&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;85+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Yandex indexed&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;70+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Total sitemap URLs&lt;/td&gt;
&lt;td&gt;240&lt;/td&gt;
&lt;td&gt;1,110&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  What I'd do differently
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Set up sitemaps before launch&lt;/strong&gt;, not after. Indexing delay cost me the first week.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use IndexNow from day one.&lt;/strong&gt; It's the fastest path to Bing/Yandex coverage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fix 404s before submitting.&lt;/strong&gt; Every broken URL in your sitemap wastes crawl budget.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;?? &lt;strong&gt;&lt;a href="https://korelyy.com" rel="noopener noreferrer"&gt;https://korelyy.com&lt;/a&gt;&lt;/strong&gt; ??1,000+ free tools, 6 languages, all client-side. No uploads, no signups.&lt;/p&gt;

&lt;p&gt;If you're building a tool site or working on SEO for a content-heavy project, I'm happy to answer questions below.&lt;/p&gt;

</description>
      <category>seo</category>
      <category>webdev</category>
      <category>indiehacker</category>
      <category>tools</category>
    </item>
    <item>
      <title>Why I Only Build Tools That Run in Your Browser</title>
      <dc:creator>CarsonJ</dc:creator>
      <pubDate>Wed, 29 Jul 2026 23:22:23 +0000</pubDate>
      <link>https://dev.to/korelyy/why-i-only-build-tools-that-run-in-your-browser-2ke</link>
      <guid>https://dev.to/korelyy/why-i-only-build-tools-that-run-in-your-browser-2ke</guid>
      <description>&lt;p&gt;There's a debate all over X right now: is software dead? Big AI is eating everything, so what's left for solo builders?&lt;/p&gt;

&lt;p&gt;My honest take is the opposite. I've never felt more alive doing this. The catch: I don't build big software. I build tiny tools that run entirely in your browser.&lt;/p&gt;

&lt;h2&gt;
  
  
  What "runs in your browser" means
&lt;/h2&gt;

&lt;p&gt;You open a page, and the tool runs on your own device. No login, no signup, no subscription, no uploads. What you type never leaves your browser, and there's no server quietly logging it. Close the tab and nothing is left behind.&lt;/p&gt;

&lt;p&gt;For a builder, this is almost cheating: no database to babysit, no user account system, no monthly server bill, no 3am panic about a data breach. For the user it's even simpler: open it, use it, leave.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I'm betting on this
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Privacy is real.&lt;/strong&gt; A lot of free online tools quietly upload your files to their servers. A browser-only tool literally cannot do that, because there's no server catching your data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Speed.&lt;/strong&gt; No round trips. Click and the result is there.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reliability.&lt;/strong&gt; No backend means no server-is-down-whole-site-is-dead. Many tools even work offline.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Low friction.&lt;/strong&gt; The signup wall scares off most people who wanted to use your tool. Remove it and the rest actually stick around.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  So what am I after
&lt;/h2&gt;

&lt;p&gt;Honestly, I'm not sure this scales in the startup sense. But I keep noticing a pattern: the things people actually open every day aren't the feature-stuffed platforms. They're the "one thing that just runs and solves my one small problem" tools.&lt;/p&gt;

&lt;p&gt;The big-software lane is crowded. But the small, useful, open-and-go lane has never been this wide open.&lt;/p&gt;

&lt;p&gt;So I just keep planting tools there, one at a time. Some get ignored. Some get used daily by way more people than I expected. I don't know where it ends, but I know I love doing it.&lt;/p&gt;

&lt;p&gt;I've been building a growing collection of these browser-based tools over at korelyy.com — always happy to trade notes with other builders.&lt;/p&gt;

&lt;p&gt;If you're building something similar, or you've got a "wish a little tool existed for this" itch, come say hi in the comments.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>indiehackers</category>
      <category>privacy</category>
    </item>
    <item>
      <title>I built a multi-language privacy-first online tool suite, everything runs locally inside your browser</title>
      <dc:creator>CarsonJ</dc:creator>
      <pubDate>Wed, 22 Jul 2026 12:36:43 +0000</pubDate>
      <link>https://dev.to/korelyy/i-built-a-multi-language-privacy-first-online-tool-suite-everything-runs-locally-inside-your-b94</link>
      <guid>https://dev.to/korelyy/i-built-a-multi-language-privacy-first-online-tool-suite-everything-runs-locally-inside-your-b94</guid>
      <description>&lt;h1&gt;
  
  
  I built a multi-language privacy-first online tool suite, everything runs locally inside your browser
&lt;/h1&gt;

&lt;p&gt;If you’ve used random free online tools recently, you’ve probably run into the same frustrations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You have to register an account just for a one-time quick task&lt;/li&gt;
&lt;li&gt;Annoying ads and forced watermarks on your exported files&lt;/li&gt;
&lt;li&gt;You upload private photos, PDFs or text data to unknown third-party servers&lt;/li&gt;
&lt;li&gt;Many tools only support English, no multi-language interface&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s why I spent months building &lt;strong&gt;Korelyy Tools&lt;/strong&gt;, a collection of everyday web utilities with a simple core rule:&lt;br&gt;
&lt;strong&gt;All processing happens locally in your browser. Your files never leave your device.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s inside the toolkit
&lt;/h2&gt;

&lt;p&gt;Right now the site includes common utilities for regular users and developers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Image compression &amp;amp; conversion&lt;/li&gt;
&lt;li&gt;QR Code generator &amp;amp; reader&lt;/li&gt;
&lt;li&gt;PDF basic tools&lt;/li&gt;
&lt;li&gt;Emoji mixer&lt;/li&gt;
&lt;li&gt;JSON formatter / validator&lt;/li&gt;
&lt;li&gt;AI text writing helper&lt;/li&gt;
&lt;li&gt;More dev-focused small utilities on the roadmap&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Core design choices I stuck to
&lt;/h3&gt;

&lt;p&gt;✅ No signup, no login required for any tool&lt;br&gt;
✅ Zero watermarks on all outputs&lt;br&gt;
✅ Client-side computation: No file uploads to backend servers&lt;br&gt;
✅ Multi-language support: English, Chinese, Spanish, French, Hindi, Arabic&lt;br&gt;
✅ Static site built on Next.js, low long-term hosting costs&lt;/p&gt;

&lt;h2&gt;
  
  
  Technical challenges I ran into
&lt;/h2&gt;

&lt;p&gt;Building fully client-side tools wasn’t as straightforward as I expected:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Browser memory limits&lt;/strong&gt;&lt;br&gt;
Large images and multi-page PDFs can easily trigger tab crashes. I added chunk processing to avoid out-of-memory errors.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Web Worker performance&lt;/strong&gt;&lt;br&gt;
Heavy tasks block the main thread, so I moved compression and document parsing into Web Workers to keep the UI responsive.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Multi-language i18n management&lt;/strong&gt;&lt;br&gt;
Maintaining translation strings for six languages adds a lot of repetitive work. I’m still optimizing how I manage localization files.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;SEO for dozens of independent tool pages&lt;br&gt;
Each small tool needs its own meta title, description and structured content to rank on search engines. It’s a slow ongoing process.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Current status &amp;amp; growth
&lt;/h2&gt;

&lt;p&gt;After launching publicly, the site hit around &lt;strong&gt;1.2k pageviews in the first 28 days&lt;/strong&gt; with zero paid ads. Most traffic comes from organic search at the moment.&lt;/p&gt;

&lt;p&gt;There’s still a long feature list I want to implement:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add more developer utilities&lt;/li&gt;
&lt;li&gt;Improve mobile responsive layout&lt;/li&gt;
&lt;li&gt;Expand more language translations&lt;/li&gt;
&lt;li&gt;Optimize bundle size for faster initial load&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’m actively collecting feedback to prioritize new tools and improvements.&lt;/p&gt;

&lt;p&gt;If you want to test it out: &lt;a href="https://korelyy.com" rel="noopener noreferrer"&gt;https://korelyy.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I’d love to hear your thoughts:&lt;br&gt;
What free web tools do you wish existed without signups, ads or data collection?&lt;br&gt;
What features should I build next?&lt;br&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3z7wx4aiv5mpoyrlqs0h.jpg" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3z7wx4aiv5mpoyrlqs0h.jpg" alt=" " width="800" height="372"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>webdev</category>
      <category>nextjs</category>
      <category>sideprojects</category>
    </item>
    <item>
      <title>How I Built an AI Prompt Generator with Next.js 15, Cloudflare Pages, and DeepSeek</title>
      <dc:creator>CarsonJ</dc:creator>
      <pubDate>Sat, 18 Jul 2026 01:26:25 +0000</pubDate>
      <link>https://dev.to/korelyy/how-i-built-an-ai-prompt-generator-with-nextjs-15-cloudflare-pages-and-deepseek-4aak</link>
      <guid>https://dev.to/korelyy/how-i-built-an-ai-prompt-generator-with-nextjs-15-cloudflare-pages-and-deepseek-4aak</guid>
      <description>&lt;h1&gt;
  
  
  How I Built an AI Prompt Generator with Next.js 15, Cloudflare Pages, and DeepSeek
&lt;/h1&gt;

&lt;p&gt;Building AI tools in 2026 is easier than ever — but getting the architecture right takes some thought. Here's how I built a free AI Prompt Generator that supports 4 models, 6 languages, and handles rate limiting at scale.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;I wanted a prompt builder that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Works offline-first for basic prompt construction&lt;/li&gt;
&lt;li&gt;Uses AI only when explicitly requested (cost control)&lt;/li&gt;
&lt;li&gt;Supports multiple models with different field sets&lt;/li&gt;
&lt;li&gt;Handles rate limiting per IP without a database&lt;/li&gt;
&lt;li&gt;Deploys to a global CDN for free&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Architecture Overview
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Frontend: Next.js 15 Static Export
&lt;/h3&gt;

&lt;p&gt;I used Next.js 15 with &lt;code&gt;output: 'export'&lt;/code&gt; mode — this generates static HTML/CSS/JS that can be served from any CDN. The core prompt building is pure frontend:&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="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;PromptField&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;key&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="nl"&gt;options&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="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;PromptModel&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;id&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="nl"&gt;kind&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&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;video&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PromptField&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="nl"&gt;join&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;string&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;lang&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;zh&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each model has its own field configuration and join function that assembles the prompt. The join function takes the user's selected options and outputs either English or Chinese prompts based on a toggle.&lt;/p&gt;

&lt;h3&gt;
  
  
  Backend: Cloudflare Pages Functions
&lt;/h3&gt;

&lt;p&gt;For the AI refinement, I used Cloudflare Pages Functions as my serverless backend. The key insight here is that Cloudflare Functions run at edge locations worldwide, so latency is minimal.&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="c1"&gt;// functions/api/[[path]].ts&lt;/span&gt;
&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/prompt-refine&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prompt&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;string&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;kind&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;kind&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;image&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;lang&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lang&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en&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;rateLimitResult&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;checkRateLimit&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;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&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;rateLimitResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;blocked&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="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;RATE_LIMIT&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;rateLimitResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;429&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;content&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;callDeepseek&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;systemPrompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;userPrompt&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="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Rate Limiting: D1 Database
&lt;/h3&gt;

&lt;p&gt;For rate limiting, I used Cloudflare D1 (a SQLite-compatible serverless database). Each IP gets a counter keyed by &lt;code&gt;${ip}:${day}&lt;/code&gt;. No Redis needed — D1 is fast enough for this use case.&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;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;checkRateLimit&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;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;limit&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;ip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;CF-Connecting-IP&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;day&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;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toISOString&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;T&lt;/span&gt;&lt;span class="dl"&gt;'&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;ip&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="nx"&gt;day&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt; &lt;span class="p"&gt;}&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;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prepare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SELECT count FROM ai_usage WHERE key = ?&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// ... increment and check&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  AI Integration: DeepSeek API
&lt;/h3&gt;

&lt;p&gt;I chose DeepSeek for its JSON response mode — no parsing markdown or extracting text from code blocks. The system prompt instructs the AI to return valid JSON only:&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>I Grew My Free Tool Site from 50 to 1,000+ Tools ??Here's What Actually Changed</title>
      <dc:creator>CarsonJ</dc:creator>
      <pubDate>Wed, 08 Jul 2026 04:48:24 +0000</pubDate>
      <link>https://dev.to/korelyy/i-grew-my-free-tool-site-from-50-to-1000-tools-heres-what-actually-changed-h9b</link>
      <guid>https://dev.to/korelyy/i-grew-my-free-tool-site-from-50-to-1000-tools-heres-what-actually-changed-h9b</guid>
      <description>&lt;h1&gt;
  
  
  I Grew My Free Tool Site from 50 to 1,000+ Tools ??Here's What Actually Changed
&lt;/h1&gt;

&lt;p&gt;Two weeks ago, korelyy.com had 50 tools.&lt;/p&gt;

&lt;p&gt;Today it has over 1,000.&lt;/p&gt;

&lt;p&gt;Here's what I learned scaling a free tool aggregator from 50 to 1,000+ without a team, a budget, or a marketing department.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why 1,000 tools?
&lt;/h2&gt;

&lt;p&gt;After launching with 50 self-built client-side tools (PDF, image compression, JSON formatting, etc.), something unexpected happened: people started asking for more.&lt;/p&gt;

&lt;p&gt;Not more features on existing tools. More categories. "Do you have tools for X?" "What about Y?" "Is there a Z alternative?"&lt;/p&gt;

&lt;p&gt;The pattern was clear ??users don't want five perfect tools. They want one place that covers everything they need, even imperfectly.&lt;/p&gt;

&lt;p&gt;So I built an aggregator layer: curated external tool recommendations alongside the original 50 self-built tools, organized by category, with honest notes on what each one does well and where it falls short.&lt;/p&gt;

&lt;h2&gt;
  
  
  What changed from 50 to 1,000
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The curation problem is harder than the technical problem&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Adding 950 more tools took far more judgment than code. Each external tool needed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A real description (not scraped from the tool's homepage)&lt;/li&gt;
&lt;li&gt;Honest pros/cons ??what it's good for, what it's not&lt;/li&gt;
&lt;li&gt;A link that actually works&lt;/li&gt;
&lt;li&gt;Categorization that makes sense&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I wrote descriptions for all of them myself. No AI-generated lists, no scraped content.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Client-side tools stay client-side&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The original 50 tools all run in-browser. Files never leave your device. This constraint shaped everything: the architecture, the performance model, the privacy story.&lt;/p&gt;

&lt;p&gt;The external recommendations are links out ??but they're labeled clearly. No confusion about what runs locally vs. what requires uploading to a third party.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Six languages from day one&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The site supports English, Simplified Chinese, Spanish, Hindi, French, and Arabic. Not because I planned a localization strategy ??because I needed it personally. Now 40% of traffic comes from non-English speakers.&lt;/p&gt;

&lt;h2&gt;
  
  
  The honest numbers after 2 weeks
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;1,000+ tools&lt;/strong&gt; across 50+ categories&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;6 languages&lt;/strong&gt; with consistent coverage&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;50 original client-side tools&lt;/strong&gt; (PDF, image, text, code, dev utilities ??all browser-based, zero uploads)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No signup required&lt;/strong&gt; for any built-in tool&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No ads&lt;/strong&gt; interrupting built-in tool usage&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;External links clearly labeled&lt;/strong&gt; ??you always know when you're leaving korelyy.com&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What I'm not proud of (yet)
&lt;/h2&gt;

&lt;p&gt;The external tool descriptions could be deeper. The category taxonomy will probably change. Some tools will inevitably break or change over time ??maintaining a live aggregator is an ongoing commitment, not a one-time launch.&lt;/p&gt;

&lt;p&gt;But the core promise holds: one place to find the right tool, with honest context, no friction.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;?? &lt;strong&gt;&lt;a href="https://korelyy.com" rel="noopener noreferrer"&gt;https://korelyy.com&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Whether you need one specific utility or want to discover something new ??the built-in tools run locally, the recommendations are human-curated.&lt;/p&gt;

&lt;p&gt;Questions about the build, the curation process, or running a solo tool site? Drop them below.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>tools</category>
      <category>productivity</category>
      <category>opensource</category>
    </item>
    <item>
      <title>I Built 19 Free Tools and Deployed to 6 Languages ??Here's What I Learned</title>
      <dc:creator>CarsonJ</dc:creator>
      <pubDate>Wed, 01 Jul 2026 15:18:06 +0000</pubDate>
      <link>https://dev.to/korelyy/i-built-19-free-tools-and-deployed-to-6-languages-heres-what-i-learned-34oc</link>
      <guid>https://dev.to/korelyy/i-built-19-free-tools-and-deployed-to-6-languages-heres-what-i-learned-34oc</guid>
      <description>&lt;p&gt;I still remember the moment I decided to build Korelyy.&lt;/p&gt;

&lt;p&gt;Not because I had a grand business plan. Not because I did extensive market research.&lt;/p&gt;

&lt;p&gt;But because I was frustrated.&lt;/p&gt;

&lt;p&gt;I'm a developer. I write code every day. And every time I needed a simple tool ??compress a PDF, convert an image, format some JSON ??I had to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Google for a tool&lt;/li&gt;
&lt;li&gt;Upload my file to some random website&lt;/li&gt;
&lt;li&gt;Wait for ads to load&lt;/li&gt;
&lt;li&gt;Worry about privacy&lt;/li&gt;
&lt;li&gt;Repeat for the next tool&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So I built Korelyy. 19 tools. No signup. No ads. No tracking.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Numbers
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;19 tools&lt;/strong&gt; (PDF, Image, Text, Code, Math, Color, Network)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;6 languages&lt;/strong&gt; (EN, ZH, ES, HI, FR, AR)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;0 registrations&lt;/strong&gt; required&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;100% free&lt;/strong&gt; (and always will be)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What I Learned
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Next.js i18n is powerful (but tricky)
&lt;/h3&gt;

&lt;p&gt;Next.js has built-in i18n support. But deploying to Cloudflare Pages? That's where it gets interesting.&lt;/p&gt;

&lt;p&gt;You need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;next export&lt;/code&gt; for static export&lt;/li&gt;
&lt;li&gt;Configure &lt;code&gt;trailingSlash: true&lt;/code&gt; (Cloudflare Pages doesn't auto-handle trailing slashes)&lt;/li&gt;
&lt;li&gt;Set up &lt;code&gt;wrangler.toml&lt;/code&gt; correctly&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Cloudflare Pages is fast (but has limits)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;??Free tier: generous (500 builds/month)&lt;/li&gt;
&lt;li&gt;??Global CDN: built-in&lt;/li&gt;
&lt;li&gt;??Function timeout: 10ms (for free tier)&lt;/li&gt;
&lt;li&gt;??No Node.js runtime (you're in Cloudflare Workers environment)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. SEO is hard when you're a tools site
&lt;/h3&gt;

&lt;p&gt;Tools sites are hard to rank. Why? Because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Low time-on-page (users get what they need and leave)&lt;/li&gt;
&lt;li&gt;Few backlinks (who links to a PDF compressor?)&lt;/li&gt;
&lt;li&gt;High competition (smallpdf, ilovepdf, etc.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;My solution&lt;/strong&gt;: Build tools that are actually useful, and write blog posts that teach.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Tech Stack
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Frontend&lt;/strong&gt;: Next.js 14 + TypeScript&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Styling&lt;/strong&gt;: Tailwind CSS&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deployment&lt;/strong&gt;: Cloudflare Pages&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Analytics&lt;/strong&gt;: Google Analytics 4&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Search&lt;/strong&gt;: Google Search Console&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try it out
&lt;/h2&gt;

&lt;p&gt;?? &lt;strong&gt;&lt;a href="https://korelyy.com" rel="noopener noreferrer"&gt;https://korelyy.com&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No signup. No ads. Just tools that work.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I'd love to hear your feedback! What tools should I add next?&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>tools</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
