Part 2 — The Moment a Desktop App Needed a Backend

At first, I tried to avoid it.

Like many developers building personal tools, I instinctively resisted introducing unnecessary complexity.

A backend meant:

  • networking

  • synchronization

  • deployment

  • authentication

  • APIs

  • state management

  • infrastructure

And infrastructure, as every developer eventually discovers, is where things start becoming delightfully absurd. Still, the idea would not leave me alone.

The dream was simple:

  • Pause music on desktop.

  • Continue on another device.

  • Keep playback state synchronized.

  • Make the library feel continuous instead of trapped on a single machine.

That naturally raised a bigger question:

"If a backend already exists… why not expose playback through a web player?"

And that was the second major shift.

Suddenly the project was no longer "a local desktop music player". It was becoming "a personal music platform".

That subtle difference changed the architecture entirely.

Now there were considerations like:

  • remote access

  • media streaming

  • centralized metadata management

  • session handoff

  • cross-device continuity

  • web authentication

  • deployment ergonomics

Ironically, none of this came from wanting to build “a platform.”

It came from wanting the experience to feel seamless.

That distinction matters.

Because many software projects begin with scale ambitions. Needle evolved because each practical improvement naturally revealed the next architectural layer.

At one point, I briefly leaned on Navidrome. And honestly, Navidrome is excellent software.

But eventually I realised something important:

Navidrome was no longer merely “another component.” It had become an architectural limitation.

Not because it was bad.

Because Needle’s vision had moved beyond what a generic Subsonic-compatible music server was designed to do.

I wanted:

  • deeper integration

  • tighter metadata ownership

  • playback handoff semantics

  • local-first assumptions

  • custom synchronization behavior

At that point, replacing the external dependency stopped feeling like ego.

It felt inevitable.

Which, naturally, is how I accidentally found myself designing backend infrastructure for a project that originally just wanted to play FLAC files properly.

And once a backend exists, another dangerous thought appears:

“Well… if this already runs as a service…”

That was the beginning of the self-hosting rabbit hole...