application.properties vs application.yml in Spring Boot
Introduction
This tutorial compares the two formats Spring Boot accepts for its configuration file -application.properties and application.yml. We will start with where Spring Boot looks for these files, then write the same configuration in both formats and load each one in a real application. We will then see what happens when both files exist, how lists and maps are written in each format, and the YAML pitfall that turns the country code NO into false. Next we will override values from outside the application, with environment variables and command-line arguments, and look at relaxed binding, which lets one property be written in several forms. Lastly, we will see the full order of precedence and decide which format to use.(This tutorial uses
@Value and ${...} placeholders from SpEL and @ValueClick to read tutorial: Spring Expression Language (SpEL) and @Value Explained; the next tutorial binds whole groups of properties with @ConfigurationPropertiesClick to read tutorial: Type-Safe Configuration with @ConfigurationProperties.)
Where Spring Boot looks for configuration files
At startup, Spring Boot looks for a file namedapplication.properties or application.yml (or .yaml) in these places, and loads every one it finds -
- the root of the classpath - in a Maven project,
src/main/resources, so the file is packaged inside the jar; - a
configpackage on the classpath; - the current directory, where the application is started;
- a
config/sub-directory of the current directory, and its immediate sub-directories.
application.properties next to the jar to change them. The base name can be changed with spring.config.name, and extra files can be added with spring.config.location or spring.config.import. The examples below use spring.config.name so that each one can load its own file.
The same settings in both formats
Here are the settings of an online bookshop - a name, a page size, a list of currencies, nested contact details, and a map of delivery days per country - first as a.properties file -
shop-props.properties - the settings in .properties format
# Shop settings in .properties format: one key=value pair per line
shop.name=JavaBrahman Books
shop.page-size=20
shop.currencies=USD,EUR,INR
shop.contact.email=orders@example.com
shop.contact.phone=+44 20 7946 0000
shop.delivery-days.GB=2
shop.delivery-days.IN=5
shop.delivery-days.US=4
shop-yaml.yml - the same settings in YAML format
# Shop settings in YAML format: nesting by indentation
shop:
name: JavaBrahman Books
page-size: 20
currencies:
- USD
- EUR
- INR
contact:
email: orders@example.com
phone: "+44 20 7946 0000"
delivery-days:
GB: 2
IN: 5
US: 4
Environment, and uses Spring Boot's Binder to read the list and the map as Java collections -
A Spring Boot application that prints the shop settings it loaded
//ConfigPrinter.java
package com.javabrahman.boot.config;
import java.util.List;
import java.util.Map;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.core.env.Environment;
@SpringBootApplication
public class ConfigPrinter {
public static void main(String[] args) {
try (var context = SpringApplication.run(ConfigPrinter.class, args)) {
Environment env = context.getEnvironment();
Binder binder = Binder.get(env);
print("shop.name", env.getProperty("shop.name"));
print("shop.page-size", env.getProperty("shop.page-size", Integer.class));
print("shop.currencies", binder.bind("shop.currencies", Bindable.listOf(String.class)).orElse(null));
print("shop.contact.email", env.getProperty("shop.contact.email"));
print("shop.contact.phone", env.getProperty("shop.contact.phone"));
print("shop.delivery-days", binder.bind("shop.delivery-days", Bindable.mapOf(String.class, Integer.class)).orElse(null));
print("shop.countries", binder.bind("shop.countries", Bindable.listOf(String.class)).orElse(null));
print("shop.countries-quoted", binder.bind("shop.countries-quoted", Bindable.listOf(String.class)).orElse(null));
}
}
static void print(String key, Object value) {
if (value != null) { // print only the keys the loaded file sets
System.out.printf("%-22s = %s%n", key, value instanceof Map<?, ?> || value instanceof List<?> ? value : "'" + value + "'");
}
}
}
.properties file, then the YAML file -
OUTPUT with --spring.config.name=shop-propsshop.name = 'JavaBrahman Books'
shop.page-size = '20'
shop.currencies = [USD, EUR, INR]
shop.contact.email = 'orders@example.com'
shop.contact.phone = '+44 20 7946 0000'
shop.delivery-days = {GB=2, IN=5, US=4}
shop.name = 'JavaBrahman Books'
shop.page-size = '20'
shop.currencies = [USD, EUR, INR]
shop.contact.email = 'orders@example.com'
shop.contact.phone = '+44 20 7946 0000'
shop.delivery-days = {GB=2, IN=5, US=4}
Explanation of the code
- Both files produced exactly the same settings. Spring Boot turns both formats into the same flat property names, such as
shop.contact.email; the application code never knows which format was used. - In
.properties, nesting is written with dots in every key. In YAML, it is written once, by indentation, so related settings are grouped visually and theshop.prefix is not repeated. - The comma-separated
shop.currencies=USD,EUR,INRand the YAML list with-items both bound to aListof three strings. - The
delivery-dayskeys became the keys of aMap, and their values were converted toInteger. - The phone number is quoted in YAML. Unquoted, a value starting with
+and containing spaces is still read as a string, but quoting values with special characters avoids surprises - as the next section but one shows.
When both files exist
If the same location holds both a.properties and a .yml file with the same name, Spring Boot loads both, and for a key that appears in both, the .properties value wins -
both.properties
shop.name=Name from both.properties
both.yml
shop:
name: Name from both.yml
page-size: 50
shop.name = 'Name from both.properties' shop.page-size = '50'
both.properties, while page-size, which only the YAML file sets, still came from both.yml: the files are merged key by key. This works, but it is confusing to maintain - keep one format per project.
The YAML pitfall: the Norway problem
YAML has an inconvenient rule inherited from version 1.1 of the YAML specification, which the SnakeYAML library that Spring Boot uses follows: the unquoted wordsyes, no, on and off, in any capitalisation, are booleans. That includes NO, the country code of Norway -
norway.yml - a list of country codes, unquoted and quoted
shop:
countries: [GB, NO, IN]
countries-quoted: ["GB", "NO", "IN"]
shop.countries = [GB, false, IN] shop.countries-quoted = [GB, NO, IN]
Explanation of the output
- In the unquoted list, YAML read
NOas the booleanfalse, which Spring then converted to the string"false"- Norway silently disappeared from the list. No error, no warning. - With quotes,
"NO"stayed a string. - The same rule hits values such as
on/offswitches, version numbers like1.10(read as the number1.1), and strings with leading zeros. Quote any YAML value that is not obviously a word or a plain number. In a.propertiesfile, every value is a string until Spring converts it, so this problem does not exist.
[GB, NO, IN] is YAML's inline "flow" style; it means the same as the indented list with - items used earlier.
Overriding settings from outside the application
A packaged application usually needs different settings in each environment. Spring Boot reads properties from several property sources besides the configuration files, and the outer sources win. The two most common are environment variables and command-line arguments. The run below starts the application with the.properties file, two environment variables and one command-line argument -
set SHOP_NAME=Name from an environment variable set SHOP_PAGESIZE=40 java -jar shop.jar --spring.config.name=shop-props --shop.name="Name from the command line"
shop.name = 'Name from the command line'
shop.page-size = '40'
shop.currencies = [USD, EUR, INR]
shop.contact.email = 'orders@example.com'
shop.contact.phone = '+44 20 7946 0000'
shop.delivery-days = {GB=2, IN=5, US=4}
Explanation of the output
shop.namewas set in three places - the file, theSHOP_NAMEenvironment variable and the command line - and the command-line argument won.shop.page-sizewas set in the file (20) and by theSHOP_PAGESIZEenvironment variable (40), and the environment variable won.- Everything else still came from the file.
- Command-line arguments are the
--name=valueoptions after the class or jar name; Spring Boot turns them into properties.
Relaxed binding
Environment variables cannot contain dots or dashes on most systems, so how didSHOP_PAGESIZE set shop.page-size? Spring Boot applies relaxed binding: it accepts several spellings of the same property name -
shop.page-size- kebab case, the recommended form in.propertiesand.ymlfiles;shop.pageSizeandshop.page_size- camel case and underscore notation, also accepted in files;SHOP_PAGESIZE- the environment-variable form: upper case, dots replaced by underscores, and dashes removed. List items use the index as a segment, as inSHOP_CURRENCIES_0_=USD.
SERVER_PORT=9090 changes server.port, and SPRING_PROFILES_ACTIVE=prod activates a profile. In code, always refer to the canonical kebab-case name, for example @Value("${shop.page-size}").
The order of precedence
Spring Boot's property sources form a list, and a value from a source higher in the list overrides the same key lower down. Simplified, from highest to lowest -- Properties set by tests, such as
@SpringBootTest(properties = ...)and@TestPropertySource. - Command-line arguments.
- The JSON in
SPRING_APPLICATION_JSON, and servlet parameters in web applications. - JVM system properties (
-Dname=value). - Operating-system environment variables.
- Configuration files: profile-specific files (such as
application-prod.yml) above plain ones, and files outside the jar above files inside it. @PropertySourceannotations on configuration classes, and defaults set withSpringApplication.setDefaultProperties().
Which format should you use?
- YAML is more readable for deep, structured configuration - many nested settings, lists of objects, several profiles in one file (separated by
---). Its cost is whitespace sensitivity and the type-guessing pitfalls above. - .properties is flat and unambiguous: every line stands alone, values are never reinterpreted, and a key can be searched for as one string. It is easy to edit with scripts and hard to break.
- Both support the same features - placeholders, lists, maps, multiple documents in one file (
.propertiesuses a#---line as the separator) and profile-specific variants. - Pick one per project and stick to it. Spring Initializr generates
application.properties; renaming it toapplication.ymland converting the contents is all it takes to switch.
Summary
In this tutorial we first saw where Spring Boot looks forapplication.properties and application.yml. We wrote the same settings in both formats and loaded each with a real application, getting identical results, including a list and a map. We then saw that when both files exist they are merged and .properties wins, and watched YAML turn Norway's country code into false. Next we overrode the file with an environment variable and a command-line argument, explained relaxed binding, and listed the order of precedence of property sources. Lastly, we compared the two formats. The next tutorial binds these settings to a typed Java object: type-safe configuration with @ConfigurationPropertiesClick to read tutorial: Type-Safe Configuration with @ConfigurationProperties.Spring Boot Tutorials
Spring Boot Starters Explained with ExamplesClick to read tutorial: Spring Boot Starters Explained with Examples Type-Safe Configuration with @ConfigurationPropertiesClick to read tutorial: Type-Safe Configuration with @ConfigurationProperties Your First Spring Boot Application with Spring InitializrClick to read tutorial: Your First Spring Boot Application with Spring Initializr How Spring Boot Auto-Configuration WorksClick to read tutorial: How Spring Boot Auto-Configuration Works Spring Boot Profiles and Environment-Specific ConfigurationClick to read tutorial: Spring Boot Profiles and Environment-Specific Configuration Logging in Spring Boot: SLF4J, Logback and Log LevelsClick to read tutorial: Logging in Spring Boot: SLF4J, Logback and Log Levels Spring Boot DevTools: Automatic Restart and ProductivityClick to read tutorial: Spring Boot DevTools: Automatic Restart and Productivity
Spring Boot Starters Explained with ExamplesClick to read tutorial: Spring Boot Starters Explained with Examples Type-Safe Configuration with @ConfigurationPropertiesClick to read tutorial: Type-Safe Configuration with @ConfigurationProperties Your First Spring Boot Application with Spring InitializrClick to read tutorial: Your First Spring Boot Application with Spring Initializr How Spring Boot Auto-Configuration WorksClick to read tutorial: How Spring Boot Auto-Configuration Works Spring Boot Profiles and Environment-Specific ConfigurationClick to read tutorial: Spring Boot Profiles and Environment-Specific Configuration Logging in Spring Boot: SLF4J, Logback and Log LevelsClick to read tutorial: Logging in Spring Boot: SLF4J, Logback and Log Levels Spring Boot DevTools: Automatic Restart and ProductivityClick to read tutorial: Spring Boot DevTools: Automatic Restart and Productivity