🍃 Properties ↔ YAML

Convert Spring Boot config both ways — lists, profile blocks and escapes included, without corrupting your version numbers.

INPUT · .properties
OUTPUT · YAML
🍃

Paste .properties on the left

Lists · profile blocks · escapes · 100% private

application.properties and application.yml

Spring reads both, and every team eventually moves from one to the other — usually to YAML, for the nesting, and occasionally back, because a flat file diffs better and cannot be broken by an indentation mistake. The conversion looks trivial and is not, because the two formats do not describe the same set of documents.

A flat file has no structure

server.port=8080 has no more structure than serverport=8080 does; the dots are a convention Spring's relaxed binder interprets, not syntax. Turning that into YAML means inventing a tree, and there is exactly one case where that is impossible: a key that is both a value and a prefix. app=1 alongside app.name=x is legal .properties with no YAML form at all, and it is reported rather than silently resolved.

Types are where configs get corrupted

Everything in .properties is a string; YAML has real scalars. So port=8080 should become a number — but version=1.10 must not, because as a number it is 1.1. Nor should enabled=on become true: YAML 1.1 says it is a boolean and Spring does not. Values are only converted when the text survives the round trip unchanged.

Profile blocks

Spring Boot 2.4 introduced #--- as the profile separator inside a .properties file, matching YAML's ---. Ignoring it merges every profile into one map, which looks right and lets the last block win — putting prod settings into dev. Each block is kept as its own document in both directions.

Frequently asked

Why did my version number stay quoted?

Because 1.10 as a YAML number is 1.1, and a version that changes value between two config files is corruption nobody goes looking for. Anything whose text does not survive a round trip through a number — 1.10, 007, 1e5 — is kept as a string.

Why is enabled=on still a string?

YAML 1.1 reads on, off, yes and no as booleans. Spring does not. Converting them would change what your application actually sees, so they stay strings.

What does the #--- separator do?

It is Spring Boot 2.4+'s profile-document separator inside a .properties file, and the equivalent of --- in YAML. A converter that ignores it collapses every profile block into one map, which looks correct and lets the prod block silently overwrite dev. Each block becomes its own YAML document here, and back again.

What is a "both a value and a prefix" warning?

app=1 and app.name=x together are legal in .properties and have no YAML form at all — a key cannot be a string and a map at once. Rather than silently pick one, the conflict is reported so you can decide which one you meant.

Are comments preserved?

No. Comments have no representation in the parsed structure, so they are dropped on the way through. This is the one thing to re-add by hand after converting a file you intend to keep.

application.properties and application.yml: converting without corrupting the config

Spring Boot reads configuration from both `application.properties` and `application.yml`, and most teams eventually move from one to the other — usually towards YAML for the nesting and the profile documents, and occasionally back, because a flat file diffs cleanly in review and cannot be broken by an indentation mistake. The conversion looks like a formatting change. It is not, because the two formats do not describe the same set of documents.

A `.properties` file is a flat map of strings. `server.port=8080` has no more structure than `serverport=8080` does; the dots are a naming convention that Spring's relaxed binder interprets, not syntax. Converting it to YAML therefore means inventing a tree, and inventing a tree can fail: a key that is both a value and a prefix — `app=1` alongside `app.name=x` — is perfectly legal properties with no YAML form at all. Silently resolving that drops a configuration value, and it will be the one that only exists in the environment you did not test.

The other half of the problem is types. Properties values are always strings; YAML has real scalars. `port=8080` genuinely should become the number 8080, but `version=1.10` must not, because as a number it is 1.1 — a version string that changes value between two config files is corruption nobody goes looking for. This converter's scalar rules are deliberately narrower than YAML's own, and where it declines to convert something it is because converting would have changed what your application sees.

Both directions are supported with the same care: properties to YAML with a choice of two- or four-space indentation and an option to keep every value a string, and YAML back to properties with optional alphabetical key sorting. Everything runs in the browser tab, which matters for a file whose whole job is to hold datasource URLs and credential placeholders.

How it works

Reading a properties line starts with finding the separator, which is the first unescaped `=`, `:` or run of whitespace — whichever comes first. That single rule is why `spring.datasource.url=jdbc:postgresql://db:5432/app` splits on the equals sign and keeps every colon in the value, while `key value` and `key : value` are both read correctly. Escapes are then expanded: `\n`, `\t`, `\r`, `\f` and `\uXXXX` become real characters, and a backslash before anything else simply drops away, which is how a key containing a literal colon is written.

Line continuations are counted rather than detected. A trailing backslash continues onto the next line only when the number of backslashes is odd — so `path=C:\\` is a Windows path ending in an escaped backslash, not a continuation, and the following line stays its own key. Getting this wrong is the difference between reading a path correctly and swallowing the next entry into it.

Keys are then split on dots into a tree, with `name[0]` segments building arrays in index order regardless of the order the lines appeared in. A gap in the indices is reported rather than closed up, because Spring stops binding a list at the first hole — `a[0]` and `a[2]` means the third element is simply never read, and quietly renumbering it would hide that. A key that is both a leaf and a prefix is detected in either order and reported as a conflict, with everything that was not in conflict still converted.

Scalar coercion only converts a value when the conversion is reversible. `true`, `false` and `null` become their YAML equivalents; a number becomes a number only when passing the text through JavaScript's `Number` and back produces the identical string, which is what rules out `1.10`, `007` and `1e5`. `on`, `off`, `yes` and `no` are left as quoted strings on purpose: YAML 1.1 reads them as booleans and Spring does not, so converting them would change the running application's behaviour. The "Keep as strings" switch disables coercion entirely.

Profile blocks are treated as first-class in both directions. Spring Boot 2.4 introduced `#---` as the profile separator inside a properties file, matching YAML's `---` document separator. Each block becomes its own YAML document going one way and is rejoined with `#---` coming back, with a warning that older Boot versions do not understand that separator. A converter that ignores this merges every profile into one map, which looks correct and lets the prod block silently overwrite dev.

Common uses

  • Migrate an existing `application.properties` to `application.yml` when adopting profile documents or nested `@ConfigurationProperties` binding.
  • Convert a YAML config back to flat properties for a file that has become hard to review, since a flat file diffs line by line and has no indentation to get wrong.
  • Translate a snippet from a Stack Overflow answer or a library's README that is written in the format your project does not use.
  • Flatten a YAML config to see the exact dotted key names to set as environment variables or `--spring.datasource.url=...` command-line overrides.
  • Split a properties file that has accumulated several `#---` profile blocks into readable per-profile YAML documents.
  • Audit a config for accidental type coercion by converting it and reading the warnings — a version, a branch code, or an `enabled=on` that another tool would have silently changed.

Before you rely on the result

  • Comments are not preserved in either direction. They have no representation in the parsed structure, so re-add them by hand on any file you intend to keep.
  • Read every "both a value and a prefix" warning before shipping the output. That conflict has no YAML expression, so one of the two keys was dropped, and only you know which one was meant.
  • A warning about a missing list index is not cosmetic. Spring stops binding a list at the first gap, so anything after the hole is not read at runtime whichever format you use.
  • Check any value that looks like a version, a zero-padded code or a numeric identifier. They are kept quoted here on purpose, and re-quoting them by hand is required if you later edit the YAML.
  • An empty list or an empty map has no properties spelling. They are written as an empty value with a warning, and Spring reads `a=` as an empty string rather than as an empty collection.
  • YAML whose top level is a list or a scalar is rejected rather than flattened — a Spring configuration document has to be a map, and a flat form for the alternatives would not mean anything.
  • The `#---` separator this tool writes between profile blocks is Spring Boot 2.4 and later. On an older Boot version those lines are ordinary comments and every block collapses into one file.
  • Diff the converted file against the original before committing rather than trusting the round trip. The conversion is faithful for the shapes it handles, but the file being converted is usually the one that decides which database production talks to.