Updated

3 min read

How to Share Components Between NextJS Projects (Easily)

In this post, I'll show you how to share components between NextJS projects with pnpm workspaces.

This approach can use alongside Turborepo for more complex projects, but it's not necessary.

Our goal is to keep things simple and easy to understand, with no build steps or type aliases.

Setting up the project

Here's a typical project structure with two NextJS projects and a shared components package.

project/ ├─ apps/ ├─ web/ # 1st NextJS project | | └─ package.json | ├─ docs/ # 2nd NextJS project ├─ packages/ └─ ui/ # Shared components └─ package.json

In the root directory (project/) initialize via pnpm:

project/
pnpm init

The root package.json should have this at the very least:

project/package.json
{ "name": "project", "version": "0.1.0", "private": true, "packageManager": "[email protected]", }

Configure workspaces

Create a pnpm-workspace.yaml file in the root directory and add the following:

project/pnpm-workspace.yaml
packages: - "apps/*" - "packages/*"

This defines the packages that are part of the workspace.

Configure the shared components package

In packages/ui, initialize a new pnpm package:

project/
cd packages/ui pnpm init

The package.json should look something like:

packages/ui/package.json
{ "name": "@project/ui", "version": "0.1.0", "private": true, "exports": { "./Button": "./src/components/Button.tsx" // we'll soon create this file // ... more components as needed }, "peerDependencies": { "react": "^19.2.3", }, "packageManager": "[email protected]", }

Now let's make a simple Button component in packages/ui/src/components/Button.tsx:

packages/ui/src/components/Button.tsx
import React from "react"; export const Button: React.FC = () => { return <button>Click me</button>; }

We can now re-use this component in the NextJS projects.

Install the shared package in NextJS projects

In apps/web and apps/docs, install the shared package by modifying their package.json files:

apps/web/package.json
{ "dependencies": { // ... rest of dependencies "@project/ui": "workspace:*", } }

Then run pnpm install in both projects to install the shared package.

Now we can use the Button component in the NextJS projects.

apps/web/pages/index.tsx
import { Button } from "@project/ui/Button"; export default function Home() { return <Button />; }

And in apps/docs/pages/index.tsx:

apps/docs/pages/index.tsx
import { Button } from "@project/ui/Button"; export default function Home() { return <Button />; }

We're now using the Button component in both the web and docs NextJS projects.

Wrapping Up

That's it! We have successfully shared a component between two NextJS projects.

  • No type aliases
  • No build step

Hope this short tutorial helps someone.

Join my newsletter for lessons, experiments, and failures in bootstrapping online businesses.

Sign up if you're curious. I’ll only email you if it's actually good.

Ryan Chiang

Meet the Author

Ryan Chiang

Hello, I'm Ryan. I build things and write about them. This is my blog of my learnings, tutorials, and whatever else I feel like writing about.
What I'm currently building →.

2026

2025

2024

2023

© 2023-2026 Ryan Chiangryansc.io

Join my newsletter for lessons, experiments, and failures in bootstrapping online businesses.

Sign up if you're curious. I’ll only email you if it's actually good.