5 Apps in One Repo - A Solo Developer's Turborepo Monorepo
How to manage multiple apps and websites in a single repository with a Turborepo monorepo. Sharing common configs, saving builds with caching, and per-app deploys, from a hands-on perspective.
TL;DR
Build several apps solo and your configs scatter everywhere. With a Turborepo monorepo, share eslint and tsconfig via packages, skip rebuilding unchanged apps thanks to the turbo cache, and deploy per app with --filter.
On this page
Build apps on your own for a while and the repositories start piling up. An app, a website, another app... and before you know it you've copy-pasted the eslint config five times. I merged all of it into a single monorepo.
Scattered configs are the real problem
With many repositories, the real pain isn't the code - it's the configuration.
- Copying eslint, prettier, and tsconfig into every repo
- Changing one rule means a tour through all of them
- Shared UI and utils feel too trivial to publish to npm
A monorepo flips this into sharing everything from one place.
Basic structure
apps/
├── web/ # 랜딩
├── blog/ # 이 블로그
├── wave/ # 오늘의 파도
└── ...
packages/
├── eslint-config/ # 공용 eslint
└── typescript-config/ # 공용 tsconfig
apps/* holds the actual deployables, and packages/* holds the config and code the apps share. Each app's tsconfig.json just inherits.
{ "extends": "@repo/typescript-config/nextjs.json" }
Now rules get fixed in exactly one place: packages.
The turbo cache is the killer feature
Turborepo's real weapon is its cache. If a task's inputs (source, config) haven't changed, it reuses the previous result as-is.
turbo run build # 전체 빌드(바뀐 것만 실제로 돎)
turbo run build --filter=blog # blog 앱만
All you declare in turbo.json is the dependencies between tasks and their outputs.
{
"tasks": {
"build": { "dependsOn": ["^build"], "outputs": [".next/**"] }
}
}
From the second build on, it finishes in seconds with "FULL TURBO".
Deploying per app
Even in one repository, deploys stay separate per app. With Docker, turbo prune carves out just that app's subtree so the image stays light.
turbo prune blog --docker # blog + 내부 의존성만 남긴 out/ 생성
This blog was carved out exactly this way and deployed to a mini PC with Docker. That story is covered in the self-hosting post.
Wrapping up
apps/*= deployables,packages/*= shared config- Manage tsconfig and eslint in one place via inheritance
- The
turbocache skips rebuilding unchanged apps - Deploy per app with
--filterandprune
If you're running multiple products alone, a monorepo isn't a luxury - it's survival gear.
Frequently asked questions
How many apps before a monorepo pays off?
Even at just 2, it pays off the moment shared config (eslint, tsconfig, UI) appears. The point is fixing a config in one place and having it apply to every app.
Doesn't the build get slower?
It actually gets faster. turbo caches the results of tasks whose inputs haven't changed, so only the apps that changed get rebuilt.
Related posts
- 💻 Dev
AI Writes the Code Now. So Why Does Git Matter More Than Ever?
If AI writes all the code, do I still need to learn Git? The question has it backwards: you need Git precisely because AI writes the code. A solo developer who builds almost everything with AI explains four reasons to get comfortable with Git and GitHub.
- 💻 Dev
I Blocked Double Execution - Then One Crash Locked It Forever
A status guard meant to stop duplicate background jobs ended up trapping a job in 'generating' forever when the process died mid-deploy. Every lock needs a way out, shipped in the same commit.
- 💻 Dev
Building an MDX Blog from Scratch with Next.js - How This Blog Was Made
How I built a blog that runs on nothing but markdown files, no CMS, using the Next.js 16 App Router. Folder structure, MDX setup, and SEO, walked through with the actual code.