Skip to main content

Publishing an npm package to Sonatype Nexus

Parameters for publishing an npm package. Creating an npm repository in Nexus, registering a user, and configuring Realm.

Setting up a build in Vite

Example vite.config.ts with vite-plugin-dts plugin for exporting TS types:

vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import dts from 'vite-plugin-dts';

export default defineConfig({
plugins: [
react(),
dts({
rollupTypes: true,
tsconfigPath: './tsconfig.app.json',
}),
],
build: {
lib: {
entry: 'src/components/index.ts',
name: 'MyComponentLibrary',
fileName: (format, name) => `${name}.${format}.js`,
},
rollupOptions: {
external: ['react', 'react-dom', '@mui/material', '@emotion/react', '@emotion/styled'],
output: {
globals: {
react: 'React',
'react-dom': 'ReactDOM',
'@mui/material': 'MaterialUI',
'@emotion/react': 'EmotionReact',
'@emotion/styled': 'EmotionStyled',
},
},
},
},
});

The bundle is placed in the dist/ folder by default.

The file name is defined in the build.lib.fileName callback and contains the module name and its format:

  • es — ESM module;
  • umd — CommonJS module.

Project description in package.json

package.json
{
"name": "My project name",
"version": "0.1.0",
"description": "My project description",
"type": "module",
"main": "dist/index.umd.js",
"module": "dist/index.es.js",
"types": "dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.es.js",
"require": "./dist/index.umd.js"
}
},
"files": [
"dist"
],
"publishConfig": {
"registry": "http://localhost:8081/repository/my-test-repo-hosted/"
},
"scripts": {
"build": "tsc -b && vite build",
"lint": "eslint .",
"storybook": "storybook dev -p 6006",
"build-storybook": "storybook build"
},
"devDependencies": {
// ...
},
"peerDependencies": {
"@emotion/react": "^11.0.0",
"@emotion/styled": "^11.0.0",
"@fontsource/roboto": "^5.1.1",
"@mui/icons-material": "^6.4.0",
"@mui/material": "^6.0.0",
"react": ">=18.0.0",
"react-dom": ">=18.0.0"
},
"eslintConfig": {
"extends": [
"plugin:storybook/recommended"
]
}
}

Here in the exports field in the nested field .:

  • types — path to the bundle with types;
  • import — path to the ESM bundle;
  • require — path to the CommonJS bundle.

The publishConfig.registry field specifies the address of the npm hosted repository in Nexus.

Setting up Sonatype Nexus

1. Install and launch Nexus

Deploy Sonatype Nexus in a Docker container using these instructions: Sonatype Nexus installation using Docker

2. Enable Realm for npm

Pasted image 20250401184417.png

3. Create a role to read and write packages to the repository

Open the role creation form:

  • go to Security -> Roles
  • proceed to role creation by clicking the Create Role button
  • fill in the fields:

Pasted image 20250401185153.png

Below in the Applied Privileges section, to add privileges, click Modify Applied Privileges and filter the list that opens by the value npm, then select privileges:

  • nx-repository-view-npm-*-browse
  • nx-repository-view-npm-*-edit
  • nx-repository-view-npm-*-read and save by pressing the Confirm button:

Pasted image 20250401190722.png

Leave the Applied Roles section blank:

Pasted image 20250401191109.png

Create a role using the Save button.

4. Create a user to publish the package

  • go to the Security section -> Users
  • proceed to role creation by clicking Create local user
  • fill in the fields with user information
  • at the end of the form, move the previously created role to the right column Granted
  • create a user by clicking Create local user

Pasted image 20250401191627.png

5. Create repositories

3 repositories need to be created: proxy, hosted, and group:

Pasted image 20250401192125.png

To create each of them you need:

  • Go to the Repositories section -> Repositories
  • Proceed to creating a repository by clicking the Create repository button.

Proxy repository

In the Recipe list that opens, select npm (proxy) and fill in the fields:

  • Name - preferred repository name (add "proxy" at the end for identification);
  • Remote storage - the address of the remote repository with packages (enter the public address https://registry.npmjs.org).

Leave the remaining fields as default and create a repository using the Create repository button:

Pasted image 20250401193011.png

Hosted-репозиторий

In the Recipe list that opens, select npm (hosted) and fill in the fields:

  • Name - preferred repository name (add "hosted" at the end for identification);
  • Deployment policy - policy for redeploying the same version.

Leave the remaining fields as default and create a repository using the Create repository button:

Pasted image 20250401193157.png

Group-репозиторий

In the Recipe list that opens, select npm (group) and fill in the fields:

  • Name - preferred repository name (add "group" at the end for identification);
  • Member repositories - list of grouped repositories. Drag newly created proxy and hosted repositories into the Members column on the right.

Leave the remaining fields as default and create a repository using the Create repository button:

Pasted image 20250401194002.png

6. Authorization in the npm repository

To authorize, execute a command like this:

npm login --registry=[repository-address]/repository/[hosted-repository-name]/

Attention!!! It's important to include the trailing slash / after the repository name in the command. For example, for a locally deployed Nexus:

npm login --registry=http://localhost:8081/repository/my-test-repo-hosted/

Repository credentials are stored in the .npmrc file. After authorization, a line like this appears in the file:

//[repository-address]/repository/[hosted-repository-name]/:_authToken=NpmToken.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

Pasted image 20250401200415.png

If you have problems with authorization, remove the line from the .npmrc file and authorize again.

7. Publishing a package to an npm repository

To publish a package, first build the bundle:

npm run build

After building, run the following command from the project directory:

npm publish

When running this command without any additional parameters, the package will be published to the hosted repository specified in the publishConfig.registry field of the package.json file (see the example in the section Project description in package.json).

The address of the hosted repository for publication can be specified explicitly by adding the --registry parameter (don't forget the slash / at the end after the repository name):

npm publish --registry=http://localhost:8081/repository/my-test-repo-hosted/

8. Installing a published package in another project from the Nexus group repository

To install a package, you must explicitly specify the address of the group repository using the --registry parameter (don't forget the slash / at the end after the repository name):

npm install my-component-library@0.1.0 --registry http://localhost:8081/repository/my-test-repo-group/