Spring Boot: H2 In-Memory Database

H2 is a lightweight Java SQL database that Spring Boot auto-configures when it finds the H2 dependency on the classpath. It runs entirely in memory by default, no installation needed, making it ideal for development, tests, and prototyping. Data is lost when the application stops unless persistent mode is configured.

Contents

Adding H2 Dependency

H2 provides the in-memory database, and Spring Data JPA the repositories.

XML
<!-- Maven — typically test scope for production projects, or compile for dev -->
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <scope>runtime</scope>
</dependency>

<!-- Also add Spring Data JPA if using JPA -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

Auto-Configuration

When Spring Boot detects H2 on the classpath and no other DataSource is configured, it auto-configures:

  • An in-memory H2 DataSource with a random database name.
  • Spring Data JPA / Hibernate with ddl-auto=create-drop: tables are created on startup and dropped on shutdown.
  • The H2 console at /h2-console (disabled by default: must be enabled in properties).

H2 Console Setup

Turn on the H2 console for development with these properties.

Properties
# application.properties
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console
# set to true only if you need remote access
spring.h2.console.settings.web-allow-others=false

Open the H2 console at http://localhost:8080/h2-console in your browser. The JDBC URL will match what you see in the Spring Boot startup log, e.g. jdbc:h2:mem:testdb.

If Spring Security is on the classpath, the H2 console path must be permitted and frame options must be disabled (H2 console uses iframes). Add .requestMatchers("/h2-console/**").permitAll() and .headers(h -> h.frameOptions(f -> f.disable())) to your SecurityFilterChain.

application.properties Config

The settings below can be placed in application.yml or application.properties. All keys shown are optional unless marked: Spring Boot applies sensible defaults when they are omitted.

Properties
# Fix the database name so the H2 console JDBC URL is predictable
spring.datasource.url=jdbc:h2:mem:mydb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=false
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=

# JPA / Hibernate
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto=create-drop  # or update, validate, none
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
DB_CLOSE_DELAY=-1 keeps the in-memory database alive as long as the JVM is running. Without it, the database may be closed between connection pool checkouts.

Using with Spring Data JPA (Entity + Repository)

An entity and a repository are all you need to store data in H2.

Java
import jakarta.persistence.*;

@Entity
@Table(name = "products")
public class Product {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false)
    private String name;

    @Column(nullable = false)
    private BigDecimal price;

    // constructors, getters, setters
}
Java
import org.springframework.data.jpa.repository.JpaRepository;
import java.math.BigDecimal;
import java.util.List;

public interface ProductRepository extends JpaRepository<Product, Long> {
    List<Product> findByPriceGreaterThan(BigDecimal minPrice);
    List<Product> findByNameContainingIgnoreCase(String keyword);
}

Schema and Data SQL Files

Place SQL files in src/main/resources and Spring Boot will execute them on startup. Use these when you want explicit control over the DDL rather than Hibernate auto-generation.

SQL
-- src/main/resources/schema.sql
CREATE TABLE IF NOT EXISTS products (
    id    BIGINT AUTO_INCREMENT PRIMARY KEY,
    name  VARCHAR(200) NOT NULL,
    price DECIMAL(10, 2) NOT NULL
);

CREATE TABLE IF NOT EXISTS orders (
    id          BIGINT AUTO_INCREMENT PRIMARY KEY,
    product_id  BIGINT NOT NULL,
    quantity    INT    NOT NULL,
    created_at  TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (product_id) REFERENCES products(id)
);
SQL
-- src/main/resources/data.sql
INSERT INTO products (name, price) VALUES ('Widget A', 9.99);
INSERT INTO products (name, price) VALUES ('Widget B', 19.99);
INSERT INTO products (name, price) VALUES ('Gadget Pro', 49.99);
Properties
# Enable script-based initialisation (required in Spring Boot 2.5+)
spring.sql.init.mode=always

# If using Hibernate AND SQL scripts, defer data source initialisation
spring.jpa.defer-datasource-initialization=true

Switching to Persistent Mode

Replace the in-memory URL with a file path to persist the H2 database between restarts.

Properties
# Persistent H2 — stores to a file
spring.datasource.url=jdbc:h2:file:./data/mydb;AUTO_SERVER=true
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=

# Use validate or update (not create-drop) for persistent mode
spring.jpa.hibernate.ddl-auto=update

The AUTO_SERVER=true flag starts an embedded TCP server, allowing multiple processes to connect to the same file-based database simultaneously.

H2 persistent mode is suitable for development and lightweight tooling, not for production workloads. For production, replace with PostgreSQL, MySQL, or another production-grade database by swapping the spring.datasource.* properties and adding the appropriate JDBC driver.