Why Does Spring Boot H2 Console Return 404 with WebFlux?
Problem
When I configured the H2 console in my Spring Boot application, I got a 404 error trying to access it:
Whitelabel Error PageThis application has no explicit mapping for /error, so you are seeing this as a fallback.
There was an unexpected error (type=Not Found, status=404).My application.yml looked correct:
spring: h2: console: enabled: true path: /h2 settings: web-allow-others: trueBut when I opened http://localhost:8080/h2, the console just returned 404.
Environment
- Spring Boot 3.x
- Spring WebFlux (spring-boot-starter-webflux)
- H2 Database 2.x
- Embedded server: Netty
What happened?
I was building a reactive application using Spring WebFlux. I added H2 as my development database and configured the console properties in application.yml.
My pom.xml dependency:
<dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope></dependency>When I started the application, I noticed this in the logs:
Netty started on port(s): 8080Started Application in 2.5 secondsThe key detail here: Netty started, not Tomcat. This indicates a reactive/WebFlux stack.
I assumed spring.h2.console.enabled=true would work, but when I accessed /h2, I got 404.
How to solve it?
I first tried adding more configuration options:
spring: h2: console: enabled: true path: /h2 settings: web-allow-others: true datasource: url: jdbc:h2:mem:testdb driverClassName: org.h2.DriverStill 404. I then searched Stack Overflow and found the root cause.
The solution is to manually configure an H2 server using org.h2.tools.Server:
package com.example.config;
import org.h2.tools.Server;import org.springframework.beans.factory.annotation.Value;import org.springframework.context.event.ContextClosedEvent;import org.springframework.context.event.ContextRefreshedEvent;import org.springframework.context.event.EventListener;import org.springframework.stereotype.Component;
import java.sql.SQLException;
@Componentpublic class H2ServerManual {
private Server webServer;
@Value("${h2-server.port:8081}") Integer h2ConsolePort;
@EventListener(ContextRefreshedEvent.class) public void start() throws SQLException { this.webServer = Server.createWebServer( "-webPort", h2ConsolePort.toString(), "-tcpAllowOthers" ).start(); System.out.println("H2 Console available at: " + webServer.getURL()); }
@EventListener(ContextClosedEvent.class) public void stop() { if (this.webServer != null) { this.webServer.stop(); } }}And update application.yml:
h2-server: port: 8081
spring: datasource: url: jdbc:h2:mem:testdb driverClassName: org.h2.Driver username: sa password:
server: port: 8080I also needed to remove the runtime scope from H2 dependency:
<dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <!-- No scope specified = compile scope, allows Server class --></dependency>Now when I start the application:
Netty started on port(s): 8080H2 Console available at: http://localhost:8081Started Application in 2.8 secondsI can access the H2 console at http://localhost:8081 (not port 8080).
The reason
The key reason for the 404 error is that Spring Boot’s H2ConsoleAutoConfiguration only executes for servlet-based applications.
Here’s the difference:
┌─────────────────────────────────────────────────────────────────┐│ Servlet Stack (Tomcat) │├─────────────────────────────────────────────────────────────────┤│ spring.h2.console.enabled=true ││ ↓ ││ H2ConsoleAutoConfiguration executes ││ ↓ ││ Servlet container (Tomcat) registers /h2 endpoint ││ ↓ ││ H2 console accessible at /h2 │└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐│ Reactive Stack (Netty) │├─────────────────────────────────────────────────────────────────┤│ spring.h2.console.enabled=true ││ ↓ ││ H2ConsoleAutoConfiguration SKIPPED (requires servlet) ││ ↓ ││ No /h2 endpoint registered ││ ↓ ││ 404 when accessing /h2 │└─────────────────────────────────────────────────────────────────┘When you use spring-boot-starter-webflux, the embedded server is Netty, not Tomcat. Netty is a reactive, non-blocking server that doesn’t support servlets. The H2 console servlet cannot be registered, so the auto-configuration is skipped.
Common mistakes I made:
- Assuming properties work universally -
spring.h2.console.enabledonly works with servlet stacks - Using runtime scope for H2 - This prevents using the
Serverclass for manual configuration - Not checking logs - The “Netty started” message was the key clue
Summary
In this post, I explained why the H2 console returns 404 in Spring Boot WebFlux applications. The key point is that H2 console auto-configuration requires a servlet environment, which Netty doesn’t provide. For reactive applications, manually configure the H2 server using org.h2.tools.Server with Spring event listeners.
Final Words + More Resources
My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me
Here are also the most important links from this article along with some further resources that will help you in this scope:
- 👨💻 Stack Overflow: Spring boot H2 console returns 404
- 👨💻 Spring Boot H2 Console Documentation
- 👨💻 H2 Database Engine Documentation
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!
Comments