System-design · Monorepo

Monorepo Interview Questions
With Answers & Code Examples

5 carefully curated Monorepo interview questions with working code examples and real interview gotchas.

Practice Interactively →← All Categories
5 questions2 beginner3 core0 advanced
Q1Beginner

What is a monorepo and what are its advantages over a polyrepo setup?

💡 Hint: All packages in one repo — atomic commits, easier refactors, shared tooling; trade-off is CI scale and access control

A monorepo stores multiple projects/packages in a single Git repository. A polyrepo gives each project its own repo.

Monorepo advantages:

  • Atomic cross-package commits — one PR can change a shared library and all consumers simultaneously, keeping them in sync.
  • Easier large-scale refactors — rename a function across 20 packages in one commit; no cross-repo PR coordination.
  • Shared tooling — one ESLint config, one TypeScript config, one CI setup for all packages.
  • Dependency visibility — you can see exactly which packages depend on what; circular deps are detectable at the repo level.
  • Simpler DX — pnpm install at root installs everything; no npm linking hacks needed.

Trade-offs:

  • CI must be smart (only build/test affected packages) — tools like Turborepo and Nx handle this.
  • Access control is coarser — everyone can see all packages. CODEOWNERS files mitigate this.
  • Repo size grows — Git history includes all packages; shallow clones help.
Practice this question →
Q2Core

How does Turborepo's caching work and what makes it fast?

💡 Hint: Task outputs are hashed by inputs (files + env vars); cache hits skip execution entirely — local and remote caches both supported

Turborepo speeds up monorepo builds through content-addressed caching and parallel execution.

Caching mechanism:

  1. Before running a task, Turbo computes a hash from: source files in the package, env variables listed in turbo.json, the task's dependencies' output hashes.
  2. If a cache entry exists for that hash, Turbo replays the cached output (logs + output files) instead of running the task.
  3. Cache hits are instantaneous — CI re-runs of unchanged packages take milliseconds.
// turbo.json
{
  "pipeline": {
    "build": {
      "dependsOn": ["^build"],  // build deps first
      "outputs": ["dist/**"],
      "env": ["NODE_ENV"]       // include in hash
    },
    "test": {
      "dependsOn": ["build"],
      "outputs": []
    }
  }
}

Remote cache — Turborepo can push/pull cache to Vercel Remote Cache or a self-hosted HTTP cache. First CI run populates it; all subsequent machines (and developer laptops) benefit.

Practice this question →
Q3Core

How does Nx differ from Turborepo?

💡 Hint: Nx has a plugin ecosystem, code generators, and module boundary enforcement; Turborepo is minimal and pipeline-focused

Both tools optimize monorepo task running with caching and parallelism, but they differ in scope:

TurborepoNx
FocusFast pipeline runnerFull monorepo platform
Plugin ecosystemMinimalRich (React, Angular, Node, etc.)
Code generatorsNoYes (nx generate)
Module boundariesNoYes (ESLint rules per tag)
Project graphInferredExplicit + visual graph UI
Remote cacheVercel / self-hostedNx Cloud / self-hosted
Learning curveLowHigher

Nx affected commands — nx affected:test runs tests only for packages changed since the last main branch merge, dramatically cutting CI time.

When to pick Turborepo: you want minimal config, your team already knows the toolchain, and you don't need generators or boundary enforcement.

When to pick Nx: large org, multiple frameworks, need guardrails on inter-package imports, want a visual dependency graph.

Practice this question →
Q4Beginner

What are pnpm workspaces and why are they preferred in monorepos?

💡 Hint: pnpm hoists deps once via hard links — saves disk space and prevents phantom dependencies vs npm/yarn workspaces

pnpm workspaces link all packages in a monorepo together so they can import each other as if they were published packages, while sharing a single node_modules store.

# pnpm-workspace.yaml
packages:
  - 'apps/*'
  - 'packages/*'

Why pnpm over npm/yarn workspaces:

1. Hard-link store — pnpm stores each package version once globally and hard-links into projects. A 100-package monorepo doesn't duplicate React 100 times on disk.

2. Strict dependency resolution — pnpm only allows importing packages listed in a package's own package.json. npm/yarn hoist everything, enabling "phantom dependencies" (importing a transitive dep that isn't declared — breaks when the transitive dep is removed).

3. Speed — hard links are faster to set up than copies; install times drop 2–5× vs npm on large repos.

4. Filtering — pnpm --filter @org/ui build runs a command in just one package; pnpm -r build runs it across all.

Practice this question →
Q5Core

What are module boundary rules in Nx and why do they matter?

💡 Hint: ESLint rules enforced via project tags — prevents forbidden imports between domains (e.g., feature libs importing from other features)

Nx lets you tag each project (e.g., scope:checkout, type:feature, type:util) and then write ESLint rules that restrict which tags can import from which.

// .eslintrc.json
"@nx/enforce-module-boundaries": ["error", {
  "depConstraints": [
    { "sourceTag": "type:feature", "onlyDependOnLibsWithTags": ["type:ui", "type:util", "type:data-access"] },
    { "sourceTag": "scope:checkout", "notDependOnLibsWithTags": ["scope:profile"] }
  ]
}]

Why this matters:

  • Prevents accidental coupling between business domains (checkout code importing profile internals).
  • Keeps the dependency graph a DAG — no cycles between feature libraries.
  • Catches violations at lint time (CI) before they become architectural debt.
  • Makes it safe to eventually extract a domain into its own repo or microfrontend — no hidden cross-domain dependencies.
Practice this question →

Other System-design Interview Topics

Rendering Strategies →Core JS →Type System →React Fundamentals →Functions →Microfrontends →Generics →Async JS →Hooks →Objects →Arrays →'this' Keyword →Utility Types →Error Handling →Modern JS →Bundle Optimization →Performance →DOM & Events →State Management →Classes & OOP →Caching Strategies →Component Patterns →Advanced Types →Authentication →React Router →Forms →Advanced Patterns →Frontend Security →Concurrent React →Server Components →Testing →Ecosystem →Network Optimization →Core Web Vitals →Browser APIs →

Ready to practice Monorepo?

Get AI feedback on your answers, predict code output, and fix real bugs.

Start Free Practice →