Introduction: why hbm2ddl.auto is both a lifesaver and a headache
\n\nAnyone who has ever configured Hibernate (or Spring Boot + JPA) has encountered the mysterious line in application.properties or hibernate.cfg.xml:
spring.jpa.hibernate.ddl-auto=update\n# or\nhibernate.hbm2ddl.auto=create\n\n\nOn Stack Overflow, this question has gathered hundreds of thousands of views. And for good reason: the wrong value can destroy your data, while the right one can save you hours of work. In this article, we will break down all possible values of hibernate.hbm2ddl.auto, show real Java code examples, and look under the hood to understand how Hibernate actually manages the database schema.
What is hbm2ddl.auto and why is it needed?
\n\nHibernate hbm2ddl.auto is a configuration parameter that controls the automatic creation, updating, or validation of the database schema based on your entities. In other words, Hibernate looks at classes annotated with @Entity, @Table, @Column and on the fly generates SQL queries like CREATE TABLE, ALTER TABLE, etc.
This is incredibly convenient during development, but can become a disaster in production if you don't understand how each value works internally.
\n\nComplete list of possible hibernate.hbm2ddl.auto values
\n\nHibernate supports exactly five values (plus none as the absence of action):
- \n
validate— schema validation only \n update— automatic update \n create— create from scratch on startup \n create-drop— create on startup and drop on shutdown \n none— do nothing (default value) \n
Let's break down each value in detail, with examples and an explanation of what happens "under the hood."
\n\n1. validate — check, but don't change
\n\nHow it works: On application startup, Hibernate compares your Java entities with the actual table structure in the database. If everything matches — the application starts. If not — Hibernate throws a SchemaValidationException.
Configuration example:
\n\n// application.properties\nspring.jpa.hibernate.ddl-auto=validate\n\n\nEntity example:
\n\n@Entity\n@Table(name = "users")\npublic class User {\n @Id\n @GeneratedValue(strategy = GenerationType.IDENTITY)\n private Long id;\n \n @Column(name = "email", nullable = false, length = 255)\n private String email;\n \n @Column(name = "age")\n private Integer age;\n}\n\n\nWhat happens under the hood: Hibernate reads the entity metadata, forms an internal representation of the users table with columns id, email (NOT NULL, length 255), age. Then it executes an SQL query to information_schema (or its equivalent in your DB) and compares types, nullable, lengths. If the email column in the DB has type VARCHAR(100) — an error will occur.
When to use: Ideal for production, to ensure that migrations (Liquibase/Flyway) have not broken the correspondence with the code.
\n\n2. update — automatic update (with caution!)
\n\nHow it works: Hibernate automatically adds new tables, columns, and constraints if they are missing in the DB. However, it never deletes columns or tables, even if you removed them from the Java code.
\n\nConfiguration example:
\n\n// application.properties\nspring.jpa.hibernate.ddl-auto=update\n\n\nExample mod