
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
Monorepos? Great. Publishing from a monorepo? Comically hard.
Consider @acme/my-awesome-package, which imports @acme/internal-utils, a workspace dependency.
Now you want to publish it.
npm publish produces an uninstallable package - @acme/internal-utils was never published.@acme/internal-utils is a permanent public API - rename a function there, break consumers you never intended to have.monocrate is a publishing CLI that gets monorepos. It produces a single publishable directory containing everything needed from your package and its in-repo dependencies.
The result: a standard npm package that looks like you had hand-crafted it for publishing.
⚠️ ESM only — monocrate only supports ES modules. If your monorepo uses CommonJS, you need to migrate to ESM first.
# Install
pnpm add --save-dev monocrate
# Or: yarn add --dev monocrate
# Or: npm install --save-dev monocrate
# Build first (monocrate publishes; it doesn't build)
npm run build
# Publish
npx monocrate publish packages/my-awesome-package --bump patch
# Or: assemble without publishing
npx monocrate pack packages/my-awesome-package --pack-destination /tmp/inspect --bump patch
Given this monorepo structure:
/path/to/my-monorepo/
└── packages/
├── my-awesome-package/
│ ├── package.json # name: @acme/my-awesome-package
│ └── src/
│ └── index.ts # import ... from '@acme/internal-utils'
└── internal-utils/
├── package.json # name: @acme/internal-utils (private)
└── src/
└── index.ts
Running npx monocrate pack packages/my-awesome-package produces:
/tmp/monocrate-xxxxxx/
└── packages/
└── my-awesome-package/ # preserves the package's original path
├── package.json # name: "@acme/my-awesome-package", version: "1.3.0" (the new resolved version)
├── dist/
│ └── index.js # rewritten:
│ # import ... from '../deps/__acme__internal-utils/dist/index.js'
└── deps/
└── __acme__internal-utils/ # mangled package name, the exact notation may vary.
└── dist/
└── index.js
The deps/ directory is where in-repo dependencies are embedded. Each dependency is placed under a mangled form of
its package name, avoiding collisions regardless of where packages live in the monorepo.
Note: The actual directory name includes a randomized suffix (e.g.,
deps-a1b2c3d4/) to prevent conflicts with existing directories in your package.
For details on how monocrate assembles packages, see The Assembly Process.
⚠️ Important:
require() calls are not rewritten, which will cause runtime failures for consumers. Only use monocrate on ESM-compliant monorepos.package.json, not embedded. It's your responsibility to ensure these are published and available to consumers.monocrate validates (and rejects with a clear error):
await import('@pkg/lib') works; await import(variable) does not.The --bump flag determines the published version. There are three approaches:
--bump value | Source of truth | Example result |
|---|---|---|
patch/minor/major | npm registry | 1.2.3 → 1.2.4 |
1.8.9 | CLI argument | 1.8.9 |
package | package.json | (whatever's in the file) |
When publishing multiple packages, see Multiple Packages for unified versioning with --max.
In all cases, your source package.json is never modified—the resolved version only appears in the assembled output.
# Registry-based: query npm, bump from latest (default is minor)
npx monocrate publish packages/my-awesome-package # bumps minor
npx monocrate publish packages/my-awesome-package --bump patch
# Explicit: use exact version
npx monocrate publish packages/my-awesome-package --bump 2.3.0
# Package-based: read from package.json
cd packages/my-awesome-package
npm version minor --no-git-tag-version
npx monocrate publish . --bump package
For custom build steps, or integration with other tooling, you can use monocrate as a library instead of invoking the
CLI:
import { monocrate } from 'monocrate'
const result = await monocrate({
pathToSubjectPackages: ['packages/my-awesome-package'],
publish: true,
bump: 'minor',
cwd: process.cwd(),
})
console.log(result.summaries[0].version) // '1.3.0'
The above snippet is the programmatic equivalent of npx monocrate publish packages/my-awesome-package --bump minor.
Sometimes your internal package name doesn't match the name you want on npm. Add a monocrate.publishName field to
your package.json to publish under a different name without renaming the package across your monorepo:
{
"name": "@acme/my-awesome-package",
"monocrate": {
"publishName": "best-package-ever"
}
}
Want to open-source your package while keeping your monorepo private? Use --mirror-to to copy the package and its
in-repo dependencies to a separate public repository:
npx monocrate publish packages/my-awesome-package --mirror-to ../public-repo
This way, your public repo stays in sync with what you publish—all necessary packages included. Contributors can clone and work on your package.
Requires a clean working tree. Only committed files (from git HEAD) are mirrored.
If you have several public packages in your monorepo, publish them in one go by listing multiple directories:
npx monocrate publish packages/lib-a packages/lib-b --bump patch
By default, each package will be published with its own version (individual versioning). If lib-a is at 1.0.0 and lib-b
is at 2.0.0, a patch bump publishes them at 1.0.1 and 2.0.1 respectively.
You can also publish all specified packages at the same version (unified versioning, à la AWS SDK v3), by using the
--max flag. This applies the bump to the maximum version and publishes all packages at that version.
# Now both will be published at 2.0.1 (the max)
npx monocrate publish packages/lib-a packages/lib-b --bump patch --max
This is purely a stylistic choice; it doesn't affect correctness since in-repo dependencies are always embedded.
monocrate <command> <packages...> [options]
Arguments
| Argument | Description |
|---|---|
command | pack (create tarballs only) or publish (publish to npm) |
packages | One or more package directories to process (required) |
Options
| Option | Alias | Type | Default | Description |
|---|---|---|---|---|
--bump | -b | string | minor | Version bump strategy: patch, minor, major, package, or explicit semver (e.g., 2.3.0). Use package to read version from package.json. |
--max | boolean | false | Use max version across all packages (unified versioning). When false, each package uses its own version. | |
--pack-destination | -d | string | (temp dir) | Directory to write tarballs to (pack command only) |
--root | -r | string | (auto) | Monorepo root directory (auto-detected if omitted) |
--mirror-to | -m | string | — | Mirror source files to a directory (for public repos) |
--result-file | string | — | Write full result as JSON to file | |
--help | Show help | |||
--version | Show version number |
monocrate(options): Promise<MonocrateResult>
Assembles one or more monorepo packages and their in-repo dependencies, and optionally publishes to npm.
MonocrateOptions
| Property | Type | Required | Default | Description |
|---|---|---|---|---|
pathToSubjectPackages | string | string[] | Yes | — | Package directories to assemble. Relative paths resolved from cwd. |
publish | boolean | Yes | — | Whether to publish to npm after assembly. |
cwd | string | Yes | — | Base directory for resolving relative paths. |
bump | string | No | "minor" | Version specifier: "patch", "minor", "major", "package", or explicit semver. |
max | boolean | No | false | Use max version across all packages (unified versioning). |
packDestination | string | No | (temp dir) | Output directory for the assembled package. |
monorepoRoot | string | No | (auto) | Monorepo root directory; auto-detected if omitted. |
mirrorTo | string | No | — | Mirror source files to this directory. |
npmrcPath | string | No | — | Path to .npmrc file for npm authentication. |
MonocrateResult
| Property | Type | Description |
|---|---|---|
resolvedVersion | string | undefined | The unified resolved version (only set when max: true). |
summaries | Array<{ packageName: string; version: string; tarballPath: string }> | Details for each assembled package, including version and path to generated tarball. |
FAQs
From monorepo to npm in one command
We found that monocrate demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.