1. Purpose of condition evaluation delta
When DevTools is enabled, you start living in a “fix → save → look at the result” mode. That is great as long as everything is obvious. But as soon as you change something infrastructural, such as a bean, a profile, or a config, the restart happens quickly, while understanding the cause of the behavior change is slow. Condition evaluation delta is Spring Boot’s attempt to give you a “git diff”, but not for files — for auto-configuration decisions: what was considered a match before the restart and what became a match after it.
To feel the problem, imagine a typical situation: you added a tiny @Bean, and after the restart Boot’s default behavior suddenly “disappeared somewhere.” The logs are huge, you scroll through them, find a bunch of lines about Tomcat, MVC, JSON, and still do not see an explanation. The delta makes this story human: it does not retell the whole startup, but shows only the changes in conditional matches between two states.
It is important to understand a subtle point: the delta is not about “which beans were created” (although you often see the consequence there indirectly), but about which conditions became true/false and why Boot enabled or disabled a piece of auto-configuration. In other words, this is a tool not so much for speed as for understanding.
2. What DevTools compares
To keep the delta from looking like yet another mysterious wall of text, it helps to keep a simple model in mind. Boot has a set of auto-configuration classes, and each such class is like a “settings package” that turns on only if certain conditions are met. There are several kinds of conditions, but in practice you will most often encounter three: checking for a class on the classpath, checking for a bean in the ApplicationContext, and checking a property value. From these conditions, Boot builds the answer to the question: “Do we enable this or not?”
Inside Boot there is a summary that neatly records which auto-configuration matched, which did not, and why. This summary is usually called the Condition Evaluation Report — in essence, it is a report of how the conditions behaved. DevTools takes the “before” report, takes the “after” report, and prints the difference — the delta. This is exactly a diff: what was present in the previous state, what disappeared, and what appeared in the new one.
This can be visualized like this:
flowchart TD
A[You change code/config] --> B[DevTools performs a restart]
B --> C[Boot collects the Condition Evaluation Report]
C --> D[DevTools compares: previous report vs new report]
D --> E[CONDITIONS EVALUATION DELTA appears in the logs]
E --> F[You understand which condition changed and why]
And here there is an immediately useful engineering thought: the delta does not answer the question “what broke”, but rather “which Boot decision changed”. Sometimes that is even more important than errors, because an error is an event, while a change in decision is the cause.
3. Enabling and finding the delta in the logs
The delta has one very practical feature: it appears after a restart, not “every second”. So if you change static HTML and get a reload, you will not see any delta — because auto-configuration conditions were not recalculated and the context was not recreated. The delta is a restart story and only a restart story. That is why it depends exactly on the changes that actually affect the ApplicationContext and its creation.
In the logs, the delta is usually highlighted by a very noticeable heading. In real life you will look for a block roughly like this (the format may differ, but the meaning is the same):
============================
CONDITIONS EVALUATION DELTA
============================
If the delta starts to annoy you (for example, you are making lots of small edits and do not want to keep seeing this block), you can disable it with a DevTools setting. The cleanest option is to keep this in a local profile, so the project’s shared configuration does not turn into a developer convenience dump:
# src/main/resources/application-local.yaml
spring:
devtools:
restart:
log-condition-evaluation-delta: false
If you want to turn it back on, just set true or remove the key — and you are back to the default behavior. The main thing is not to turn this property into a religion. The delta is a useful spotlight, but sometimes it shines straight into your eyes.
4. Reading the delta: what changed and why
Reading the delta as “just another startup log” is almost guaranteed to be pointless. The working approach is different: first you define what exactly you changed, and then in the delta you look for the type of conditions that should have reacted. If you added @Bean, it is logical to expect changes in conditions like @ConditionalOnMissingBean. If you switched the profile, it is logical to expect property conditions or simply the presence of your configuration classes to change. If you changed only business logic in a service, the delta may be empty — and that is normal.
It is useful to keep this mini-table in mind: “change → what usually moves in the delta”:
| What you changed | What usually changes in the delta | What conclusion you can draw |
|---|---|---|
| Added @Bean to the project | @ConditionalOnMissingBean stopped matching in the auto-config | Boot backed off and took your setup instead of the default |
| Removed your @Bean | The auto-config did not match before, now it matches | Boot returned to the defaults |
| Switched the profile (local → dev) | Conditions tied to properties or the profile changed outcome | The profile was actually activated, or not, rather than “seemingly” |
| Changed a YAML property that affects conditions | @ConditionalOnProperty changed its match | The property is actually read and has the expected value |
Another important point: a delta does not necessarily mean “bad.” It may contain Negative matches, and that is not an error at all. It is often just a statement of fact: “previously the condition was true, and now it is false because you added a bean.” In a healthy Boot project, this happens all the time, and it is a normal part of controlled customization.
5. Scenario: you added your own bean — Boot “backed off”
The most classic case where the delta really saves time: you added your own infrastructural bean, intentionally or by accident, and part of the auto-configuration stopped being applied because Boot works on the principle of “if you configured it explicitly, I will not interfere.” That is the backoff model we discussed earlier. The problem is that without the delta, you sometimes do not understand which exact default Boot stopped applying and why.
Let us take catalog-service and run a deliberately educational experiment: temporarily add your own ObjectMapper (or, more precisely, JsonMapper, which is a descendant of ObjectMapper) to see the backoff model in the delta. A quick warning in the spirit of “so it does not hurt later”: you should not keep such an override as a permanent local setting. What matters here is not the mapper itself, but how the delta shows Boot’s decision changing.
Let us add a configuration active only in the local profile so the experiment stays controlled:
package com.example.catalogservice.support.jackson;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.json.JsonMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
@Configuration // Picked up by component scan: this is a regular Spring configuration
@Profile("local") // Enable this configuration only in the local profile so the experiment does not leak further
public class LocalJacksonConfiguration {
@Bean // Create our own ObjectMapper: this makes Boot "back off" from the default JacksonAutoConfiguration
public ObjectMapper objectMapper() {
// Custom mapper to see the effect of the backoff model in the delta
return JsonMapper.builder()
.findAndAddModules() // Automatically connect modules (for example, JavaTimeModule for java.time.*)
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) // Dates will be serialized in a more "human" way
.build(); // Build the final ObjectMapper
}
}
Pay attention to two things. First, the class is located inside the application’s root package (com.example.catalogservice...), so it will be included in component scan. Second, @Profile("local") makes this bean “switchable”: it exists in local, but not in dev and prod.
After you save the file, DevTools will perform a restart (because this is a Java code change), and in the logs you will see the delta. In an educational form, it may look like this:
============================
CONDITIONS EVALUATION DELTA
============================
Negative matches:
----------------
JacksonAutoConfiguration:
Did not match:
- @ConditionalOnMissingBean (types: com.fasterxml.jackson.databind.ObjectMapper)
found bean 'objectMapper' (OnBeanCondition)
The meaning is literal: “JacksonAutoConfiguration no longer fits because the @ConditionalOnMissingBean(ObjectMapper) condition is not satisfied — the objectMapper bean already exists.” And that is exactly the educational effect we wanted: Boot honestly tells you why it does not create its own default ObjectMapper.
There is also a very real-world takeaway. If you ever add an ObjectMapper and suddenly your date format or enum serialization changes, the delta often gives the first explanation of where the lever switched. And yes, this is the kind of case where one small configuration can change the behavior of the entire JSON layer. So the backoff model is a powerful tool, but the responsibility is also real. As soon as you see this effect, it is better to remove LocalJacksonConfiguration so the local profile can go back to using Boot’s normal JSON configuration.
6. Scenario: switching profiles
Profiles in Boot are wonderful, but tricky. Wonderful because they let you keep local conveniences separate. Tricky because sometimes you think local is active, but in reality default started, and you spend half an hour arguing with the monitor about why “the setting does not work.” Condition evaluation delta in such cases is almost like a witness: it shows what was enabled and what was disabled, precisely because the conditions changed.
Let us continue with our LocalJacksonConfiguration example. In the local profile, the objectMapper bean exists, and Boot backs off from its JacksonAutoConfiguration. As soon as you leave local or simply remove this temporary bean, on the next restart the delta should show the opposite picture: the auto-configuration matches again because missing bean is true again.
From a logic perspective, it looks like this: in the dev profile, your ObjectMapper does not exist → the @ConditionalOnMissingBean(ObjectMapper) condition is satisfied again → Boot enables its auto-configuration again.
A hypothetical delta fragment may look like this:
============================
CONDITIONS EVALUATION DELTA
============================
Positive matches:
----------------
JacksonAutoConfiguration:
Matched:
- @ConditionalOnMissingBean (types: com.fasterxml.jackson.databind.ObjectMapper)
did not find any beans (OnBeanCondition)
Now the delta becomes a very concrete signal: “in this run, Boot again considers ObjectMapper absent, so it will create the default one.” And this is useful not only for Jackson. You can use it to trace profile-driven changes in MVC settings, in conditional enabled/no-op beans, and anywhere behavior depends on the environment.
And again, an important nuance: the delta does not replace your understanding of profiles, but it greatly shortens the path from “it seems like the wrong profile” to “yes, it really is the wrong profile.” In learning, that saves nerves; in work, it saves hours. And after such a check, it is better to remove the temporary override so local does not carry extra JSON customization around.
7. Delta and framework takeover in MVC
Sometimes students, and honestly not only students, accidentally stage a small coup against a Spring Boot project. The most common scenario is that someone adds too “strong” an MVC customization, and Boot starts disabling part of its defaults. In the course we deliberately keep the boundary: we customize MVC through WebMvcConfigurer, but we do not enable @EnableWebMvc, because that often turns into framework takeover. And the delta is one of the tools that helps you see this takeover not by symptoms (“why did static resources stop working?”), but by cause (“why did auto-configuration get disabled?”).
Even if you do not plan such experiments, it is useful to understand the principle. The WebMvcAutoConfiguration class usually has a condition like: “enable yourself if nobody brought their own full MVC configuration.” When you bring in too heavy a setup, Boot sees it and backs off. In such cases the delta often shows a sharp move: a big auto-configuration moved into negative matches because of OnBeanCondition.
And this is why it matters methodically. When you see in the delta that an entire layer of auto-configuration stopped matching, that is almost always a reason to stop and ask yourself: “Did I really want to disable Boot’s defaults, or did I just want to add a small formatter or converter?” In our course, the correct answer is usually the second one. And the delta helps catch the moment when you accidentally did the first.
8. Discipline in reading the delta
The delta is informative, but it can be talkative, especially if your changes affected many auto-configuration classes. At such moments it is easy to fall into reading the log like a novel: “Positive matches… Negative matches…” and five minutes later you realize you understood nothing, but are very tired. For the delta to work for you, not against you, it needs discipline.
The first technique is not to read the delta top to bottom, but to look for familiar words. In most cases you already know the area of change: JSON, MVC, profiles, some of your @Configuration classes. So you look in the delta for corresponding auto-configuration names or condition types. The second technique is to remember that the delta shows the difference between two states. If you do not remember what exactly you did before the restart, the delta will look like magic, because you lost the other half of the diff — the “before”.
The third technique is to allow yourself to disable the delta temporarily when you are working on a task where it does not help. For example, you are editing the pure business logic of course filtering in CourseCatalogService, and every restart is accompanied by a delta that is either empty or irrelevant. Turn it off — do the work — turn it back on. That is not weakness. That is normal tool adjustment to the task, not the task adjustment to the tools.
9. Common mistakes when working with the delta
Mistake #1: reading the delta like an error log and panicking at the word “Negative.”
In the delta, negative matches usually do not mean a problem, but a fact: this auto-configuration is no longer applied because the condition is not satisfied. In Boot this is a normal part of the backoff mechanism. The mistake starts when you treat any negative as a failure and start fixing what is not broken at all.
Mistake #2: trying to understand the delta without fixing what exactly you changed.
The delta is a diff. If you do not remember the “left side” — the previous state — the “right side” turns into a set of mysterious lines. This happens especially often when you made several changes in a row: adjusted YAML, added a bean, switched the profile, and then try to read the delta as if it had one cause. In that mode it does not help.
Mistake #3: expecting the delta to react to every file change.
The delta appears after a restart, not after a reload. If you changed a static resource or something that DevTools updated without recreating the context, the delta is not required to appear. Sometimes students think “the delta does not work,” when in fact there was no restart. That is not a bug — that is the tool’s logic.
Mistake #4: making an “educational” infrastructural override and forgetting that it affects the whole service.
The ObjectMapper example is very illustrative: you added one bean, and your entire JSON layer changed. In this case the delta honestly says “Boot backed off,” but it will not save you from the consequences if you do not understand what exactly you intercepted. That is why any infrastructure override should be done very carefully, or strictly limited by the @Profile("local") profile, so you do not accidentally carry the experiment into a place where it is not needed.
Mistake #5: turning off the delta too early “because there is too much text.”
Yes, the delta can be noisy. But often it becomes understandable after just a couple of deliberate readings. If you disable it at the first discomfort, you lose one of the most convenient bridges between “I changed something” and “Boot made a different decision.” Here it is better not to be heroic, but also not to capitulate: read it on one or two simple cases, and after that it will start working like a hint, not a punishment.
GO TO FULL VERSION