Black Sheep Code
rss_feed

How to publish a React component package, using NextJS as the compiler

Published:

This is a short guide on publishing a React component library package to NPM, using NextJS as the compiler.

Motivation

Your component may be a straight client component with client hooks, and as such doesn't fall in to the React Server Components behaviour.

However, there are two reasons we might still want to use NextJS as our base:

  1. Server side rendering will still occur for your component, essentially the first render of the component will be rendered server side.
  2. In the future you might want to include RSCs in your component library, and so it's easier to make it work now.

Example code

All code for this tutorial can be found in this repo.

Step 1: Scaffold your project using create-next-app

Run npx create-next-app and follow the prompts

Step 2: Create a src/library folder and create your components

This is where you will create your component(s) for publishing.

Everything else will still be a regular NextJS project. You can use this as a sandbox for development, it won't be packaged for export.

Step 3: Create a src/exports.ts to export your files

Step 4: Add a tsconfig.build.json

You now have two tsconfigs, one for the regular NextJS application, and one specifically for building the package for publishing.

Step 5: Add build and publish scripts to your package.json

At this step I also like to prefix the existing start, build scripts with next: - because we need to distinguish between 'build the NextJS application' and 'build the package'.

Step 6: Mark React a dev + peer dependency, Next a dev dependency in your package.json

The only items in your dependencies object should be things that are required for your package to run in the context it's installed.

By marking them as dev dependencies they're available to you while developing the package but won't be needlessly installed by the application that uses it.

Note that I've marked the React peerDependencies with the >=18 rather than ^18. With the recent stable release of React 19, we want our package to be usable with React 19 applications without showing this warning:

npm error Found: react@19.0.0
npm error node_modules/react
npm error   react@"^19.0.0" from the root project
npm error
npm error Could not resolve dependency:
npm error peer react@"^18" from an-example-react-package-built-with-nextjs-tooling@0.3.0
npm error node_modules/an-example-react-package-built-with-nextjs-tooling
npm error   an-example-react-package-built-with-nextjs-tooling@"*" from the root project
npm error
npm error Fix the upstream dependency conflict, or retry
npm error this command with --force or --legacy-peer-deps
npm error to accept an incorrect (and potentially broken) dependency resolution.

Note that it's up to you to determine whether your package will be forward compatible with major React versions - for a simple package it probably will be.

Step 7: Add main, files and exports properties to your package.json

We define the entry points for our package with the main, exports properties, as well as a files property to only include the relevant code.

The exports syntax allows to define multiple entry points into our package, which as we'll see is necessary.

At this point it will be helpful to check if your package is building and configured correctly, and that another project is able to use it.

We can use npm link to emulate using the package, without really publishing to NPM before we are ready.

npm run build 
npm link 

And in the other project

npm link an-example-react-package-built-with-nextjs-tooling

You should now be able to use the package as if it were any other package.

Step 9: Differentiating client and non-client components

If you have a client component like:

And an exports file like:

Then at this point you may be seeing this error when you go to use it:

Error: Unsupported Server Component type: undefined

This appears to be a pitfall with RSCs and NextJS see this Stack Overflow question.

The resolution is to export your RSCs or your client components separately, like:

and be sure to add this new exports file to your tsconfig.build.json

We update our package.json to define a second entry point:

Now your users can use the components like so:

import {MyComponent } from "an-example-react-package-built-with-nextjs-tooling";
import {MyClientComponent} from "an-example-react-package-built-with-nextjs-tooling/client";

Step 9: npm publish

Run npm publish and see your published package!

This package is published here.

Addendum: Add other tooling you want to use

At this point you could add tools like Storybook for NextJS, or set up your unit tests etc.



Questions? Comments? Criticisms? Get in the comments! 👇

Spotted an error? Edit this page with Github