Open-source project
hapifhir/hapi-fhir avatar
hapifhir/hapi-fhir

hapi-fhir: the Java library most FHIR servers and clients are built on

🔥 HAPI FHIR - Java API for HL7 FHIR Clients and Servers

2,410 stars1,506 forksJavaApache-2.0

At a glance

What is it?
HAPI FHIR is not one library but fifty Maven modules covering client transports, a JPA-backed server, storage, terminology services and Android bindings, and the README is little more than a set of signposts to hapifhir.io.
Who is it for?
hapi-fhir makes sense when you are writing Java and need real FHIR behaviour rather than a thin REST wrapper: validated resources, several FHIR versions in one codebase, a server stack that persists to a relational database. The cost is the module map, where picking the wrong artifact for a job is an easy mistake and the README will not catch you on it.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 2 days ago.
What is it written in?
Mainly Java, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 11, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A README that is almost entirely signposts

It is worth being blunt about the first thing a reader hits: the HAPI FHIR README is short. After the title and the one-line description, it carries a CI table with three columns for the master build, the SNAPSHOT pipeline and the current release, a coverage section, and then a list of links. There is no quick start, no dependency snippet, no sample code, and no list of requirements.

Everything substantive is delegated. Complete project documentation lives at hapifhir.io, a running demonstration is at hapi.fhir.org, and a wiki page on GitHub is where the project sends anyone looking for help. Commercial support is handled separately, with the README pointing at Smile CDR for that.

That delegation is a legitimate choice for a project of this size, and for a Java library it is also how you read most Maven Central artifacts. But it does mean the repository README cannot answer a single adoption question on its own. Which module do I want? Which version pairs with which FHIR release? Does it run on Java 17? None of that is here. You are expected to go to the documentation site, which is a real cost that a smaller project does not charge you.

The module map is the architecture

Because the README is thin, the top-level tree becomes the most informative thing in the repository. There are around fifty entries, and they fall into recognizable families:

bash
hapi-fhir-base/
hapi-fhir-client/
hapi-fhir-client-okhttp/
hapi-fhir-client-apache-http5/
hapi-fhir-converter/
hapi-fhir-jpa/
hapi-fhir-jpaserver-base/
hapi-fhir-jpaserver-model/
hapi-fhir-storage-batch2/
hapi-fhir-storage-mdm/
hapi-fhir-server-openapi/
hapi-fhir-server-cds-hooks/

The naming is consistent enough to read as a design. The `hapi-fhir-client-` family is the outbound side, with a base client and two HTTP transports underneath it, which reads as an abstraction over OkHttp and Apache HttpClient 5 rather than a hard dependency on either. The `hapi-fhir-jpaserver-` family is the inbound side, split so that the persistence model, the search parameter registry, the storage layer and the matcher logic can move independently.

`hapi-fhir-converter` is the piece that turns wire formats into Java objects, and `hapi-fhir-base` is what everything else shares. Around those sit the deployment-shaped modules: `hapi-fhir-spring-boot`, `hapi-fhir-cli`, `hapi-fhir-android`, `hapi-fhir-dist`, `hapi-fhir-bom` for dependency management, and `hapi-fhir-docs`.

Then there is the long tail of specialised servers, and this is where the project stops looking like a general library: a CDS Hooks server, a master data management server, an international patient summary module, an HFQL module, subscription handling, and OpenAPI generation. Each is a directory you can ignore until you need it, and each is also a thing you have to understand before you can be sure the base server does not already do it.

Client transports and the choice they force

The client side is where a real decision sits, and it is not one the README helps with. Having both `hapi-fhir-client-okhttp` and `hapi-fhir-client-apache-http5` means the FHIR client is written against an abstraction with at least two implementations, so you pick a transport rather than inherit one.

That choice is ordinary enough, but it has consequences. OkHttp sits on top of the JDK HTTP client and brings its own connection pool and interceptor model. Apache HttpClient 5 is the Apache project's own client, widely used in enterprise Java stacks and the one most likely to match the rest of an existing application. If you already have an OkHttp-based service or an HttpClient 5 based service, the mismatch costs you either an adapter or a second transport in the same process.

A subtler consequence is versioning. This project publishes client modules at a different cadence from server modules, and the tree shows separate test modules per FHIR version for the server side, including dedicated directories for DSTU2, DSTU3, R4, R4B and R5. A codebase serving several FHIR versions at once is exactly the situation HAPI is built for, and also exactly the situation where a single wrong version of an artifact produces a class of error that is hard to read, because the failure shows up as a missing method rather than a version conflict.

What the JPA server stack commits you to

The server side names a persistence approach in the module list, which is more information than most FHIR libraries give you. `hapi-fhir-jpa` and `hapi-fhir-jpa-hibernate-services` say the storage engine is JPA over Hibernate, and the surrounding directories, including `hapi-fhir-storage-batch2`, `hapi-fhir-storage-mdm`, `hapi-fhir-jpaserver-searchparam` and `hapi-fhir-jpaserver-model`, describe a server that persists to a relational database through a generated data model rather than storing opaque JSON documents.

The consequence is the usual trade for that design. You get SQL you can inspect, index you can tune, and transactions, which matters the moment anyone asks about reporting or a support engineer needs to look at a row. You also get a schema that has to be managed across FHIR versions, and a search parameter registry that is code rather than configuration, since `hapi-fhir-jpaserver-searchparam` exists as its own module. Custom search parameters are a real part of FHIR server work, and whether that arrives as a deployable artifact or as a class you write and register changes the shape of your release process.

`hapi-fhir-storage-batch2` is a good name to stop on. The storage layer is not one implementation, and a project with two numbered storage generations is telling you that the persistence approach has been revised at least once. Reading that module boundary before you commit is cheaper than discovering it later. There is also `hapi-fhir-sql-migrate` in the tree, which suggests migration tooling ships alongside, and `hapi-fhir-jpaserver-elastic-test-utilities`, which points at Elasticsearch as a tested search option rather than an undocumented one.

Cadence, tooling files and the release notes

The repository is not archived and the last push was on 2026-09-28, so this is an actively maintained codebase rather than a legacy one you are reviving. The release page shows v8.12.0 published 2026-09-01, v8.12.1 published 2026-09-15, and v8.8.2 published 2026-09-25, which tells you two things: the project ships often, and the 8.x line is still receiving patch releases while the 8.12 series advances.

What the release entries do not do is describe anything. Each published note for these three versions is just the version number as its body. So the release page confirms that a build happened and roughly when, and nothing about what changed or what you must do when upgrading. For a library with this many modules, an upgrade crossing several minor versions is where you would most want that information, and the release page will not supply it. The version history has to be reconstructed from commit history and from the documentation site.

The tree also shows how the project is run: `.pre-commit-config.yaml` and a `hapi-fhir-checkstyle` module for style enforcement, `hapi-fhir-jacoco` for coverage, `.whitesource` for dependency scanning, and a `check_for_maven_updates.sh` script at the root. Two files at the root are unusual enough to mention: `AGENTS.md` and `CLAUDE.md` sit next to `AI_POLICY.md` and `CONTRIBUTORS.md`, which means the project has written down how it expects automated tooling to be used in its own development, and `HELPWANTED.md` is the standing invitation for outside contributions.

Licensing is Apache 2.0, with both `LICENSE.txt` and `NOTICE.txt` present, which is what that license requires. For a library that healthcare vendors embed in products, the permissive license is a genuine advantage over anything copyleft, and the presence of a NOTICE file means downstream attribution obligations are already documented.

When hapi-fhir is the wrong size of tool

The honest case against it is weight. If you need to read and write a handful of FHIR resources, validate them against a profile, and ship them over HTTPS, then a client library plus a few libraries from the ecosystem is a lighter dependency than fifty Maven modules with a Hibernate stack behind them. The README even links to a demo server and a documentation site that cover the simple path, which suggests most readers start far from the server modules.

There is a licensing-shaped reason to look elsewhere too, and it is not about price. The README routes commercial support enquiries to a separate company, which is a normal arrangement and not a problem in itself. It does mean that if you need someone accountable under contract for a supported FHIR version, you are looking at a commercial product rather than buying support from the project, and that conversation starts somewhere other than the repository.

For a server, the real alternative is to write against the HL7 FHIR specification directly, or to adopt a hosted FHIR service and keep HAPI only as a client. Each is defensible. Building your own means owning conformance testing, search parameter registration, versioning, terminology expansion and conditional update semantics, which is a large amount of specification surface to hold correctly. A hosted service means giving up control of where patient data sits, which in several jurisdictions is the whole decision.

Where HAPI is hard to beat is exactly the case the repository is built around: several FHIR versions coexisting, Java on both ends of the wire, and a server that must persist to a database you also need to query. If that is your situation, the module list is not a warning sign. It is evidence that someone has already split the problem into the pieces you would otherwise have to split yourself.

Editorial conclusion

hapi-fhir makes sense when you are writing Java and need real FHIR behaviour rather than a thin REST wrapper: validated resources, several FHIR versions in one codebase, a server stack that persists to a relational database. The cost is the module map, where picking the wrong artifact for a job is an easy mistake and the README will not catch you on it. Start at hapifhir.io, read the getting started page for the component you actually need, and confirm on the Maven Central listing under the group id ca.uhn.hapi.fhir that the artifact version you need matches the FHIR version your payloads use.

Frequently asked questions

What is Hapi in FHIR?

HAPI is the open source Java implementation of the HL7 FHIR standard, and hapi-fhir is the project that publishes it. The repository describes itself as a Java API for HL7 FHIR clients and servers, which covers both directions: reading and writing FHIR resources, and running a server that stores them.

Is Hapi FHIR open-source?

Yes. The project states that it is open source and licensed under the Apache Software License 2.0, and the repository root carries both LICENSE.txt and NOTICE.txt. Commercial support is handled separately, with the README pointing readers to Smile CDR rather than selling it in the repository.

Which Maven artifact should I depend on?

It depends entirely on what you are building. The tree separates client transports such as hapi-fhir-client-okhttp and hapi-fhir-client-apache-http5 from the server stack built on hapi-fhir-jpa and hapi-fhir-jpaserver-base, plus conversion in hapi-fhir-converter and shared types in hapi-fhir-base. Artifacts are published under the group id ca.uhn.hapi.fhir, and the getting started documentation on hapifhir.io is where the mapping is documented.

Does hapi-fhir store data in a relational database?

The module names indicate a JPA and Hibernate based server: hapi-fhir-jpa, hapi-fhir-jpa-hibernate-services, hapi-fhir-jpaserver-model and the hapi-fhir-storage-batch2 family. Search parameters live in their own module, hapi-fhir-jpaserver-searchparam, which means they are registered in code rather than only in configuration files.

Official sources

  1. hapifhir/hapi-fhir on GitHub
  2. License: Apache-2.0
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/hapifhir-hapi-fhir.svg)](https://hysenlabs.com/projects/hapifhir-hapi-fhir)