# Hibernate ORM: the reference JPA implementation, read from the source

> Apache-2.0 licensed, four thousand lines of intent in a repository with more modules than most people expect, and a build that wants JDK 25 to produce Java 17 bytecode.

**hibernate/hibernate-orm** — Idiomatic persistence for Java and relational databases

- Repository: https://github.com/hibernate/hibernate-orm
- Website: http://hibernate.org
- Stars: 6,468 · Forks: 3,816
- Language: Java
- License: Apache-2.0
- Published: 2026-10-06 · Updated: 2026-10-06 · Language: en
- Canonical page: https://hysenlabs.com/projects/hibernate-hibernate-orm

## Three Jakarta specifications, one implementation

The README describes Hibernate ORM as the de facto standard implementation of the Java Persistence API, now called Jakarta Persistence, and that description has widened. The current text names three specifications rather than one: Jakarta Persistence, Jakarta Query and Jakarta Data.

That third one is the interesting development. Jakarta Data is a specification for repository-style data access rather than entity-manager queries, which means the modern Hibernate is not only trying to be a faster mapping layer but is also absorbing the query-builder and repository pattern that other libraries popularised. If you have read comparison articles written against Hibernate 5, they are describing a different project.

The value proposition in the README is written as a list of capabilities rather than adjectives: writing complex queries and working with their results, synchronising in-memory changes with the database, respecting ACID transaction properties, handling temporal data and audit logging, covering multi-tenancy and row-level security, and allowing performance optimisation after the basic persistence logic is written.

Two of those lines are worth pausing on. Audit logging is not a feature of plain JPA, and neither is multi-tenancy or row-level security, so the specification boundary and the implementation boundary are not the same. Hibernate is the place where those extensions live, which is a fair chunk of why applications stay with it rather than swapping to a lighter mapping layer.

## The module list tells you what the project has become

Reading the repository root explains the scope better than the description does. `hibernate-core` is the mapping layer everyone knows, and it sits alongside roughly twenty sibling modules.

The ones with distinct jobs: `hibernate-envers` for entity auditing, `hibernate-spatial` for geospatial types, `hibernate-community-dialects` for databases outside the core set, `hibernate-vector` for vector search support, `hibernate-micrometer` for metrics, `hibernate-jfr` for Java Flight Recorder events, `hibernate-jcache` for second-level cache integration, and two connection-pool integrations in `hibernate-agroal` and `hibernate-hikaricp`. There is also `hibernate-ucp` for the Oracle unified connection pool and `hibernate-c3p` for the older pool.

The testing infrastructure is as large as the product code, which is the correct ratio for something that has to work against dozens of databases. `hibernate-dialect-testkit`, `hibernate-testing`, `hibernate-tck-runner` and `hibernate-tck-data-runner` exist to prove that a dialect behaves, and `hibernate-graalvm` covers native image builds.

Two more directories are easy to overlook and easy to appreciate. `design/` holds design documents, which is a sign the team writes things down. `documentation/` is the source of the guides published at hibernate.org/orm/documentation, and the README links contributors to the AsciiDoc configuration page directly rather than to a rendered page.

The repository also carries governance files with real weight: `MAINTAINERS.md`, `CONTRIBUTING.md`, `dco.txt` for a developer certificate of origin, `AUTHORS.txt`, `branching.adoc` and `classification-tooling.adoc`. That last one controls the stability labels on features, and it is the closest thing to a public statement of what the team considers safe to depend on.

## Building it means JDK 25 and a Gradle wrapper

The build requirement is the first line that makes contributors stop: the build requires at least JDK 25 and produces Java 17 bytecode. So the toolchain is ahead of the output, which is a deliberate choice and one worth respecting.

Gradle drives everything, and the README insists on using the wrapper rather than a system Gradle.

```bash
./gradlew tasks
```

To build every module from the root, the README shows the clone step and the build together.

```bash
cd hibernate-orm
./gradlew build
```

Single modules work either by changing into the module directory or by qualifying the task name, which is the form to use from an IDE-friendly root prompt.

```bash
./gradlew hibernate-core:test
```

The common task list is short and worth knowing by name. `build` assembles jars and runs tests, `compile` performs all compilation including test resources, `jar` produces the archive, `test` runs the tests, `clean` wipes the build directory, and `publishToMavenLocal` abbreviates to `pTML`, installing the artifact into `~/.m2/repository` for cross-checking against another Maven build. Gradle never reads that cache itself, which the README points out, but the escape hatch is invaluable when a change behaves differently under Maven resolution.

None of this is exotic. It is a well-behaved multi-module Gradle project with a documented primer for newcomers, which is more than most repositories of this size offer.

## Testing against a real database through db.sh and profiles

The default test run uses an embedded h2 database, which is fast and easy.

```bash
./gradlew test
```

Testing anything else goes through two steps: start a real database as a container, then run the tests with the matching profile. The script that starts the database is `db.sh`, sitting in the repository root, and running it with no arguments prints the list of available configurations.

```bash
./db.sh postgresql
```

Container support means podman or docker and no local database installation. The script kills any previously started database by default, which is why the multi-database case gets its own flag: `-k` or `--keep-orphans` leaves them running.

```bash
./db.sh -k postgresql
./db.sh -k mysql
```

Profiles are defined in `local.databases.gradle` and activated through a `db` build property, passed either as a JVM system property with `-Ddb=...` or as a Gradle project property with `-Pdb=...`. The examples use the Gradle form.

```bash
gradle clean build -Pdb=postgresql
```

Running tests from an IDE needs the property expansion to happen first, and the README gives a separate compile command with the profile for that. One practical note for contributors: a JDBC driver that is not on Maven Central has to be added to the local `~/.m2/repository` or to a personal repository server, which is the friction point that catches newcomers working with vendor drivers. The `dbHost` system property covers the Docker host address when it is not local.

## Two maintained lines shipping on the same day

The release feed shows what a healthy infrastructure project looks like. 7.4.9 published 2026-09-17, then 7.4.10 and 6.6.58 both published on 2026-09-20, ten minutes apart.

Both notes are formulaic and both are useful. Each names the exact fix version in a Jira query URL, so the change list is one click away rather than being summarised in prose. Each links the release page, the migration guide, the introduction guide, the user guide and the Javadoc, plus the compatibility policy and the supported APIs page.

The reason two branches ship together is generational rather than accidental. The 6.6 line serves applications on the previous Jakarta generation, and 7.4 serves the current one. That is why a new project should not pick a version by taking the highest number available, but by checking the Jakarta Persistence baseline of the runtime it targets.

The last push to the repository was 2026-09-21, a day after the pair of releases. 6469 stars and 3817 forks is an unusual ratio for a library, and the fork count is the more informative half: it reflects the long history of teams forking Hibernate to patch a dialect, change a fetch strategy or vendor an extension, then maintaining that fork indefinitely.

139 open issues is modest for a project this size, and the daily cadence says the triage is working. If you are evaluating the project on maintenance grounds, the release dates are the strongest evidence available, and they are unambiguous.

## What Hibernate is not the right answer for

The comparison people usually make is with a lighter mapping layer or with hand-written JDBC, so it is worth being direct about where the ORM shape costs you.

If your data model is genuinely relational and your queries are joins over many tables, Hibernate will not save you much, because the work it does is mapping objects to rows you could have selected directly. The abstraction earns its cost when the object graph is the natural shape of the problem, which is exactly when the framework is most useful and exactly when the N+1 query problem appears.

The lazy-loading behaviour is the sharp edge. Defaults that fetch related entities on access produce a query per collection, and the usual remedy is an explicit fetch join that you have to remember to add in every place the association is touched. This is a documentation and review problem more than a configuration one.

The build-time cost is real too. The annotation processor, the metamodel generation and the schema tooling add a build step and a classpath, and the move to a newer Jakarta namespace has forced at least one mass rename in every application's history. Teams that resent that should note it before committing rather than after.

None of this makes Hibernate a poor choice. It makes it a specific one: a mapping layer for object-shaped problems on relational databases, with vendor extensions for auditing, multi-tenancy, caching and second-level cache invalidation, maintained by a project whose release cadence is one of the better signals in the Java ecosystem.

## Conclusion

Hibernate ORM is the right default for Java persistence on a relational database, and the case for it is stronger now than it was during the JPA naysaying years. It implements Jakarta Persistence, Jakarta Query and Jakarta Data, it is Apache-2.0 licensed, and it shipped two patch releases on the same day in September 2026, 7.4.10 and 6.6.58 on 2026-09-20, which tells you something about maintenance that any blog post would have to take on faith. Two things to sort out first. The 6.6 line exists for applications still on the older generation, so choosing between the two maintained lines is a decision about your Jakarta EE baseline, not about features. And contributing to the project means building from source, which the README says requires at least JDK 25 and produces Java 17 bytecode, a gap that surprises people. Before adopting anything beyond `hibernate-core`, check which module you actually need, since the repository also ships Envers for audit logging, Spatial for geospatial types and a vector module, and each one is a separate artifact with its own release cadence.

## FAQ

### Is Hibernate an ORM?

Yes. Hibernate ORM is an object-relational mapping solution for Java and the de facto standard implementation of Jakarta Persistence, formerly the Java Persistence API. The current README also names Jakarta Query and Jakarta Data among the specifications it implements. It is Apache-2.0 licensed, the source lives at github.com/hibernate/hibernate-orm, and the documentation is published at hibernate.org/orm.

### Is Hibernate outdated?

No. Hibernate ORM published 7.4.10 and 6.6.58 on the same day, 2026-09-20, with 7.4.9 arriving three days earlier on 2026-09-17, and the repository was last pushed on 2026-09-21. Two maintained lines run in parallel, 7.4 for the current Jakarta generation and 6.6 for the previous one, so pick the line that matches your runtime's Jakarta Persistence baseline rather than the highest version number.

### What is the difference between ORM and JPA?

ORM is the general technique of mapping objects to relational rows, and it is what libraries implement. JPA, now called Jakarta Persistence, is the specification that defines that mapping for Java, including the entity manager, the query language and the annotations. Hibernate is one implementation of the specification. So a specification, not a product, and the specification exists so that other implementations and portable code are possible.

### What is Hibernate and why is it used?

Hibernate exposes relational data to a Java program in a type-safe form, so you can write complex queries, synchronise in-memory changes with the database, respect ACID transaction properties, and handle temporal data and audit logging, multi-tenancy and row-level security. It also lets you optimise performance after the basic persistence logic is written. The practical reason teams reach for it is that the mapping is written once and the object graph becomes the natural shape of the application code.

## Sources

- [hibernate/hibernate-orm on GitHub](https://github.com/hibernate/hibernate-orm)
- [License: Apache-2.0](https://github.com/hibernate/hibernate-orm/blob/main/LICENSE)
- [Project website](http://hibernate.org)
- [README](https://github.com/hibernate/hibernate-orm/blob/main/README.md)
- [Releases](https://github.com/hibernate/hibernate-orm/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/hibernate-hibernate-orm
