React + Quarkus integration using Maven 5


In this post I will show you how to serve a ReactJS (or any other JavaScript SPA) front-end application using a Java Quarkus Application as a back-end and static page server. The post also includes instructions on how to configure Maven to perform the front-end build tasks along with your application packaging.

This article is very similar to my 2017 Angular + Spring Boot integration using Gradle blog post, with some added features to enable React’s router to work.


The technology stack required for this example is:

The main goal is to achieve an npm install + build that integrates with the Maven resources plugin and deploys the distribution files to a directory where Quarkus can serve them. Quarkus will then act both as the back-end service and the gateway API to serve the front-end too.

You can find the code for these configurations in my YAKC – Kubernetes Dashboard quickstart application for YAKC (Yet Another Kubernetes Client).

Back-end (Quarkus)

In this new Microservice world, it makes sense that the front-end and back-end(s) are different services that are usually served and orchestrated by a gateway API. It’s hard to find those former web applications where front-end and back-end were part of the same service.

An image showing a microservice vs a monolith

This distributed architecture makes sense for large enterprise projects, but sometimes we just want to prototype or quickly build a simple web application. That’s the time when you start missing those old monoliths and their simplicity that allowed you to quickly create and especially deploy your application.

The main goal is to achieve that Quarkus acts as a gateway API. So in addition to provide the REST API, it serves the front-end files too. This way we get to keep ReactJS as our main front-end technology, Quarkus as our back-end, and avoid all of the extra complexities needed for a 2 (or more) separate service deployment.

You may think that Quarkus already provides a way to serve static resources and that the solution is as simple as storing the front-end built files in this directory before building the back-end. However, this will not allow the React router to work and you wouldn’t be able to route /nested/front-end/routed/paths (Just try to refresh your browser in one of those nested paths).

GatewayResource class

This class is the main entry point for any HTTP request that the application receives.

The first method, getApiResource delegates any request to /api/v1 to the ApiResource subresource instance that will take care of it.

The getFrontendRoot will take care of any request to the root path /by requesting the index.html file to the getFrontendStaticFile which I’ll describe next.

Finally the getFrontendStaticFile will take care of the rest of the requests. The method first tries to locate any file with the provided file name in the /frontend resource directory. This directory should be packaged during the application build phase and contains the ReactJS built application.

If no file is found with this name, it will serve the index.html file. This is the part that allows the React router to work. Any request not matched either by the API subresource or a front-end file will serve the React application which will then take care of performing a “front-end” routing.

Front-end (React)

Your complete front-end application may be located anywhere within your project, in my case I’ve located it under src/main/frontend. Besides noting the path location for your React application, you don’t really need any extra configuration for this procedure to work.

Maven build

For the final step to integrate the React front-end with the Quarkus back-end you need to tune the Maven build.


In this first excerpt, I’ve added a new entry to the build resources configuration. Besides the standard src/main/resources, the directory where the React application is built src/main/frontend/build will also be assembled and copied to target/classes/frontend directory. If you recall, in the GatewayResource class, I was loading static resources from this directory.

Npm build + install

The second excerpt is used to run npm install and npm run build from Maven. I added this as a separate profile because I usually perform these steps manually while in my local machine. I only invoke them in the CI, so my CI build step looks like mvn -Pbuild-frontend clean package. However, there’s no problem in adding these configurations directly to your pom.xml build section.

As you can see I configured 2 executions for the Exec Maven Plugin. The first one will invoke npm install using the front-end home directory (src/main/frontend) as its working directory. The second execution has a similar configuration but runs npm run build instead.


Once your application is packaged, you can run it either by running the generated jar (java -jar ./target...) file or by running mvn quarkus:dev.

A recording of how front-end routing works with Quarkus

Development mode

If you want to enjoy and benefit from both Quarkus and React hot/live reloading you will need some extra configuration.

In this case, we will run the front-end using the standard npm start and pointing our browser to http://localhost:3000. And we’ll run our back-end using mvn quarkus:dev in http://localhost:8080.


Since the front-end is served from a different URL, we need to enable CORS in Quarkus.

We can do this by modifying our to include:

These properties enable CORS to allow requests from the front-end dev origin. You can modify the entries to make it more or less restrictive depending on your needs.


For the front-end part, we need to tune our React application to hit different back-end endpoints depending on the environment we’re running it on.

In my case, since I’m using create-react-app, I added two environment property files:

.env for production:

.env.development for dev:

Once these two files are ready, create-react-app takes care of the appropriate replacements in your application depending on your target environment. In order to use those values, you’ll need to reference the URL using the process.env.REACT_APP_API_URL variable:


In this post, I showed you how to serve both a JavaScript front-end and a Java back-end application using Quarkus. Quarkus acts as an API gateway and either serves the front-end static files or processes the back-end request using resources and services. I’ve also shown you how to combine and use hot reload in React and Quarkus by tuning the settings for each application.

I’ve extracted the code for this post from my YAKC – Kubernetes Dashboard quickstart. You can learn more by visiting  YAKC’s GitHub project site. You can also see related code here.

Leave a comment

Your email address will not be published. Required fields are marked *

5 thoughts on “React + Quarkus integration using Maven

  • Jeff Rogers

    This is very interesting, especially the gateway api. I’m new to microservices, but my understanding of them is that they are able to be deployed individually. It looks like the different resources in this example would be deployed in a single Quarkus instance.

    Is this still considered microservices?

    Could you expand on this topic a bit more on how the different services would be deployed individually using the quarkus rest client?

    Thank you for sharing this article.

    • Marc Nuri Post author

      > Is this still considered microservices?

      I wouldn’t consider what I depict in this post a microservice on its own. However, if this monolithic application (frontend+backend) was to be deployed as part of a distributed system and the architecture was designed according to a microservice philosophy (do one thing and do it well), I guess you could consider that as a microservice (micromonolith of sorts ;p).

      From my experience, front-ends are usually deployed as separate microservices. An API gateway (such as Zuul, NGINX, Traefik) is then used to redirect traffic to one service or another depending on certain parameters (e.g. HTTP path). Any of the resources served by the ApiResource class could be “easily” deployed as separate services (the left part of the diagram). You could then tune the gateway to serve traffic to those services by using a pattern matcher on the HTTP path.

      In this example the GatewayResource class represents this otherwise external API gateway. So another thing you could do is use this service as the front-end + API gateway server and use the Quarkus REST client to redirect traffic to other microservices (I’ve also seen this approach in some projects). The advantage of this is that you could use programmatic rules to compute where traffic should get redirected. However, this doesn’t follow the microservice philosophy since any change to the front-end would require a redeploy of the gateway (not doing a single thing and doing it well). You’d also lose the option (or at least make it much harder) to do front-end canary deployments, etc.

      I’m not sure if this clarified your doubts or introduced new ones. Anyway, thanks for reading 😉

  • Jeff Rogers

    I’m not a react developer, but I do use quarkus. Your GET method for index.html when a page is refreshed worked nice for my quarks/angular application.

    Thanks for sharing

  • Guillaume Fortin

    Hi, I have an issue with the code. When I call the api/v1, the app reacts the way it should however when I call the root it looks like the React App doesn’t trigger and I’m staying with a blank page.
    If I start the React app independently it’s working fine.

    The root path of my quarkus app is /klon/. it’s not the default /

    What could be the issue?

    • Marc Nuri Post author

      I’d guess that your front-end app hasn’t been built or deployed.

      In this example there is a build-frontend Maven profile that runs npm install and npm run build for you. Are you sure you’re invoking the maven command correctly (mvn -Pbuild-frontend clean package)?