ChotaURL: The URL Shortener That Lets the Browser Own the QR Code

A clean MERN app with a split architecture: the backend handles links and redirects, while the frontend generates downloadable QR codes in real time.

6 to 7 min read • View on GitHub • More from akashbyalal

A wide editorial scene showing a browser window on the left where a long URL is pasted into a shortener form, and a short link plus QR code are generated instantly on the right. A quiet server rack sits in the background, emphasizing that the browser handles the QR code while the backend stays focused on routing and counting.
ChotaURL’s most interesting choice is architectural, not cosmetic. The browser generates the QR code locally, while the backend stays on link storage, redirects, and click counts.
Key Takeaways

The neat trick: the browser makes the QR code

ChotaURL is not trying to reinvent URL shortening. Its best move is smaller and smarter: after the backend returns a short link, the browser turns that URL into a QR code locally and gives you a download immediately. No image endpoint. No server-side rendering pass. No waiting on another round trip.

That changes the shape of the product. The backend does the durable work, storing the mapping and handling redirects, while the frontend owns the visible finishing move. For a utility app, that split makes the experience feel lighter than the category usually does.

This is the core mental model. One request creates a short link on the server, then the browser generates the QR code from that returned URL without involving the backend again.

Why that split architecture works

The separation of labor is straightforward. The frontend manages form state, copy-to-clipboard behavior, and QR generation. The backend owns persistence, uniqueness, redirects, and click tracking. That gives ChotaURL a clean boundary between presentation and infrastructure.

DimensionTraditional shortenerChotaURLWhy it matters
QR generation locationServer-side or external APIBrowser-side with <code>QRCode.toDataURL()</code>The QR code appears immediately without a dedicated image service.
Server workloadHandles links plus image generationHandles links onlyLess backend work means a smaller attack surface and simpler deployment.
User latencyTwo server interactions are commonShort link arrives, then QR is made locallyThe UI feels faster because the second step never leaves the browser.
Dependency surfaceOften includes image rendering toolsUses a client library insteadFewer backend moving parts to maintain.
Ease of downloadUsually a server-generated assetA local Data URL can be saved instantlyThe download action becomes a UI concern, not a file delivery concern.
Privacy / data transferQR content may pass through another serviceQR stays in the browser after the short link is returnedLess data leaves the client unnecessarily.
Deployment simplicityNeeds extra rendering supportOnly the API and static frontend are requiredThe app is easier to ship and reproduce.

Inside the redirect path

The backend’s redirect route is the part that makes the shortener real. A request to GET /:shortId looks up the record, increments the click count, and sends the browser onward with res.redirect(). That is the whole loop, and it is exactly the right amount of logic for this kind of app.

router.get('/:shortId', async (req, res) => {
  try {
    const { shortId } = req.params;
    const url = await Url.findOne({ shortId });

    if (!url) {
      return res.status(404).json({ message: 'URL not found' });
    }

    await Url.updateOne({ shortId }, { $inc: { clicks: 1 } });
    return res.redirect(url.originalUrl);
  } catch (error) {
    return res.status(500).json({ message: 'Server error' });
  }
});

There is no hidden complexity here. The route is short because the product is short. That restraint is part of the design.

How ChotaURL avoids duplicate short IDs

The collision guard is a small but important detail. ChotaURL generates an eight-character NanoID, checks the database, and keeps looping until it finds an unused value. NanoID is already highly collision-resistant, but the extra lookup makes the system more trustworthy.

A close-up mechanical scene shows candidate ID tiles moving along a conveyor belt toward a database checkpoint. Each tile is tested, rejected if it matches an existing record, and sent forward only when it clears the gate. The image explains the loop that keeps short IDs unique without making the system feel heavy.
The NanoID loop is pragmatic rather than flashy. It treats uniqueness as a quick database check, not a philosophical problem.
let shortId = null;
let existingUrl = true;

while (!shortId || existingUrl) {
  shortId = nanoid(8);
  existingUrl = await Url.findOne({ shortId });
}

const newUrl = await Url.create({
  originalUrl,
  shortId,
});

That loop is the sort of thing most users never notice, which is exactly why it matters. It keeps the app honest without turning the code into ceremony.

What the stack says about the project

The stack reads like a modern MERN starter with opinionated choices: React 19, Vite, Tailwind CSS 4, Express 5, Mongoose, Axios, NanoID, and QR generation on the client. Nothing about that list is exotic. The signal is in how current it feels.

LayerChoice in ChotaURLWhat it suggests
FrontendReact 19 with ViteFast local development and a lean build setup.
StylingTailwind CSS 4The UI is utility-driven and easy to iterate on.
APIExpress 5The project is willing to use newer platform defaults.
DatabaseMongoDB with MongooseA flexible document model fits short links and analytics.
ID generationNanoIDThe author values compact, collision-resistant identifiers.
QR generationqrcode in the browserClient-side work is a deliberate product decision.

The result is a codebase that feels current without being overbuilt. It is modern in tooling, but still small enough to understand in one sitting.

What it is, and what it is not yet

ChotaURL is best read as a polished utility and a learning project, not a scale-tested link platform. The README and code point toward future additions like analytics, password-protected links, caching, and tighter CORS rules. Those are sensible next steps, but they also underline the current scope.

QuestionTodayLater if it grows
Who is it for?People who need a clean shortener and QR workflowTeams that need tracking, controls, and administration
What does it optimize?Simplicity and client-side convenienceScale, governance, and observability
What is missing?Advanced analytics and protection layersDashboards, caching, and policy controls
How mature is it?Educational and early-stageProduction-ready after hardening

That honesty is useful. The project’s value is not that it solves a hard problem at internet scale. It is that it makes a familiar workflow feel sharper by moving one meaningful piece into the browser.