You added a dependency, pressed run, and Spring Boot stopped before Tomcat even started. On Spring Boot 3.x the console shows this block:
***************************
APPLICATION FAILED TO START
***************************
Description:
Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.
Reason: Failed to determine a suitable driver class
Action:
Consider the following:
If you want an embedded database (H2, HSQL or Derby), please put it on the classpath.
If you have database settings to be loaded from a particular profile you may need to activate it (no profiles are currently active).It means auto-configuration decided this application needs a DataSource, then could not build one: no spring.datasource.url was found in any active property source, and no embedded database driver was on the classpath to fall back on. Nothing is wrong with your database server. Spring never tried to connect to it.
Quick fix checklist
- Add
spring.datasource.url,usernameandpasswordtoapplication.propertiesorapplication.ymlinsrc/main/resources. - Make sure the JDBC driver (for example
org.postgresql:postgresql) is a runtime dependency. - If your settings live in
application-dev.yml, activate the profile:spring.profiles.active=devor--spring.profiles.active=dev. - Check the
Action:text: “no profiles are currently active” is a strong hint. - For tests or prototypes, add H2 so Boot can create an embedded database.
- Only if the app truly has no database, remove the JDBC/JPA starter or exclude
DataSourceAutoConfiguration.
Before you start
You need a Spring Boot 3.x project (Java 17+) built with Maven or Gradle, and you should know where src/main/resources lives. It helps to know which starter pulled in JDBC: spring-boot-starter-data-jpa, spring-boot-starter-jdbc and spring-boot-starter-data-jdbc all bring spring-jdbc and the HikariCP pool. Code in this article is written for Spring Boot 3.x.
Why it happens
Spring Boot’s auto-configuration reacts to what is on the classpath. DataSourceAutoConfiguration is guarded by @ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class }), so the moment spring-jdbc arrives (directly or through the JPA starter) Boot assumes you want a connection pool.
From there it takes one of two paths:
- Pooled DataSource. If a pool such as HikariCP is present, Boot binds
spring.datasource.*intoDataSourcePropertiesand builds the pool. To do that it must know the JDBC URL and the driver class. When the URL is missing, it tries to infer an embedded database instead. - Embedded DataSource. If H2, HSQLDB or Derby is on the classpath, Boot can create an in-memory database with a generated URL and no credentials.
When neither path works, DataSourceProperties throws DataSourceBeanCreationException, and a FailureAnalyzer turns that stack trace into the friendly Description: and Action: text. The analyzer also checks the environment: it prints the active profiles, or “no profiles are currently active”, because a forgotten profile is the most common reason a URL that exists in a file was never read.
The Reason: Failed to determine a suitable driver class line is a consequence, not a separate problem. Boot derives the driver from the URL prefix (jdbc:postgresql: means the PostgreSQL driver). No URL, no driver.
Step-by-step walkthrough
Step 1: Reproduce with a minimal project
Create a project with only spring-boot-starter-web and spring-boot-starter-data-jpa, no driver and an empty application.properties. Run it. You get the exact failure above. This proves the cause is configuration, not code: no repository or entity is needed to trigger it, because the decision happens while auto-configuration is evaluated.
Step 2: Read the Description and Action sections
The Description: names the missing piece ('url' attribute). The Action: lists two remedies and the profile state. If it says (the profiles "dev" are currently active) and you still fail, the URL is not in application-dev.* either. If it says no profiles are active, look for a profile-specific file you assumed was loaded.
To see why auto-configuration matched, start with --debug (or debug=true in properties). The condition evaluation report lists DataSourceAutoConfiguration under “Positive matches” with the class conditions it found.
Step 3: Provide the connection settings
For a real database, set the URL and credentials and add the driver:
spring.datasource.url=jdbc:postgresql://localhost:5432/orders
spring.datasource.username=orders_app
spring.datasource.password=${DB_PASSWORD}
spring.jpa.hibernate.ddl-auto=validateThe same in YAML:
spring:
datasource:
url: jdbc:postgresql://localhost:5432/orders
username: orders_app
password: ${DB_PASSWORD}
jpa:
hibernate:
ddl-auto: validate<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>You rarely need spring.datasource.driver-class-name; Boot infers it from the URL. Set it only for drivers Boot does not recognise.
Gotcha
In YAML, indentation is the structure.
datasource:indented under the wrong key, or a tab character, silently produces a different property name such asspring.jpa.datasource.url, and you get the same failure even though the URL is “in the file”.
Step 4: Fix profile and file location problems
If the settings are in application-dev.yml, nothing reads them until dev is active. Choose one way to activate it:
./mvnw spring-boot:run -Dspring-boot.run.profiles=dev
java -jar target/orders.jar --spring.profiles.active=dev
SPRING_PROFILES_ACTIVE=dev ./gradlew bootRunAlso confirm the file is in src/main/resources (not src/main/java or the project root) and is named exactly application.properties or application.yml. An IDE run configuration can carry its own active profiles, so check it too.
Step 5: Decide whether you need a DataSource at all
If the service genuinely has no database (a gateway, a batch client calling HTTP APIs), the clean fix is to remove the starter that pulled in JDBC. If a shared library forces spring-jdbc onto your classpath and you cannot remove it, exclude the auto-configuration:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}If JPA is also present you will then hit missing EntityManagerFactory errors, which is a sign you do need a database after all.
Worked scenario
A team keeps local settings in application-local.yml so that developers can point at Docker Postgres, and production settings come from environment variables. A new developer clones the repository and runs OrdersApplication from the IDE.
Broken setup:
# src/main/resources/application-local.yml
spring:
datasource:
url: jdbc:postgresql://localhost:5432/orders
username: orders
password: ordersapplication.yml contains only server.port: 8081. The failure output ends with “no profiles are currently active”. That single line is the diagnosis: the URL exists, but in a file Boot never loaded because local was not active.
The tempting fix is to copy the datasource block into application.yml. That works locally and then quietly points every other environment at localhost unless they override it. A better fix is to make activation explicit for local runs and keep the base file free of environment-specific URLs:
# src/main/resources/application.yml
server:
port: 8081
spring:
datasource:
url: ${DATABASE_URL:}The developer then runs with SPRING_PROFILES_ACTIVE=local, which the team documents in the README and stores in the shared IDE run configuration. Production sets DATABASE_URL. Note that the empty default ${DATABASE_URL:} still fails fast with the same message when the variable is missing, which is exactly what you want in production: a clear startup failure instead of a half-working service.
Common mistake
The most tempting wrong fix is @SpringBootApplication(exclude = DataSourceAutoConfiguration.class) because a Stack Overflow answer said so. The application starts, and the problem moves: the first repository call fails, or JPA auto-configuration fails with a missing entityManagerFactory, or a JdbcTemplate bean cannot be created. Exclusion is correct only when you have no database. If you do, it just hides the missing URL.
A second mistake is hardcoding the production password in application.properties to make the error disappear. Use environment variables, a secrets manager or a profile file that is not committed.
A third: adding H2 to the main classpath “to make it start”. Boot happily creates an in-memory database, the app runs against an empty schema, and data disappears on restart. Keep H2 in test scope unless you really want it.
Verify the behavior
Prove both directions with ApplicationContextRunner, which runs only the auto-configurations you list and is fast:
import static org.assertj.core.api.Assertions.assertThat;
import javax.sql.DataSource;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
class DataSourceConfigurationTest {
private final ApplicationContextRunner runner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class));
@Test
void createsDataSourceWhenUrlIsSet() {
runner.withPropertyValues("spring.datasource.url=jdbc:h2:mem:orders")
.run(context -> assertThat(context).hasSingleBean(DataSource.class));
}
@Test
void failsWithoutUrlOrEmbeddedDatabase() {
runner.withClassLoader(new FilteredClassLoader("org.h2", "org.hsqldb", "org.apache.derby"))
.run(context -> assertThat(context).hasFailed());
}
}This test assumes H2 is a test dependency. For the full application, a @SpringBootTest with @ActiveProfiles("local") (or Testcontainers) confirms the profile wiring. At runtime, a successful start logs HikariPool-1 - Start completed. from com.zaxxer.hikari.HikariDataSource.
Interview exercise
“Your service starts fine on your laptop but fails in CI with ‘Failed to configure a DataSource’. Nobody changed the code. How do you investigate?”
Answer and reasoning
Start from the failure analysis, not the code. The Action: section prints which profiles are active, so compare that with the laptop: an IDE run configuration or a shell variable such as SPRING_PROFILES_ACTIVE often supplies a profile locally that CI lacks. Next, check where the URL comes from on the laptop: a profile file, an environment variable like SPRING_DATASOURCE_URL (relaxed binding maps it to spring.datasource.url), or an untracked application-local.yml ignored by Git. Then check the classpath: if the laptop has H2 on the runtime classpath through a dev dependency, Boot silently used an embedded database there. The fix is to make configuration explicit per environment, inject the CI URL as a variable or use Testcontainers, and keep the fail-fast behaviour rather than excluding auto-configuration.