Hari Rajashekar
All work
(00)
Case study · 03

LinkedIn Engine

A self-hosted Next.js app for posting on LinkedIn without opening LinkedIn.

Role  Personal tool·Timeline  3 weekends·Stack  Next.js, Turso, Gemini, Vercel Blob
3
Weekends to v1
$0
Monthly hosting cost
1
LinkedIn tab I no longer open
100%
Self-hosted
(01)
TL;DR

I don't like LinkedIn. I like that it drives inbound for my work, but I don't like being on it. So I built a small Next.js app that lets me write, schedule, and post to LinkedIn without ever opening the site. Three weekends, self-hosted, free to run.

(02)

The problem.

LinkedIn is the highest-impact channel for what I do. People hire me because they saw a post. The problem is that posting on LinkedIn means being on LinkedIn, and being on LinkedIn means scrolling LinkedIn. The algorithm is designed to keep you there. Every time I went to write a post, I'd lose 30 minutes to the feed before I'd written a word.

The other LinkedIn tools out there are either expensive, or they're SaaS products that own your content, or they need browser extensions that break every other week. I wanted something I owned, that ran locally, that I could change whenever I wanted.

(03)

Constraints.

Three rules going in:

  • 01Free to run. No monthly subscriptions to anything.
  • 02Self-hosted. No third-party SaaS storing my drafts.
  • 03Single command to deploy. If updating the app takes more than 30 seconds, I'll stop using it.
(04)

What I tried first.

Started with the official LinkedIn API. That ended fast. The official API only lets you post to your own profile if you're an approved partner, which I'm not. The app review process is opaque and slow.

Tried a couple of community libraries. They worked, but they relied on session cookies that expired every few days. I wasn't interested in re-authenticating constantly.

Eventually settled on a different approach: don't try to fully automate the post. Let the app do everything except the final click. The app drafts, formats, and queues posts. It generates an image if I want one. It opens LinkedIn pre-filled. I hit publish. Total time on LinkedIn: about 8 seconds.

(05)

What actually worked.

The stack is small and weirdly satisfying:

  • ANext.js. The app itself.
  • BTurso. SQLite database for drafts, scheduled posts, image refs.
  • CGemini. Image generation — cheaper than DALL·E for what I need.
  • DVercel Blob. Image storage.
  • EVercel. Hosting the app itself.

Everything sits on free tiers. Combined monthly cost is zero unless I go nuts with image generation, in which case it's a few cents.

Fig. 01 · app UILinkedIn Engine app UI flowThree screens: Draft (text input), Preview (LinkedIn-accurate render with AI image), Publish (one-click open in LinkedIn pre-filled).01DRAFTAI image02PREVIEWinopens pre-filledin new tabPublish03PUBLISHmatches LinkedIn renderingTotal time on LinkedIn: 8 seconds. No scrolling, no feed, no opening the site.
01 · Draft library, LinkedIn-accurate preview, one-click open-in-LinkedIn.

The interaction model is simple. I open the app. I type or paste a draft. The app cleans up formatting, suggests a hook variation if I want one, generates an image (or I upload my own), and gives me a preview that matches LinkedIn's actual rendering. When I'm ready, I hit open in LinkedIn and the app opens a new tab pre-filled with the content. I publish in 8 seconds without scrolling the feed.

I added a simple draft library because I'd been losing posts in my notes app for years. I added a scheduled queue because sometimes I write three posts in one sitting and don't want to publish them all at once.

That's it. It's not a SaaS product. It's not for sale. It's a tool I built for me, and it works.

(06)

The numbers.

3 weekends to v1. $0 to host. About 50 posts published through it so far. The real number is how much time it gave me back — I used to lose 30 minutes per post to the feed. Now I lose 8 seconds. Multiply by a few posts a week and the math is obvious.

Time on LinkedIn, per post
BeforeAfter
30m15m030 min8 secBEFOREAFTERScroll first, write laterOpen-in-LinkedIn, publish, close
(07)

What I'd do differently.

  • 01Build the draft library before the publishing flow. I built them in the wrong order and ended up rewriting the data model.
  • 02Skip the image generation feature for v1. I added it because I thought I'd want it. I use it maybe 1 in 10 posts. Should have shipped without it and added it when I actually missed it.