After we have written the code and compile it, the next step is to build and deploy it somewhere. We can go two ways here:
- build many times the code, deploy it many times
- build once the code, deploy it many times
Build many
This is the way many of you are familiar with, as this is a common way of building and deploying code. Basically you have a build tool and you will build a deployable (jar, war, ear) for each environment. With maven you can do this with maven profiles. At the end of the process the deployable is ready and cannot(should) be changed externally.

There will be a build job for each environment, and naturally the build will take longer. There are unit tests, integration and end to end tests to be run.
Build once
This has taken shape over the last years, and it goes hand in hand with the CI/CD process. The code is build once and the deployable can be externally changed with environment variables. Spring profiles are widely used for this. There is one build job which takes significantly less time to run. The tests run only once. One difference here is that the deployable must live somewhere.
Now, which is the right way of doing it? Is there even a right way? I don’t think so. Just ask yourself some questions. Do you deploy often? Then build once is a good way to go. Are you doing waterfall with deployments at a 3 months interval? Then it does not matter which one you choose. I’ve seen the build many approach in projects that basically are a bit old and the guys working on them did no want to change a working process. Which is more error prone? If you think of environment variables you could easily screw up some configurations. It is less likely if you use a small number of variables and keep most of them in a spring profile. On the other hand since there is one binary file created that means fewer chances of mistakes. If you have build many in place, the build should be created from tags in order to avoid situations like when a commit is pushed after the test environment is built and it breaks the staging environment.
But we need flexibility! We need it even if we can possibly break things, we will find the issue faster. Just look at a docker example:
docker run -it --rm --name mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=debezium -e MYSQL_USER=mysqluser -e MYSQL_PASSWORD=mysqlpw debezium/example-mysql:0.6
What if we have a frontend and a backend and we want to build them together as a whole? One build process. Unless the frontend framework is able to read environment variables we cannot build it in one shot. We are able though to pass environment parameters at the build time(maven profiles again), but we still need multiple deployables. So here there could be a combination of both worlds: build many for the frontend, build once for backend.