docs/build-pieces/misc/bundling-pieces.mdx
Activepieces builds every piece into a self-contained bundle. Instead of shipping a piece that depends on @activepieces/shared, @activepieces/pieces-framework, @activepieces/pieces-common, and the @activepieces/core-* packages at install time, the build inlines all of that code into a single artifact.
This is what lets the engine provision a piece by downloading one artifact, with no bun install / npm install of a dependency tree at runtime.
When a piece is built for publishing, the bundler:
@activepieces/* workspace libraries (shared, pieces-framework, pieces-common, core-utils, core-piece-types, …) directly into the bundle. These libraries are never published to npm; they only exist as part of each piece's bundle.require. These remain in the published dependencies so the runtime installer resolves them.The result is typically ~2–3× smaller than the raw inputs, and the published package.json lists only the few unavoidable external deps (e.g. tslib).
After bundling, the piece's dist/package.json is rewritten:
{
"name": "@activepieces/piece-json",
"version": "0.1.7",
"main": "./src/index.js", // the self-contained bundle
"dependencies": {
"tslib": "2.6.2" // only genuinely-external deps remain
},
"files": ["src/index.js", "package.json", "src/i18n"]
}
No @activepieces/* dependency appears, so installing the piece never requires those packages to exist on the registry.
If a dependency must not be inlined (for example a native module), add it to a bundleDeps array in the piece's package.json. The bundler will keep it external and preserve it in the published dependencies.
{
"name": "@activepieces/piece-example",
"bundleDeps": ["some-native-addon"]
}
A file your piece loads by path at runtime (for example child_process.fork(path.join(__dirname, 'runner.js'))) is invisible to the bundler's import graph, so by default it would not exist in the published package. Declare it in bundleForkedEntries:
{
"name": "@activepieces/piece-oracle-database",
"bundleForkedEntries": ["src/lib/common/oracle-runner.ts"]
}
Each declared entry is bundled on its own and emitted next to the main bundle at src/<name>.js, which is where path.join(__dirname, '<name>.js') resolves at runtime, since the bundled parent code lives at src/index.js. Dependencies that only the forked file imports (e.g. oracledb) are still captured into the published dependencies.
The bundler fails the build if piece code uses __dirname without declaring any bundleForkedEntries, because such code breaks silently after publishing.
Bundling happens automatically when you build or publish a piece:
npm run build-piece <name>: builds and packs the bundle into a .tgz (see Build Custom Pieces).npm run publish-piece-to-api: bundles and uploads the piece to a platform (see Publish Custom Pieces).You don't need to configure anything for bundling; it is the default behavior.