AppCrib has 27 tools live right now. A jq playground running real jq 1.8 compiled to WebAssembly. A SQL formatter powered by sql-formatter v15. A gradient builder doing OKLCH color interpolation math. A token counter for LLM prompts. A drywall calculator, a mulch estimator, a BAC calculator, a stud spacing calculator, and nineteen others.
None of them have a backend. That was the point.
Why would you skip the backend on purpose?
The default for most free online tools is: collect user input, send it to a server, process it, send it back. Path of least resistance for the developer. Worst possible architecture for the person using the tool.
A server means your data leaves your browser. Cold starts. CORS configuration. API keys and rate limits. The tool breaks when the server's down, when the SSL cert expires, when the billing threshold trips. Somebody is storing your JSON, your SQL queries, your private calculations on infrastructure you can't inspect.
We wanted the opposite of all of that. Every tool on AppCrib runs entirely in your browser tab. Paste a JSON blob into Jsonr and the parsing happens on your machine. Run a jq filter in Jqbin and it executes in a WebAssembly sandbox in your tab. Format SQL in tidysql and the formatter library runs client-side. Your data never leaves the tab. There's no server to leave it on.
What does "no backend" actually mean technically?
The entire site is a Next.js static export. output: "export" in the Next.js config. The build step spits out plain HTML, CSS, and JavaScript files. No server-side rendering, no API routes, no serverless functions. Cloudflare serves the static files from its CDN edge. That's the full server-side story.
Each tool is a route inside a single Next.js app. Epochr lives at /epochr. Pipefmt lives at /pipefmt. One deployment, one build, 27 routes. They all share the same deploy pipeline, the same Tailwind theme system, the same shadcn/ui component library, the same build-time verification.
The client-side logic varies. Some tools are arithmetic. Drywl calculates drywall sheets from room dimensions, Mulchly estimates mulch volume, Perclo computes percentage changes. Others pull in heavy libraries. Jqbin loads a WebAssembly binary of jq 1.8. tidysql uses sql-formatter v15 with dialect-specific formatting rules. Graduo does gradient interpolation in the OKLCH color space: perceptually uniform gradients instead of the muddy midpoints you get from RGB.
All of it runs in the browser. No fetch calls to our servers. No API keys in env vars. No Lambda cold starts.
How do you handle the hard stuff without a server?
People assume client-side-only means toy functionality. That was maybe true in 2018. It isn't now.
WebAssembly changed everything. Jqbin doesn't use a JavaScript reimplementation of jq. It runs the actual C codebase of jq 1.8 compiled to WASM via Emscripten. The output matches what you'd get in your terminal. That's not a toy. It's the real tool running in a sandbox.
Modern JS libraries are genuinely good. sql-formatter v15 handles over a dozen SQL dialects with configurable indentation, keyword casing, and line width. The diff library powering Diffpad does unified and side-by-side diffs with syntax highlighting. Lintcron parses and validates cron expressions entirely in JavaScript with human-readable schedule descriptions.
CSS itself does things that used to need server compute. Graduo's OKLCH gradients use CSS oklch() values directly. Hextly does hex-to-RGB-to-HSL conversion with native color math. TypeDuo generates font pairing previews by loading Google Fonts on the client and rendering live specimens. No image generation API, just fonts and a DOM.
And then there's the stuff that never needed a server in the first place. Blank detects invisible Unicode characters with string analysis. Oktal converts between number bases with arbitrary precision. Massvo does unit conversions across mass and volume. The industry just defaulted to building backends because that was the familiar pattern.
What are the actual performance benefits?
Here's what you actually get:
Zero cold starts. A serverless function might take 200-500ms to wake up on the first request. A static file served from a CDN edge node takes the same time on the first request as the millionth. The tool loads, the JS initializes, and you're working. No spinner while a Lambda warms up.
Works offline. Once the page loads, the tool works. Kill your WiFi, put your laptop in airplane mode. Rowson still converts CSV to JSON, Favset still generates favicons, Ratia still calculates aspect ratios. The tool is on your machine already.
No CORS headaches. More of a developer experience point than a user-facing one, but it matters for how fast we ship. No backend means no cross-origin request to configure. No preflight OPTIONS requests. No debugging why the cookie isn't being sent.
No rate limits. Paste a 50MB JSON file into Jsonr and it'll try to parse it. Slowly, probably, but it'll try. No API gateway returning 429s. No payload size limit from a proxy. The limit is your browser's memory, which is the honest limit.
What about privacy? Is client-side actually more private?
Yes, and it's not close.
When a tool runs on a server, you're trusting the operator's privacy policy, their logging configuration, their access controls, and the hope that nobody accidentally logs request bodies to a debug endpoint. That's a lot of trust for a JSON formatter.
When a tool runs in your browser, the data doesn't leave. Not "we promise not to look at it." It physically doesn't transmit. Open your browser's network tab while using any AppCrib tool. You'll see zero POST requests containing your data. No telemetry payloads with your input. No analytics events capturing what you typed. The processing happens in JavaScript on your device and the result shows up in the same tab.
That's why we built it this way. Not because we couldn't afford a backend. We have Convex available for any tool that genuinely needs one, and our architecture explicitly keeps that door open. We chose client-side because it's the only architecture where "your data stays private" is a verifiable claim instead of a policy document.
How do you build 27 tools this way without it taking forever?
Standardization. Boring answer, but it's the real one.
Every tool on AppCrib shares the same foundation: Next.js static export, Tailwind CSS, shadcn/ui components built on Radix primitives, the same next.config.js security headers (CSP, HSTS, X-Frame-Options, X-Content-Type-Options), the same build pipeline. When we start a new tool, routing already exists. The theme system works. Dark mode works. Accessibility linting is in place via eslint-plugin-jsx-a11y. Ad layout slots are defined. The privacy policy template accounts for client-side-only data handling.
What changes per tool is the domain logic: the actual thing it does. Walltly calculates wallpaper rolls. pvalr interprets p-values for statistical significance. Cogsly computes gear ratios. Rolemat generates role-playing matrices. Focused client-side logic dropped into the same chassis.
The build pipeline validates every tool with the same gates: does it build, does the static export produce valid routes, do the security headers pass, does the accessibility scan flag anything. One set of standards across 27 tools. No per-tool DevOps, no per-tool deployment config, no per-tool monitoring stack.
What are the actual tradeoffs?
We're not pretending this is free lunch. Client-side-only has real limitations.
Browser memory is the ceiling. You can't stream a 2GB CSV through a browser tab the way you can through a server with disk-backed temp files. For formatters, converters, calculators, visualizers, browser memory is fine. If we needed to build a video transcoder, we'd need a different architecture.
No persistent user accounts. Without a backend, there's no user database. Jqbin stores query history in localStorage. Laydown saves flooring estimates locally. Clear your browser data and those are gone. For micro-utility tools, that's the right tradeoff. For something that needs cloud sync or collaboration, it wouldn't be.
SEO takes more deliberate work. Static export means every page needs its metadata defined at build time. No server-side rendering to dynamically generate Open Graph tags or structured data. We handle it with Next.js metadata exports and JSON-LD, but it's more upfront effort than letting a server render it.
For utility tools that do one thing and do it fast, these tradeoffs are worth it every time.
Would we do it again?
We're doing it again. Tool 28 is in the pipeline. The constraint (no backend unless you genuinely need one) forces every tool to be self-contained, fast, and private by default. It turns out that's a pretty good set of defaults.
Twenty-seven tools, one static export, no servers touching your data.