How to organize a Next.js project in a monorepo architecture? Advantages, tools, folder structure, and advice from my experience on high-volume applications.

When developing a Next.js application that will grow over time — with multiple modules, backends, shared components — a monorepo architecture quickly becomes a necessity. After several projects, I'm sharing here my best practices for structuring a Next.js project in a clean, maintainable, and scalable monorepo.
A well-structured monorepo also allows multiple people to work without overwriting other modules.
projectReferencesmy-app/
├── apps/
│ ├── web/ → main Next.js app
│ └── admin/ → admin interface
├── packages/
│ ├── ui/ → shared components (design system)
│ ├── config/ → Tailwind, ESLint config, etc.
│ └── db/ → ORM, Drizzle schemas, DB helpers
├── .gitignore
├── package.json
├── turbo.json
└── tsconfig.json
Each sub-project can have its own dependencies while accessing common packages via workspaces.
The packages/ui folder contains components like <Button />, <Card />, <Layout />, all written in TypeScript and styled with Tailwind.
// packages/ui/button.tsx
export function Button({ children }) {
return (
<button className="rounded-xl px-4 py-2 bg-orange-500 text-white">
{children}
</button>
);
}
Then, you import it from apps/web:
import { Button } from "@ui/button";
In packages/types, I place all my shared types between frontend, backend, and API. This allows strict typing, especially for data retrieved with Drizzle ORM.
For tests, each app can embed its own Jest/Vitest, or we can share helpers in packages/test-utils.
I support startups and ambitious web projects in their technical structuring, whether in creation or redesign.
© 2025 MKWeb. All rights reserved.