The is an and for the . The framework’s core features can be used by any Java application, but there are extensions for building web applications on top of the (Enterprise Edition) platform. Although the framework does not impose any specific , it has become popular in the Java community as an addition to, or even replacement, for the (EJB) model. The is an . Spring Framework application framework inversion of control container Java platform Java EE programming model Enterprise JavaBeans Spring Framework open source Spring Profiles provide a way to segregate parts of your application configuration and make it available only in . certain environments Preparation Spring profiles are a very useful concept in the framework but there are some gotchas to catch for mastering it. The following article aims to explain how profiles are applied and how to survive in a multi-profile set-up. Let's start from the set-up Spring-boot Lombok Gradle Everything starts from . This is a standard Spring boot command line application. Also introduce , this helps with print environment and properties. Application.java EnvironmentPrinter.java will be holding our properties that are defined into Properties.java application.yml Default profile Now everything is set up. Let us start the application and find out what happens: No active profile set, falling back to default profiles: default Active profiles: Properties: Properties(param1=param1) As we can see we don’t have an active profile. But application.yml is read and has the value Notice that because no active profiles have been set, spring falls back to profile. Default profile is applied to all spring beans that do not explicitly use @Profile annotation. param1 param1. default Let's try to introduce default profile: dev first, we create new yml for dev profile application-dev.yml app: param1: dev-param1 and add the following to application.yml: spring: profiles: default: dev Let's run our application again. No active profile set, falling back to default profiles: dev Active profiles: Properties: Properties(param1=param1) Okay, it seems correct. We do not have an active profile, so it falls back to dev profile… Wait a minute, why doesn't our have value ? param1 dev-param1 Active profile Default profile makes our beans to be in dev profile, but it doesn’t load any additional properties files. So, instead of introducing the default profile, we should introduce the . Replacing yml's relevant default profile block: active profile spring: profiles: active: dev gives us an output: The following profiles are active: dev Active profiles: dev Properties: Properties(param1=dev-param1) Now it looks the way we expected as it should be. Multiple active profiles Spring allows us to activate multiple profiles. I will introduce 2 more profiles, let's name them and . And I will create 2 more yml files. dev-db dev-mock #application-dev-db.yml app: param1: dev-db-param1 #application-dev-mock.yml app: param1: dev-mock-param1 Now I will activate the dev-db profile in file. Let us ignore the dev-mock profile right now. We will use it soon. application.yml #application.yml spring: profiles: active: dev,dev-db app: param1: param1 We are now expected to have active profiles and But which will be our param1 value? Let's run the application once again. dev dev-db. The following profiles are active: dev,dev-db Active profiles: dev,dev-db Properties: Properties(param1=dev-db-param1) If I switch active profiles to dev-db,dev , the new output as follows. The following profiles are active: dev-db,dev Active profiles: dev-db,dev Properties: Properties(param1=dev-param1) So, we can conclude that if property is overridden in another profile, the last profile in the row wins. Now let us try to activate one more profile but I want to do it in some active profile yml. In general, I will try to override property. spring.profiles.active #application-dev-db.yml spring: profiles: active: dev,dev-db,dev-mock app: param1: dev-db-param1 and output for that change The following profiles are active: dev,dev-db Active profiles: dev,dev-db Properties(param1=dev-db-param1) Hmm... okay, it seems that it is not possible to override active profiles definition. Include Of course, we can add to active profiles in but this is not always desired. Sometimes we want to have a certain profile include another profile. This can be done with property. Lets modify profile yml a little bit. dev-mock application.yml include dev The following profiles are active: dev,dev-db,dev-mock Active profiles: dev,dev-db,dev-mock Properties: Properties(param1=dev-mock-param1) As we can see, a new profile is included and applied as last in the row - so all the properties that introduces, will be included and they will override previous profile properties with the same name. dev-mock dev-mock Why to use include instead of modifying Usually we do not want to introduce active profiles in application.yml or we will override profiles with command line argument Command line override gives us the ability to introduce the exact profile per environment. application.yml. -Dspring.profiles.active=. Sometimes one single profile yml might be too long or there are many repetitions with other environments. In this case, it is much more convenient to use single profile in the command line property and include the other profiles in that profile's yml file. For example, might include profiles to act like a dev environment but override database's and some third party API URL's. local-dev dev,local-db,local-mock In this case we introduce yml as follows: #application-local-dev.yml spring: profiles: include: dev,local-db,local-mock And execute with command line parameter "-Dspring.profiles.active=local-dev" The following profiles are active: local-dev,dev,local-db,local-mock Active profiles: local-dev,dev,local-db,local-mock Properties: Properties(param1=dev-param1-override) I didn't change , it still contains an active profile as . But as you can see this is not applied. It is because of command line argument. So, If we use the command line argument, spring boot will ignore property in yml file. application.yml dev,dev-db spring.profiles.active This is a nice feature to know. This helps to configure the application so that it has a default active profile which will be used if nothing is specified. I usually use as default active profile and all other environments use command line parameter for overriding this profile. local-dev In my experience, it is useful to keep running the app in the local environment as easy as possible because this is an environment that must be built up multiple times for different developers in different locations. Hassle-free local environment helps start coding as soon as possible. Nobody wants to hear day after day that a professional developer must waste his/her time with setting up an environment. Overrides So far, I played with profiles and their inclusions. I already showed how profiles override each other's properties. Now let us dig deeper. Spring Boot uses a very particular PropertySource order that is designed to allow sensible overriding of values. Properties are considered in the following order (with values from lower items overriding earlier ones)[ ]: https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-external-config Default properties (specified by setting SpringApplication.setDefaultProperties). annotations on your @Configuration classes. Please note that such property sources are not added to the Environment until the application context is being refreshed. It is too late to configure certain properties such as logging.* and spring.main.* which are read before refreshing begins. @PropertySource Config data (such as application.properties files) A RandomValuePropertySource that has properties only in random.*. OS environment variables. Java System properties (System.getProperties()). JNDI attributes from java:comp/env. ServletContext init parameters. ServletConfig init parameters. Properties from SPRING_APPLICATION_JSON (inline JSON embedded in an environment variable or system property). Command line arguments. properties attribute on your tests. Available on and the . @SpringBootTest test annotations for testing a particular slice of your application annotations on your tests. @TestPropertySource in the $HOME/.config/spring-boot directory when devtools is active. Devtools global settings properties As we can see the config data is number three in the list. So it's quite low in priority. In other words, we have plenty of options to override application properties. I will not get into these because I want to keep the focus on yml files. After all, this is an article about profiles. So let's concentrate on the third bullet point. Config data files are considered in the following order: packaged inside your jar (application.properties and YAML variants). Application properties packaged inside your jar (application-{profile}.properties and YAML variants). Profile-specific application properties outside of your packaged jar (application.properties and YAML variants). Application properties outside of your packaged jar (application-{profile}.properties and YAML variants). Profile-specific application properties Externalizing yml Right now, our yml files were in classpath. Let's assume that we have an application as jar and we want to override something without modifying our jar package. It’s quite simple, just add yml file to the same folder than jar. I will demonstrate it with profile. First, let's modify classpath . I would like to keep it simple, so I cleaned it up and added only the param1 value. local-dev application-local-dev.yml #application-local-dev.yml app: param1: local-dev-param1 And our external yml (the file that I added to the same level as jar or out of the source directory, into the runtime directory) local-dev #external application-local-dev.yml app: param1: local-dev-param1-override Let's run the application now. The following profiles are active: local-dev Active profiles: local-dev Properties: Properties(param1=local-dev-param1-override) Everything is the way we expected and like spring documentation stated. External yml file property will override the same property in classpath file. Let's restore the include part in classpath yml. #application-local-dev.yml spring: profiles: include: dev, local-db,local-mock app: param1: local-dev-param1 And now the output is follows: The following profiles are active: local-dev,dev,local-db,local-mock Active profiles: local-dev,dev,local-db,local-mock Properties: Properties(param1=dev-param1) We can see now that param1 is holding the value . This might seem confusing, but it is logical if we see the list of active profiles. Even though the property was overridden in external yml file, the profile precedence is -> -> -> . It means that is more important than and because of that it overrides external property. dev-param1 local-dev local-dev dev local-db local-mock dev local-dev Let's try to override spring profiles include. As I stated before, it might be that we cannot change jar file. So, we might want to change properties with an external yml file. I added include property with some overridden profiles to yml #external application-local-dev.yml spring: profiles: include: nodev,local-mock,local-db app: param1: local-dev-param1-override First, I changed to profile. Secondly, I swapped and . Lets see our output dev nodev local-mock local-db The following profiles are active: local-dev,dev,local-db,local-mock,nodev Active profiles: local-dev,dev,local-db,local-mock,nodev Properties: Properties(param1=dev-param1) Now it's interesting. First it seems that cannot be overridden. Active profiles are still -> -> -> . It is clear that this order is the same as in classpath. But then there is profile as our last and most relevant profile. It seems that we can add new profiles with include . This is important to know. Nothing hints that should be with highest priority and it is easy to make mistakes with overridden properties. Although I wanted to declare that must be lower than or , then in reality it got higher precedence. spring.profiles.include local-dev dev local-db local-mock nodev but we can't change the already declared profiles nodev nodev local-db local-mock It might very well be that the person who must run the application and is responsible for overriding profiles with a external config might not know all the profiles, or the developer changes profiles in classpath without notice. Such misconfiguration might mess up the properties values and it might be very hard to in the end to debug errors in production. Conclusion As we could see, using spring-boot profiles is a very useful way to mitigate different properties values in different environments. Adding all the possible ways to override properties will give us an extremely dynamic tool to change their values. But it can get very messy quite easily. Because of this, I think that overriding properties should be avoided or used as little as possible. Try to arrange profiles so that new profiles introduce new properties but do not override them. Some recommendations that might help you as they helped me: Do not use in . As we could see, property is merged not overridden. And is always used in property value resolving algorithm. spring.profiles.include application.yml include application.yml You can use in . This can be easily overridden by system property. But do not use it in other profiles. spring.profiles.active application.yml Try to minimize overriding properties with profile specific yml files. Introduce new properties instead with profile specific yml files. For example, do not override database properties but introduce them in specific ...-db profiles. So, you can include only a specific profile for environment. For example, include profile for production and for development. This way you can avoid wrong values in wrong environment. prod-db dev-db Always keep an eye on your log output. Spring log output gives you a hint about active profiles and their precedence. Powerful tools deserve respect!