I built 109 tools that never touch a server - here is the architecture
Most "tools" sites you have used do this:
- You upload a file
- It goes to a server
- The server processes it
- You download the result
Sometimes the server stores it. Sometimes it leaks. Sometimes it disappears with the company.
I wanted something different. Every tool on korelyy.com runs 100% in your browser. Zero backend. Zero upload. Zero tracking.
Here is the actual architecture, the real numbers after 90 days, and what I learned.
What "no server" actually means
For each of the 109 tools:
- The entire app is a static HTML + CSS + JS file
- It is served as-is from a CDN (Cloudflare Pages)
- All file processing happens in your browser via
FileReader,canvas,Web Crypto API, orOffscreenCanvas - Your file never leaves your device
- Closing the tab = the data is gone (no cookies, no localStorage, no account)
This is not a marketing claim. It is verifiable:
- Open DevTools -> Network tab
- Use any tool that requires a file (image converter, JSON formatter, etc.)
- Reload. The only network request is for the static HTML/CSS/JS bundle.
No fetch() to a server. No XHR. No upload. The file is read, processed in-memory, and downloaded.
The 4 browser APIs that do 90% of the work
When you remove a backend, you are left with the browser. The browser is more capable than most people think.
1. FileReader and URL.createObjectURL
Read any file the user gives you:
const file = document.querySelector('input[type=file]').files[0];
const url = URL.createObjectURL(file);
const img = new Image();
img.onload = () => {
// process image
canvas.toBlob(blob => {
const downloadUrl = URL.createObjectURL(blob);
// trigger download
});
};
img.src = url;
Image conversion, PDF generation, audio trimming - all the same pattern. Read blob, process, create new blob, download.
2. crypto.subtle (Web Crypto API)
Hashing, encryption, signing - all client-side:
const hash = await crypto.subtle.digest('SHA-256', arrayBuffer);
const hex = Array.from(new Uint8Array(hash))
.map(b => b.toString(16).padStart(2, '0'))
.join('');
No need for a Node backend. The browser has FIPS-validated crypto built in.
3. canvas and OffscreenCanvas
Image manipulation in 2D context:
- resize, crop, rotate
- draw shapes, text, gradients
- extract pixel data
- convert formats via
canvas.toBlob()
OffscreenCanvas lets you do this in a Web Worker, so the UI does not freeze on large images.
4. Worker and SharedWorker
For CPU-heavy work (JSON validation, regex, large CSV parsing), offload to a Web Worker. The main thread stays responsive.
The hard parts
It is not all easy. Three categories of features are genuinely hard without a server:
1. Anything that needs a shared database
"No server" means no central state. You cannot have user accounts, leaderboards, comments, or shared documents without a backend.
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.
If you want shared state, you need a backend. Be honest about it.If you have ever used a tool site and felt uneasy about uploading your file to a server you have never heard of, you are not alone. I was one of those people, and it is the reason I started building tools that run entirely in the browser.
I now run a small site with 110 free browser-based tools, and every one of them runs without a server. Here is what that means, why I made that choice, and the few cases where you genuinely cannot avoid a backend.
What "runs in the browser" actually means
When a tool runs in the browser, the entire product is the HTML, CSS, and JavaScript the user downloads. Once that page is loaded, the tool works without further round trips. You can disconnect from the internet and the tool keeps working. No data leaves the device unless the user explicitly exports it.
For most small tools, this is more than enough. A character counter does not need a server. A JSON formatter does not need a server. A color picker does not need a server. A QR code generator does not need a server. The backend was there because that was the default, not because the tool demanded it.
Why I chose it
Three reasons, in order of how much they actually affected my work.
1. Trust. When the tool is on the page, users can open DevTools and see exactly what it is doing. That is the strongest privacy statement you can make. It is not a banner, it is not a checkbox, it is the architecture.
2. Cost. A static site served from a CDN is essentially free. I serve millions of requests a month, and the bill is a rounding error. No database, no worker, no queue, no egress.
3. Reliability. I have not been paged in two years. There is no Node process to crash, no Redis to flush, no deploy to roll back. If the DNS works, the tools work.
Where it does not work
I want to be honest about the cases where a browser-only tool is the wrong call.
- Tools that need a server-side data source. Currency conversion needs live rates. Weather needs an API. There is no way around that.
- Tools that need to remember cross-device state. A note-taking app that runs only in the browser is local to one device. If cross-device sync is a feature, you need a server.
- Tools that share a small file with the world. A pastebin that is browser-only is just a fancy download link.
For those cases, I use a small Cloudflare Worker. The boundary is simple: if the tool touches only the user, the browser is enough. If the tool needs to reach me or another user, the server is needed.
What I learned
After two years of running a 110-tool site this way, a few things stand out.
Users notice. A surprising number of users email me specifically because the site does not track them. It is a feature they actively look for.
Shipping is faster. I write a tool, push to GitHub, the site is updated. There is no migration, no schema, no API versioning. The deploy step is a single git push.
The architecture is portable. If Cloudflare disappeared tomorrow, I could move the site to Netlify, or S3, or even a USB stick, in under an hour. There is no state to migrate.
The hardest part is discipline. Once you remove the server, every shared feature becomes a real engineering decision. "Save" becomes "download as file" or "copy to clipboard." "Search" becomes a static JSON index. "Login" becomes "you do not need one." These are not bugs, they are constraints, and constraints are good.
Try it
If you are building a small tool site, the next time you start a new tool, try to build it without a backend. You might be surprised how much of what you thought you needed was actually optional.
The 110 tools are at https://korelyy.com. They all run in the browser. None of them send data anywhere. The whole site is one static bundle and one small Worker for the contact form.
2. Anything that needs to call a third-party API that requires a key
Most LLM APIs, payment APIs, and OAuth flows need a server-held secret.
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.)
3. Anything that requires lots of CPU or RAM
A 4K video transcoded in the browser will lock up the UI for 30 seconds. There is no fix except "use a server."
My answer: korelyy does not do video. Image, audio, text, code, JSON, PDF, CSV - all fine. Video, 3D, ML inference - skip.
The SEO win no one talks about
A static-only site is insanely fast for Google.
- Lighthouse 100/100/100/100 on every page
- LCP under 500ms globally
- TTFB under 100ms (Cloudflare edge)
- Total page weight under 50KB
Google rewards this. My actual results after 90 days:
- 165 pages indexed
- 1,545 monthly impressions
- 22 monthly clicks
- 0 backlinks
- 0 marketing spend
These are not impressive numbers. But the cost per impression is literally $0. And the trend is monotonically up.
The 6-language "trick"
Most indie sites ship English-only because i18n is painful. Mine has 6 (en, zh, es, fr, hi, ar).
The trick: translations live in JSON files, not in the code. A 2,000-line tool component never knows what language it is in. The useTranslations hook from next-intl handles it.
// English file
{ "compressImage": { "title": "Compress image" } }
// Chinese file
{ "compressImage": { "title": "压缩图片" } }
RTL (Arabic) is one CSS rule: html[dir=rtl] { ... } plus using logical properties (margin-inline-start instead of margin-left) throughout.
Cost: 1 week to set up. Saved: 6x market reach with zero ongoing effort.
What I would do differently
After 90 days, here is what I would change:
- Start with SEO from day 1, not day 30. I lost 30 days of indexing time. Set up sitemap, structured data, and submit to GSC before launch.
- Ship fewer, better tools. I shipped 109. 20 of them are great. 60 are decent. 29 are mediocre. I would rather have shipped 30 great ones.
- Do not add a backend for the sake of it. Every time I was tempted to add a server, I asked "do users actually need this?" 95% of the time, the answer was no.
- Write the marketing page before the tool. I built tools nobody searched for. Now I check Google Trends and "People Also Ask" before building anything.
When NOT to do this
The no-backend approach is wrong for:
- Multiplayer or collaborative products
- Anything requiring authentication
- Products with ML inference
- Products with heavy server-side processing
- Anything where you need analytics
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.
Try it
If you want to see the architecture in action:
- Image converter - upload, convert, download. Check Network tab. Zero requests.
- JSON formatter - paste 10MB of JSON, validates in 50ms
- Password generator - uses crypto.getRandomValues
- Markdown preview - 6 languages UI
All 109 at korelyy.com/en.
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.
Sometimes the simplest constraint is the best one.
Top comments (0)