Skip to content
ReactField

TopicsIntermediate

Nx Introduction & Architecture

Nx monorepo paths for greenfield, migration, slow CI and boundaries: thin apps, library types, affected builds and module rules.

Mohamed ElshahawyPublished Apr 2026Updated Oct 2026
4 min read

What you'll learn

  • Paths for greenfield monorepos, polyrepo migration, slow CI and boundary enforcement
  • Match pains like everything-builds or tangled imports to a fix
  • Thin apps, focused libs and dependency direction
  • Affected builds and caching so CI stays fast as the graph grows

Nx turns code colocation into an operational monorepo platform: task caching, affected analysis, module boundaries and a project graph. A plain git monorepo without those pieces usually recreates polyrepo pain inside one repository.

Use the path picker when you know your situation. Use the pain matcher when CI or imports already hurt. For import-layer practice without leaving ReactField, use the ImportBoundaryChecker on Project Standards.

Five short paths from an Nx hub toward greenfield, migration, CI, multi-app and boundary goals
Start from your situation, then apply one architecture move.

How to use this page

  1. Pick a workspace path if you are starting or migrating.
  2. Match a pain if CI or imports already hurt.
  3. Keep apps thin and libs focused.
  4. Enforce boundaries with tags, not hope.

Pick an Nx workspace path

Try it: Nx workspace path

Pick your situation. You get an ordered approach, why it fits, and a first-week plan.

Goal

Your path

Thin apps, focused libs, boundaries from day one

Start with one app and a few libs. Add caching and affected commands before the repo is large enough to hurt.

  1. Nx getting started

    Official intro and workspace mental model.

  2. Applications and libraries

    Apps as composition roots; libs hold product code.

  3. Module boundary rules

    Tag and lint rules before imports tangle.

  4. Project graph

    See the dependency picture early.

First week

Scaffold one web app and two libs (ui + feature). Run nx graph. Add tags for type and scope.

Tip: monorepo success is tooling plus boundaries, not just putting folders in one git repo.

Checkpoint

You are starting a greenfield Nx workspace. Where should most product code live?

Match an Nx pain

Pain chips connected to fix cards for affected, boundaries, thin apps and library types
Name the pain, then pick one primary fix.

Try it: match an Nx pain

Choose the pain you feel. The matcher points to a primary fix and an optional alternate.

Pain

The pain

Every PR runs lint, test and build for the entire workspace.

Start here

Nx affected

Affected analysis runs only changed projects and their dependents. Pair it with caching.

Also consider

Nx caching

Reuse task outputs so repeated work disappears.

Related: Bundle size when the pain is app JS, not CI graph

Tip: practice forbidden imports on Project Standards with the ImportBoundaryChecker.

Key takeaway

Monorepo success depends on tooling and boundaries, not on repository shape alone.

Why monorepos and why Nx

When you manage multiple related projects, you usually choose between:

  • Polyrepo: each project has its own repository and release cycle.
  • Monorepo: all related projects live in one repository.

Neither is universally better. The right choice depends on team size, coupling, release model and tooling maturity.

AspectPolyrepoMonorepo
Code sharingPublish and version packagesDirect imports, always in sync
Cross-project changesMultiple PRs, coordination overheadSingle atomic commit
Dependency updatesRepeated across reposOne update path
RefactoringCross-repo complexityCentralized, IDE-friendly

Plain monorepos without platform tooling usually create slow CI, weak boundaries, inconsistent commands and hard onboarding.

Nx addresses that with:

  • Task caching: reuses prior build, test and lint outputs
  • Affected analysis: runs only what changed and downstream dependents
  • Module boundaries: enforces architecture through lint rules
  • Dependency graph: makes impact and coupling visible
An orange Nx hub connects caching, the dependency graph, affected analysis and module boundaries to the applications, shared libraries and utilities below it
Nx sits between your tools and your projects and decides what to build, test and cache.
Terminal
# visualize project relationships
npx nx graph

# run tasks only for changed projects
npx nx affected --target=build
npx nx affected --target=test

# run one project's target
npx nx run web-app:serve

Workspace layout

Nx works best with a clear split:

  • apps/ for thin deployable entry points
  • libs/ for most business logic, features, UI and shared utilities

Think of apps as composition roots. Libraries hold the actual product code.

TSX
// apps/web-app/src/app/page.tsx
import { HomePage } from '@org/web-modules/feature-home'

export default function Page() {
  return <HomePage />
}
Four separate repositories, each with its own pipeline, consolidate into one repository that shares a single pipeline
Four repositories with four pipelines become one repository with one graph and one pipeline.

Suggested shape:

Text
monorepo/
|-- apps/                         # Thin, deployable entry points
|   |-- web-app/
|   |-- mobile-app/
|   |-- api-server/
|   `-- admin-dashboard/
|
|-- libs/                         # Most code lives here
|   |-- web-modules/
|   |-- ui/
|   |-- shared/
|   `-- db/
|
|-- tools/
|-- nx.json
|-- tsconfig.base.json
`-- package.json

You can also scope libs/ by ownership: libs/client/*, libs/admin/*, libs/shared/*.

Library types

Libraries stay clearer when each one has a single concern and consistent naming.

  • Feature libraries (feature-*): route-level business logic and smart components
  • UI libraries (ui-*): reusable presentational components
  • Data-access libraries (data-access-*): API clients, query logic, state adapters
  • Utility libraries (util-*): pure helpers, formatters, validators, constants
Text
libs/
|-- web/
|   |-- feature-auth/
|   |-- feature-dashboard/
|   `-- data-access-api/
|-- shared/
|   |-- ui-kit/
|   |-- util-format/
|   `-- types/
`-- admin/
    |-- feature-users/
    `-- data-access-admin-api/

Feature modules keep domain logic together:

Text
libs/web/feature-auth/src/
|-- components/
|-- hooks/
|-- services/
|-- models/
|-- routes/
`-- index.ts

Use barrel index.ts files as the public API and hide internals.

Module boundaries

An app sits above feature libraries, which sit above shared libraries, with arrows pointing downward and an upward import blocked by a wall
Dependencies flow downward. Boundary rules block imports that point back up.

Without boundaries, monorepos become tightly coupled. Safe default direction:

Text
apps/* -> feature-* -> data-access-* -> util-* / types

Avoid reverse imports (for example util-* importing feature-*).

  • Add tags per project (domain, type, scope)
  • Enforce import rules in linting
  • Review nx graph for accidental cycles before merge

Practice the same idea interactively on Project Standards. Do not treat folders alone as architecture.

Checkpoint

CI runs lint, test and build for every project on every PR. What should you wire first?

Affected builds and CI

A scalable Nx workflow focuses on fast local iteration and selective CI.

Terminal
# local: one app or one lib
npx nx run web-app:serve
npx nx run web-feature-auth:test
npx nx affected --target=lint

# CI: changed projects and dependents only
npx nx affected --target=lint --base=origin/main --head=HEAD
npx nx affected --target=test --base=origin/main --head=HEAD
npx nx affected --target=build --base=origin/main --head=HEAD

Tips:

  • Keep targets standardized (build, test, lint, typecheck) across projects
  • Prefer smaller libraries with clear APIs over giant shared buckets
  • Use caching aggressively in CI and local dev

The key habit

Thin apps, focused libs, tags that lint can enforce, and affected CI before the graph is huge.

Nx checklist

  • Apps are thin composition roots
  • Libs are named by type (feature, ui, data-access, util)
  • Dependency direction is documented and linted
  • nx graph is reviewed for cycles on large changes
  • CI uses nx affected against the default branch
  • Task caching is enabled where it helps

Further reading

Conclusion

Nx works when architecture and tooling are one system. Monorepo shape defines collaboration. Library boundaries define health over time. Caching and affected commands define delivery speed.

Start simple. Enforce boundaries early. Scale library granularity with the team, not ahead of it.

The key takeaway

Treat Nx as a platform for boundaries and selective work, not as a folder convention alone.

Check your understanding

Test yourself6 questionsQuestion 1 of 6

Where should most product code live in a greenfield Nx workspace?

Recap

What to remember from this article

Sections read

0

Questions

0

none answered yet

Quiz

0

not taken yet

Up next: Automated Testing · 7 min

Continue