Custom Builder
Inject custom esbuild plugins into the Native Federation Angular builder via runBuilder.
Sometimes you need an esbuild plugin in the federation build itself — code transformation, bundling tweaks, third-party tooling. Since v4 the Angular adapter exposes its builder factory as runBuilder from @angular-architects/native-federation/internal, so you can wrap it in your own Architect builder and pass extra plugins through.
The Pattern
- Write a tiny builder file that calls
runBuilderwith an extended options object. - Point the relevant
angular.jsontargets at your wrapper instead of the default@angular-architects/native-federation:build.
1. The wrapper
// custom-builder.js
import { runBuilder } from '@angular-architects/native-federation/internal';
import { createBuilder } from '@angular-devkit/architect';
import { myEsbuildPlugin } from './my-esbuild-plugin.js';
async function* customBuilder(options, context) {
const nfOptions = {
...options,
plugins: [
myEsbuildPlugin(),
// ...more plugins
],
};
yield* runBuilder(nfOptions, context);
}
export default createBuilder(customBuilder);
The plugins array is appended to the adapter's own externals plugin, so the order is: externals plugin first, then yours. Plugins receive the standard esbuild PluginBuild interface and run for both the federation build (shared bundles, exposed modules) and the Angular build path.
2. Wire it in angular.json
{
"projects": {
"mfe1": {
"architect": {
"build": {
"builder": "./custom-builder",
"options": {
"projectName": "mfe1",
"tsConfig": "projects/mfe1/tsconfig.federation.json"
// ... everything you'd normally pass to the federation builder
}
},
"serve": {
"builder": "./custom-builder",
"options": { /* same idea */ }
}
}
}
}
}
You're swapping the builder, not the options schema — every option from Builder → Options still applies.
Notes
runBuilderis exposed from@angular-architects/native-federation/internal. As the name suggests, it's not part of the public API guarantee — minor bumps may rename or refine the signature. Pin the adapter version when you ship a custom builder.- Plugins added this way only run inside the build the adapter drives. They do not see Angular CLI's pipeline outside the federation flow.
- If you only need a config tweak rather than a plugin (e.g. forcing externals, changing output paths), prefer the existing builder options or a
federation.config.mjschange.
Related
- Builder — the options the wrapper inherits.
- Core: Build Adapters — the contract under the hood (
NFBuildAdapter) if you'd rather plug a different bundler in entirely.