Managing Multiple Next.js Apps with Shared Packages and API Services Using Turborepo

blog-asset-missing

Introduction

Imagine you’re part of a growing product team responsible for a customer-facing web app, an internal admin dashboard, and maybe even a documentation site—each built with Next.js. They all need their own pages and styling, yet under the hood they share buttons, forms, API clients, hooks, and business logic. Without a clear structure, duplication and version mismatches quickly become a maintenance nightmare.

Enter Turborepo: a high-performance monorepo tool that brings these applications together, lets you share packages cleanly, cache builds intelligently, and keeps your developer experience frictionless.

Why Choose a Monorepo with Turborepo?

  • Unified Development Experience Everyone—designers, front-enders, backend engineers—sees the same folder structure, conventions, and code. No more hunting across multiple repos for that shared button or global type.

  • Instant Build Caching Turborepo tracks dependencies between apps and packages. Change a shared UI component once, and only the apps that import it rebuild. Subsequent runs can be nearly instant.

  • Consistent Dependency Management Shared libraries (UI, styling, utilities, API clients) all use the same React, ESLint rules, and TypeScript settings. “Works on my laptop” surprises become a thing of the past.

  • Optimized CI/CD Run linting, testing, and builds in parallel with intelligent caching—your pipelines finish in a fraction of the time.

A Glimpse at the Structure

A typical Turborepo monorepo might look like this:

/apps

  ├─ web/      (customer-facing site)

  ├─ admin/    (internal dashboard)

  └─ docs/     (documentation site)

/packages

  ├─ ui/       (buttons, forms, layout system)

  ├─ api/      (HTTP client, endpoint definitions)

  ├─ hooks/    (shared React hooks)

  ├─ config/   (ESLint, Prettier, tsconfig)

  └─ utils/    (date formatting, error handlers)

  • apps/: Each folder is a standalone Next.js project.

  • packages/: Reusable pieces consumed by all apps.

Turborepo’s configuration wires @monorepo/ui in admin (for example) to the local package, not an NPM version.

The Developer Experience

Picture a Tuesday afternoon:

  1. You clone the monorepo, run turbo dev, and watch two Next.js servers spin up in parallel (web and admin).

  2. You tweak a color variant in your shared Button component in /packages/ui. Both local dev servers instantly reflect the change. No publish, no reinstall.

  3. On CI, turbo lint, turbo test, and turbo build run in parallel, leveraging cached results for packages that haven’t changed.

This fluid feedback loop keeps you in a “code → see changes” flow instead of waiting on slow installs or builds.

How Shared Packages Drive Consistency

UI Library

Your brand’s buttons, inputs, and cards all come from /packages/ui. Update the primary color or padding once, and every app—marketing site or analytics dashboard—stays in sync.

API Client

A centralized HTTP client (e.g., Axios with interceptors and error-handling logic) in /packages/api ensures that auth tokens, base URLs, and timeouts remain identical across apps.

Custom Hooks

Authentication, data-fetching, and form state management live in /packages/hooks. A single useAuth or useFetch hook shared across pages reduces duplication and bugs.

Real-World Benefits

  1. Faster Feature Delivery No more copying components or chasing missing imports. New features roll out simultaneously across all apps with minimal overhead.

  2. Simplified Maintenance Fix a bug in the shared login flow once in /packages/hooks—it’s patched everywhere instantly. No need for three separate PRs across three repos.

  3. Scalable Architecture Add new apps (mobile dashboard, microsite, API docs) by simply declaring a workspace and depending on existing packages.

  4. Optimized CI/CD With Turborepo’s incremental caching and parallel execution, pipelines often finish in under 2 minutes—even as the codebase grows.

Best Practices for a Healthy Monorepo

  • Keep Packages Focused One responsibility per package (UI, hooks, API client). Avoid “kitchen-sink” libraries.

  • Enforce Workspace Versions Use workspace:* so local packages always stay in sync.

  • TypeScript Everywhere Strict typing in shared packages surfaces integration errors early. Centralize shared types in /packages/api/types.

  • Automate Linting & Formatting A shared ESLint/Prettier config in /packages/config ensures consistent style across apps.

  • Document Each Package Include a README in every package describing its purpose, exports, and usage examples.

Conclusion

Managing multiple Next.js applications no longer requires juggling dozens of repos or duplicating code. By adopting a Turborepo monorepo with clearly defined apps and shared packages, teams can:

  • Work faster with instant build results

  • Ship features consistently across applications

  • Scale their frontend architecture gracefully

Turborepo lets you focus on building delightful user experiences—not wrestling with glue code and builds. Whether you maintain two apps or twenty, this approach keeps your codebase maintainable, your CI fast, and your development teams happy.