A high-performance FHIR R4 server built with Spring Boot and MongoDB, optimized for handling billions of records.
- Full FHIR R4 compliance with 145 resource types
- MongoDB backend with optimized indexes
- Redis caching for high-performance reads
- Cursor-based pagination for efficient large dataset handling
- Async processing for non-blocking operations
- GZIP compression for large resources
- Prometheus metrics for monitoring
- Swagger/OpenAPI documentation
- Docker support with full stack deployment
- Docker & Docker Compose
- Java 17+ (for local development)
- Maven 3.8+ (for local development)
# Clone the repository
git clone <repository-url>
cd fhirSpringboot
# Start all services
./scripts/start.sh
# Or with all admin & monitoring tools
./scripts/start.sh --all
# Check status
./scripts/status.sh
# View logs
./scripts/logs.sh# Start MongoDB and Redis only
docker-compose up -d mongodb redis
# Run the application
mvn spring-boot:runAll scripts are located in the scripts/ directory:
| Script | Description |
|---|---|
start.sh |
Start services with various profiles |
stop.sh |
Stop services (optionally remove data) |
status.sh |
Show status of all services |
logs.sh |
View service logs |
restart.sh |
Restart services |
build.sh |
Build Maven project and Docker image |
# Basic start (MongoDB + Redis + FHIR Server)
./scripts/start.sh
# Start with admin UIs
./scripts/start.sh --admin
# Start with monitoring (Prometheus + Grafana)
./scripts/start.sh --monitoring
# Start all services
./scripts/start.sh --all
# Rebuild and start
./scripts/start.sh --all --build
# Run in foreground (see logs)
./scripts/start.sh --foreground# Stop services (keep data)
./scripts/stop.sh
# Stop and remove all data
./scripts/stop.sh --volumes
# Complete cleanup
./scripts/stop.sh --all# Show status of all services
./scripts/status.sh# Follow all logs
./scripts/logs.sh
# Follow FHIR server logs
./scripts/logs.sh fhir
# Show last 50 lines of MongoDB logs
./scripts/logs.sh mongo -n 50
# Show logs without following
./scripts/logs.sh --no-follow# Restart all services
./scripts/restart.sh
# Restart only FHIR server
./scripts/restart.sh fhir
# Rebuild and restart
./scripts/restart.sh fhir --build# Full build (Maven + Docker)
./scripts/build.sh
# Build without tests
./scripts/build.sh --skip-tests
# Clean build
./scripts/build.sh --clean
# Maven only
./scripts/build.sh --maven-only
# Docker only
./scripts/build.sh --docker-only| Service | URL | Description |
|---|---|---|
| FHIR Server | http://localhost:8080/fhir | FHIR API endpoint |
| Swagger UI | http://localhost:8080/swagger-ui.html | API documentation |
| OpenAPI Spec | http://localhost:8080/api-docs | OpenAPI JSON |
| Health Check | http://localhost:8080/actuator/health | Application health |
| Metrics | http://localhost:8080/actuator/prometheus | Prometheus metrics |
| Property | Value |
|---|---|
| Host | localhost (local) / mongodb (docker) |
| Port | 27017 |
| Database | fhirdb |
| Username | fhiruser |
| Password | fhirpass |
| Connection String | mongodb://fhiruser:fhirpass@localhost:27017/fhirdb?authSource=admin |
| Property | Value |
|---|---|
| Host | localhost (local) / redis (docker) |
| Port | 6379 |
| Password | fhirRedis@2024 |
| Connection | redis://:fhirRedis@2024@localhost:6379 |
| Property | Value |
|---|---|
| URL | http://localhost:8081 |
| Username | admin |
| Password | admin123 |
| Property | Value |
|---|---|
| URL | http://localhost:8082 |
| Username | admin |
| Password | admin123 |
| Property | Value |
|---|---|
| URL | http://localhost:9090 |
| Authentication | (none) |
| Property | Value |
|---|---|
| URL | http://localhost:3000 |
| Username | admin |
| Password | admin123 |
# Basic setup (MongoDB + Redis + FHIR Server)
docker-compose up -d
# With admin UIs (adds MongoDB Express + Redis Commander)
docker-compose --profile admin up -d
# With monitoring (adds Prometheus + Grafana)
docker-compose --profile monitoring up -d
# Full stack (all services)
docker-compose --profile admin --profile monitoring up -dcurl -X POST http://localhost:8080/fhir/Patient \
-H "Content-Type: application/json" \
-d '{
"resourceType": "Patient",
"name": [{"family": "Smith", "given": ["John"]}],
"gender": "male",
"birthDate": "1990-01-15"
}'curl http://localhost:8080/fhir/Patient/{id}# Offset-based pagination
curl "http://localhost:8080/fhir/Patient?_page=0&_count=20"
# Cursor-based pagination (for large datasets)
curl "http://localhost:8080/fhir/Patient?_cursor={lastId}&_count=20"curl -X PUT http://localhost:8080/fhir/Patient/{id} \
-H "Content-Type: application/json" \
-d '{
"resourceType": "Patient",
"id": "{id}",
"name": [{"family": "Smith", "given": ["John", "William"]}],
"gender": "male",
"birthDate": "1990-01-15"
}'curl -X DELETE http://localhost:8080/fhir/Patient/{id}curl http://localhost:8080/fhir/metadatacurl -X POST http://localhost:8080/fhir \
-H "Content-Type: application/json" \
-d '{
"resourceType": "Bundle",
"type": "transaction",
"entry": [
{
"fullUrl": "urn:uuid:patient-1",
"resource": {
"resourceType": "Patient",
"name": [{"family": "Doe", "given": ["Jane"]}]
},
"request": {
"method": "POST",
"url": "Patient"
}
}
]
}'| Variable | Default | Description |
|---|---|---|
MONGODB_URI |
mongodb://fhiruser:fhirpass@localhost:27017/fhirdb?authSource=admin |
MongoDB connection string |
MONGODB_DATABASE |
fhirdb |
Database name |
REDIS_HOST |
localhost |
Redis host |
REDIS_PORT |
6379 |
Redis port |
REDIS_PASSWORD |
(empty) | Redis password |
FHIR_BASE_URL |
http://localhost:8080/fhir |
Base URL for FHIR resources |
MONGO_POOL_MAX_SIZE |
200 |
Max MongoDB connections |
MONGO_POOL_MIN_SIZE |
20 |
Min MongoDB connections |
ASYNC_CORE_POOL_SIZE |
10 |
Async thread pool core size |
ASYNC_MAX_POOL_SIZE |
50 |
Async thread pool max size |
BATCH_SIZE |
1000 |
Batch processing size |
Key configuration in application.yml:
fhir:
server:
base-url: http://localhost:8080/fhir
default-page-size: 20
max-page-size: 100
cache:
default-ttl-minutes: 60
resource-ttl-minutes: 30
search-ttl-minutes: 5
compression:
enabled: true
threshold-bytes: 10000This server supports all 145 FHIR R4 resource types including:
Clinical: Patient, Practitioner, Organization, Encounter, Condition, Observation, DiagnosticReport, Procedure, MedicationRequest, AllergyIntolerance, Immunization, CarePlan, and more.
Financial: Claim, ClaimResponse, Coverage, ExplanationOfBenefit, Invoice, PaymentNotice, and more.
Workflow: Appointment, Schedule, Slot, Task, ServiceRequest, and more.
Conformance: CapabilityStatement, StructureDefinition, ValueSet, CodeSystem, and more.
See /fhir/metadata for the complete list.
The server creates optimized compound indexes for:
- Resource lookups by type and ID
- Filtered queries on
deletedflag - Time-based sorting by
lastUpdated - Patient reference searches
- Code/coding lookups
- Full-text search
| Cache | TTL | Purpose |
|---|---|---|
resources |
30 min | Individual resource reads |
searches |
5 min | Search results |
metadata |
24 hours | CapabilityStatement |
counts |
10 min | Resource counts |
terminology |
12 hours | ValueSet/CodeSystem |
- Offset-based: Traditional
_pageparameter (for small datasets) - Cursor-based:
_cursorparameter (O(1) performance for billions of records)
All FHIR resource operations are logged to MongoDB Time Series Collections for efficient time-based queries and automatic data expiration.
- Per-resource collections: Each resource type has its own time series collection (e.g.,
audit_patient,audit_observation) - Auto-creation: Collections are created automatically on first use
- Change tracking: Stores old/new values and field-level diffs for UPDATE operations
- Auto-expiration: Data automatically expires after retention period (default: 90 days)
- Async logging: Non-blocking audit writes for optimal API performance
fhir:
audit:
enabled: true # Enable/disable audit logging
retention-days: 90 # Auto-expire data after N days
granularity: SECONDS # Time series granularity (SECONDS, MINUTES, HOURS)| Field | Description |
|---|---|
timestamp |
Event timestamp (time series time field) |
action |
CREATE, READ, UPDATE, DELETE, SEARCH, etc. |
resourceType |
FHIR resource type |
resourceId |
Resource ID |
versionId |
Resource version after operation |
oldValue |
Previous state (UPDATE/DELETE) |
newValue |
New state (CREATE/UPDATE) |
changes |
Field-level diff (UPDATE only) |
actor |
User/system performing action |
durationMs |
Operation duration in milliseconds |
# Get audit system status
curl http://localhost:8080/fhir/_audit/status
# Get collection info for a resource type
curl http://localhost:8080/fhir/_audit/collections/Patient
# Get audit logs for a specific resource
curl http://localhost:8080/fhir/_audit/Patient/p-123
# Get recent audit logs (last 24 hours)
curl http://localhost:8080/fhir/_audit/Patient/p-123/recent?hours=24
# Get audit statistics by action type
curl http://localhost:8080/fhir/_audit/Patient/stats{
"timestamp": "2026-02-06T08:30:00Z",
"action": "UPDATE",
"resourceType": "Patient",
"resourceId": "p-123",
"versionId": 2,
"oldValue": "{\"resourceType\":\"Patient\",\"gender\":\"male\"...}",
"newValue": "{\"resourceType\":\"Patient\",\"gender\":\"female\"...}",
"changes": {
"gender": {
"field": "gender",
"oldValue": "male",
"newValue": "female",
"changeType": "MODIFIED"
}
},
"durationMs": 45
}# Application health
curl http://localhost:8080/actuator/health
# Detailed health (when authorized)
curl http://localhost:8080/actuator/health -u admin:adminAvailable at /actuator/prometheus:
fhir_resource_operations_total- CRUD operation countsfhir_resource_latency_seconds- Operation latency (p50, p95, p99)fhir_search_operations_total- Search countsfhir_cache_operations_total- Cache hit/miss ratesfhir_bulk_operations_total- Batch operation counts
- Start with monitoring profile:
docker-compose --profile monitoring up -d - Access Grafana at http://localhost:3000
- Login with
admin/admin123 - Add Prometheus data source:
http://prometheus:9090 - Import dashboard or create custom panels
mvn clean packagemvn testdocker build -t fhir-server:latest .src/main/java/com/fhir/
├── config/ # Configuration classes
│ ├── AsyncConfig.java
│ ├── CacheConfig.java
│ ├── FhirConfig.java
│ ├── MongoConfig.java
│ └── OpenApiConfig.java
├── controller/ # REST controllers
│ ├── FhirResourceController.java
│ ├── FhirSystemController.java
│ ├── PatientController.java
│ └── ...
├── exception/ # Exception handling
├── metrics/ # Prometheus metrics
├── model/ # Data models
├── repository/ # MongoDB repositories
├── service/ # Business logic
│ ├── FhirResourceService.java
│ ├── FhirBatchService.java
│ └── FhirSearchService.java
└── util/ # Utilities
For billions of records, enable MongoDB sharding:
// Connect to mongos
sh.enableSharding("fhirdb")
// Shard by resourceType + resourceId
sh.shardCollection(
"fhirdb.fhir_resources",
{ "resourceType": 1, "resourceId": "hashed" }
)For high availability, use Redis Cluster or Redis Sentinel.
Deploy multiple FHIR server instances behind a load balancer:
# docker-compose.override.yml
services:
fhir-server:
deploy:
replicas: 3Connection refused to MongoDB:
# Check if MongoDB is running
docker-compose ps mongodb
docker-compose logs mongodbRedis connection failed:
# Check Redis status
docker-compose ps redis
redis-cli -h localhost pingOut of memory:
# Increase JVM heap
JAVA_OPTS="-Xmx4g -Xms2g" mvn spring-boot:run# All services
docker-compose logs -f
# Specific service
docker-compose logs -f fhir-server
# Application logs
docker-compose exec fhir-server tail -f /app/logs/application.logThis project is licensed under the MIT License - see the LICENSE file for details.
For issues and feature requests, please open a GitHub issue.