One developer, ten platforms

Why I run everything as Dockerized TypeScript in one repo, and how that lets a single person ship more surface area than a small team.

10 Jun 2026 · 3 min

People assume that shipping ten platforms means ten of everything: ten repos, ten build systems, ten ways to deploy, ten things to forget how to operate. It does not. It means one way to do every common thing, repeated until it is boring, plus the small amount of code that is actually unique to each platform.

That is the whole bet. The boring parts are identical everywhere, so I almost never think about them. The interesting parts are the only thing left to think about.

One language, top to bottom

Everything is TypeScript. The web app, the API, the worker that drains the queue, the little script that rotates a token at 3am. I am not switching mental models when I move from the frontend to the cron job, and types cross the boundary instead of dying at it. A change to a shared shape breaks the build in both places at once, which is exactly when I want to hear about it.

This is not a religious claim about the language. It is a claim about context-switching cost for one person. The tax on a solo developer is not writing the code, it is reloading the world every time you move between two different stacks. Pick one and the tax goes away.

Docker is the contract

Every platform is a folder with a Dockerfile. That Dockerfile is the only promise I make to the host: give me an image, run it, I will listen on a port. I do not care whether the target is my laptop, a tiny VPS, or a managed runner, because the contract is the same image everywhere.

The payoff shows up the day something breaks at 11pm. There is no "works on my machine" conversation, because my machine runs the same image the server does. I rebuild, I run, I see the same failure, I fix it. The distance between local and production collapses to one command.

FROM node:22-slim
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
RUN npm run build
CMD ["node", "--enable-source-maps", "dist/server.js"]

That file, with small edits, is most of what "deploy" means across every platform I run.

The monorepo earns its keep at the seams

The argument against a monorepo is that it couples things. The argument for it, when you are one person, is that it couples the right things and you control the rest. Each platform is self-contained enough to build and deploy on its own. What they share is the shape of the tooling, not a tangle of imports.

When I find the same logging setup copy-pasted into a fourth platform, I do not extract it the first time, or the second. I wait until the duplication actually hurts, then I lift it once, into one place, and every platform picks it up. Premature sharing is how you turn a fast repo into a slow one.

What this actually buys

It buys attention. A platform that is broken is loud, because the deploy path is the same one I use every day, and a broken deploy looks wrong immediately. A platform that is healthy is silent, and silence is the goal. I want most of my systems to be things I have not thought about in weeks.

Ten platforms is not ten times the work. It is one well-worn path plus ten small destinations. Build the path once, keep it boring, and the destinations stop being scary.

Related
now runningwhisper_scheduleopen