Why NextWhy Next
Back to posts
💻 Dev3 min read

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 turbo cache skips rebuilding unchanged apps
  • Deploy per app with --filter and prune

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