Library / SDK
eirslett/frontend-maven-plugin avatar
eirslett/frontend-maven-plugin

frontend-maven-plugin: Node and npm Inside Your Maven Build

"Maven-node-grunt-gulp-npm-node-plugin to end all maven-node-grunt-gulp-npm-plugins." A Maven plugin that downloads/installs Node and NPM locally, runs NPM install, Grunt, Gulp and/or Karma.

4,384 stars869 forksJavaApache-2.0

At a glance

What is it?
A Maven plugin that downloads Node and npm into the project, runs npm install and frontend tasks such as Grunt, Gulp or Karma, and keeps the same Node version in every build environment. It is for backend teams that do not want Node installed on the build machine.
Who is it for?
Adopt it if your backend is built with Maven and the frontend build must run in the same reactor without a globally installed Node. Do not adopt it if you already have a working Node toolchain and only need to call an existing binary: the README points those users at exec-maven-plugin instead.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 2 days ago.
What is it written in?
Mainly Java, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The gap frontend-maven-plugin fills between Maven and a Node toolchain

A Java project built with Maven has no opinion about Node. The moment a build needs npm install, a Gulp task or a Karma run, something outside Maven has to provide the Node binary, and that something is usually a machine image, a CI image or a developer laptop. The version then drifts: the build server has one Node, the laptop has another, and a lockfile generated by one may not resolve identically under the other.

This plugin moves that dependency inside the build. According to the README, it downloads and installs Node and npm locally for your project, runs npm install, and then any combination of Bower, Grunt, Gulp, Jspm, Karma or Webpack. Node and npm are placed in a node folder created in the installation directory, so they are local to the project and do not interfere with any Node installation already on the system.

The audience is specific. The README says frontend developers will still install Node on their laptops, but backend developers can run a clean build without installing Node at all. That is the whole proposition: one Maven plugin, one pinned Node version, no global toolchain on the build host.

The README is equally clear about what it is not. It is not meant to replace the developer version of Node, and it is not meant to install Node for production use. The Node usage is intended as part of a frontend build, running tasks such as minification, obfuscation, compression, packaging and testing.

How the download, install and task execution actually work

The mechanism is a Maven plugin with executions bound to lifecycle phases. An execution declares a goal, and the plugin runs it during the phase you bind it to; the README notes that the default phase is generate-resources. A typical setup has one execution for install-node-and-npm and separate executions for the npm and frontend tasks that follow.

Version resolution happens at download time, not at build time. The README states that the versions of Node and npm are downloaded from https://nodejs.org/dist, extracted, and put into a node folder created in your installation directory. The nodeVersion and npmVersion configuration keys decide which archive is fetched. For Node versions greater than 4.0.0, the README says the plugin uses the npm provided by the Node distribution, so npmVersion is optional in that case.

Because the download root is configurable, the plugin works in locked-down networks. downloadRoot changes the default https://nodejs.org/dist, and nodeDownloadRoot and npmDownloadRoot let you point Node and npm at separate mirrors, since the README notes they are stored in separate repositories. If the mirror requires authentication, serverId names a server entry from your Maven settings file. The README also mentions using Nexus Repository Manager to proxy npm registries.

Task execution is a chain of goals rather than a shell script. Each frontend tool has its own goal, and the README recommends running all your tasks via npm scripts instead of invoking bower, grunt or gulp directly. That recommendation matters for maintenance: a package.json script is one place to change when a tool is swapped, while a Maven goal binding is one place per tool.

One structural constraint is worth stating plainly. The README says the plugin does not support already installed Node or npm versions, and directs users who want that to exec-maven-plugin. So the pinned download is not an optimisation you can turn off; it is the design.

Installing frontend-maven-plugin and running a first npm build

The plugin is consumed as a Maven plugin declaration, not as a standalone installer. The README shows the groupId com.github.eirslett and the artifactId frontend-maven-plugin, with the version replaced by the latest tagged release from Maven Central. The README also states the requirements: Maven 3.6 and Java 17, with Maven 4 reported to work fine. Maven 2 support lives in the project wiki rather than the README.

Start with the plugin declaration inside the plugins element of your pom.xml. The comment in the README points at the Maven Central directory listing for the plugin, which is where you read the current version.

xml
<plugins>
    <plugin>
        <groupId>com.github.eirslett</groupId>
        <artifactId>frontend-maven-plugin</artifactId>
        <!-- Use the latest released version:
        https://repo1.maven.org/maven2/com/github/eirslett/frontend-maven-plugin/ -->
        <version>LATEST_VERSION</version>
    </plugin>
</plugins>

Next, add the execution that downloads Node and npm. The execution id is optional but the README notes it looks nice in your build log. The goal is install-node-and-npm, and the default phase is generate-resources.

xml
<execution>
    <id>install node and npm</id>
    <goals>
        <goal>install-node-and-npm</goal>
    </goals>
    <phase>generate-resources</phase>
</execution>

Then pin the versions in the plugin configuration. The README example uses nodeVersion v24.12.0 and npmVersion 11.6.2, and notes that for Node greater than 4.0.0 the npm bundled with the distribution is used. When you run the build, the plugin fetches the archives and extracts them into the node folder in the installation directory.

xml
<configuration>
    <nodeVersion>v24.12.0</nodeVersion>
    <npmVersion>11.6.2</npmVersion>
    <downloadRoot>http://myproxy.example.org/nodejs/</downloadRoot>
</configuration>

After the install execution, bind the npm goal to run your install step, and add further executions for the tools you use. The README points to the example project at frontend-maven-plugin/src/it/example project/pom.xml as the reference setup. Two practical notes from the README: gitignore the node folder unless you actually want to commit it, and prefer npm scripts over direct Grunt or Gulp goals.

Where frontend-maven-plugin stops being the right tool

The most common failure is reaching for it when Node is already present. The README is explicit that the plugin does not support already installed Node or npm versions and names exec-maven-plugin as the alternative. If your CI image already ships the exact Node version you need, this plugin adds a download step and a second copy of Node on disk for no benefit.

Production is the second boundary. The README says the Node usage is intended as part of a frontend build, not for installing Node for production uses. Running a Node server process from a Maven build is outside what the project claims to do.

Network policy is the third. The default download root is https://nodejs.org/dist, and the README offers downloadRoot, nodeDownloadRoot, npmDownloadRoot and serverId for mirrors and credentials. In an environment where outbound access to those hosts is blocked and no internal mirror exists, the install execution cannot complete. That is a configuration problem with a documented answer, but it is a real prerequisite.

There is also a versioning hazard that the README does not resolve. The README says to change LATEST_VERSION to the latest tagged version, which means the plugin version is a manual decision with no automatic upgrade path described in the README. Combined with a pinned nodeVersion, you have two version numbers to track, and the README does not document rollback if a new plugin version or Node version breaks a build.

Finally, the plugin is a build-time coordinator, not a package manager. It does not replace npm's resolution behaviour, and it does not make two different lockfiles agree. If your problem is dependency resolution rather than Node provisioning, this plugin will not solve it.

frontend-maven-plugin against exec-maven-plugin and a separate frontend pipeline

The README itself names the closest alternative: exec-maven-plugin, for projects that want to use an already installed Node or npm. The difference is ownership of the toolchain. exec-maven-plugin assumes Node exists on the machine and simply invokes it, so the build inherits whatever version the host provides. frontend-maven-plugin downloads a version you declare and installs it into the project directory, which is why the README can promise the same Node and npm in every build environment. You trade a download on first build and a node folder on disk for version determinism.

The other real alternative is architectural rather than a different plugin: keep the frontend in its own repository and build it with its own Node-based CI job, then publish the artefacts for the Java build to consume. That removes Node from the Maven reactor entirely. The README's stated goal is the opposite, letting you keep frontend and backend builds as separate as possible while reducing the interaction between them to one plugin. If your teams are already split along those lines, a separate pipeline is simpler than a plugin binding; if a single Maven invocation must produce both halves, the plugin is the shorter path.

Within the plugin's own scope there are choices too. The README supports npm, Yarn and corepack as package managers, and separate goals for Bower, Grunt, Gulp, Jspm, Karma and Webpack. The README's recommendation to route tasks through npm scripts rather than direct tool goals is the closest thing to a design opinion in the document, and it is a good one: it keeps the Maven configuration small and puts tool-specific logic where frontend developers already look.

Maintenance, licence and what an upgrade actually costs

The repository is not archived, and the last push was on 2026-08-04. That is recent enough that the project is being touched, though the README does not describe a release cadence and no recent releases were retrieved, so treat the plugin version as something you check rather than something that moves on a schedule.

Upgrade cost is concentrated in two configuration values. The plugin version lives in the version element of the plugin declaration, and the README instructs you to read the latest tagged version from the Maven Central directory listing. The Node version lives in nodeVersion, with npmVersion alongside it for older Node lines. Changing either one changes what gets downloaded on the next clean build, so a version bump is a build-environment change, not a source change. The README does not document a rollback procedure, and it does not describe a compatibility matrix between plugin versions and Node versions beyond the note that Node greater than 4.0.0 uses the npm bundled with the distribution.

The project is licensed under Apache-2.0, which is a permissive licence that permits commercial use and modification, and it includes an explicit patent grant. That is a statement about the licence text, not legal advice; if your organisation has policy about bundled third-party components, the plugin downloads Node and npm at build time, and those have their own licences that your review should cover separately.

Operationally, the node folder created in the installation directory is the artefact to think about. The README says to gitignore it unless you want to commit it, which also means a clean checkout pays the download again unless your CI caches that directory. The README does not document caching, so that is a decision for your build configuration.

Editorial conclusion

Adopt it if your backend is built with Maven and the frontend build must run in the same reactor without a globally installed Node. Do not adopt it if you already have a working Node toolchain and only need to call an existing binary: the README points those users at exec-maven-plugin instead. Before wiring it in, verify that the exact Node version you need exists under https://nodejs.org/dist, that your Maven is 3.6 or newer on Java 17, and that the node folder it creates in the installation directory is in .gitignore.

Frequently asked questions

What is frontend-maven-plugin?

It is a Maven plugin that downloads and installs Node and npm locally for your project, runs npm install, and then any combination of Bower, Grunt, Gulp, Jspm, Karma or Webpack. The README states that Node and npm go into a node folder in your installation directory and are not installed globally.

What is the frontend-maven-plugin alternative if Node is already installed?

The README points to exec-maven-plugin, noting that this plugin does not support already installed Node or npm versions. If your build host already provides the exact Node version you need, exec-maven-plugin invokes it instead of downloading a second copy.

What does frontend-maven-plugin require to run?

The README lists Maven 3.6 and Java 17 as requirements, and notes that Maven 4 seems to work fine. Maven 2 support is documented in the project wiki rather than the README.

Can frontend-maven-plugin use a Node version that is already on the machine?

No. The README states that the plugin does not support already installed Node or npm versions and directs those users to exec-maven-plugin. The versions you declare are downloaded from https://nodejs.org/dist and extracted into the node folder in the installation directory.

How do I configure frontend-maven-plugin behind a proxy or private mirror?

The README provides downloadRoot to replace the default https://nodejs.org/dist, plus nodeDownloadRoot and npmDownloadRoot for separate mirrors, and serverId to reference credentials from your Maven settings file. It also mentions using Nexus Repository Manager to proxy npm registries.

Official sources

  1. eirslett/frontend-maven-plugin on GitHub
  2. Issues
  3. License: Apache-2.0
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/eirslett-frontend-maven-plugin.svg)](https://hysenlabs.com/projects/eirslett-frontend-maven-plugin)