Web AppQ3 2022Lead
Heckfree
Users get a public profile that showcases all of their links in one place.

The build
One link that carries every platform you're on. Mine is at /meharshit.
Problem
Every platform wants a link and only gives you one field. The result is a bio that points at whichever profile you thought mattered most that month, and an audience that never finds the rest.
The product is small and the problem is real: a single stable URL that resolves to everything else, owned by the person rather than by a platform.
Constraints
- Public pages must be fast and boring. A profile is opened from a phone, on a slow connection, from someone else's bio. It renders or it's useless.
- Editing must be trivial. If reordering a link takes more than a drag and a save, people stop maintaining the page and it rots.
- No team, on free hosting. Same as everything else here — no budget, and no one on call but me.
Approach
Server-rendered EJS pages served at each user's handle, with the edit surface behind Passport-backed accounts.
// The public route — one lookup, no session, no join.
app.get("/:handle", async (req, res) => {
const profile = await Profile
.findOne({ handle: req.params.handle })
.lean();
if (!profile) return res.status(404).render("404");
res.render("profile", { profile });
});Link ordering is stored on the profile document as an array, so the order the owner drags into is the order the page renders — no sort key to keep consistent, no second collection.
Tradeoffs
- Server rendering over a client app. The public page is the whole product, so it renders on the server and ships almost no JavaScript. The editor is worse for it — every save is a round trip.
- Ordering as an array on the document. Reordering rewrites the array, which is fine at a dozen links and wrong at a thousand. It was the right call for the size of the thing.
- Handles as the primary key of the public URL. Clean URLs, at the cost of handle changes breaking every link already shared. There's no redirect table; there should be.
Outcome
It works and it's still up. My own profile runs on it, which is the only endorsement a link-in-bio tool can honestly give — I use the one I built instead of the one everybody else uses.
Decisions
- Building it at all, against using Linktree. Chosen because the interesting part was the modelling, not the product — public pages, ownership, and ordering are a compact study in all three. Against it: the commercial version is free and better maintained.
- Passport accounts over magic links. Chosen for consistency with everything else I'd built, so there was one auth pattern in my head rather than two. Against it: another OAuth app to register per deployment.
- No custom domains. Chosen to keep hosting simple. Against it: the feature that would make it genuinely useful to somebody else is precisely the one missing.
Stack
- Node.js
- Express.js
- MongoDB
- Passport.js
- EJS
- JavaScript
Related projects

Lecture Lense
Turns any recording into searchable, timestamp-cited notes.

Chitter
A mini social app that lets users sign up, log in and post whatever is on their mind.

Coscholars
An Ed-Tech platform built end to end during my internship at Coscholars.