Configuration Reference
This is the comprehensive reference for Fire Arrow Server's application.yaml configuration. Properties are organized by section, with descriptions, defaults, and examples.
spring.datasource - Database Connection
Fire Arrow Server uses PostgreSQL as its primary data store. For quick local experimentation, H2 in-memory is also supported.
PostgreSQL (Recommended)
spring:
datasource:
url: jdbc:postgresql://localhost:5432/hapi
username: hapi
password: hapi
driverClassName: org.postgresql.Driver
hikari:
maximum-pool-size: 20
minimum-idle: 5
jpa:
properties:
hibernate.dialect: ca.uhn.fhir.jpa.model.dialect.HapiFhirPostgres94Dialect
hibernate.search.enabled: false
H2 In-Memory (Development Only)
spring:
datasource:
url: jdbc:h2:mem:hapi;DB_CLOSE_ON_EXIT=FALSE
username: sa
password:
driverClassName: org.h2.Driver
jpa:
properties:
hibernate.dialect: ca.uhn.fhir.jpa.model.dialect.HapiFhirH2Dialect
H2 is suitable for quick experiments only. Data is lost when the server stops. Always use PostgreSQL for persistent deployments.
| Property | Description | Default |
|---|---|---|
url | JDBC connection URL | jdbc:postgresql://localhost:5432/hapi |
username | Database username | hapi |
password | Database password | hapi |
driverClassName | JDBC driver class | org.postgresql.Driver |
hikari.maximum-pool-size | Maximum connections in the pool | 20 |
hikari.minimum-idle | Minimum idle connections maintained | 5 |
hapi.fhir - FHIR Server Behavior
Controls the FHIR server's capabilities, supported resources, and API features.
hapi:
fhir:
fhir_version: R4
graphql_enabled: true
openapi_enabled: true
default_page_size: 20
max_page_size: 200
search_index_full_text_enabled: false
cors:
enabled: true
allowed_origins:
- "*"
subscription:
resthook_enabled: false
message_enabled: false
websocket_enabled: false
email:
enabled: false
| Property | Description | Default |
|---|---|---|
fhir_version | FHIR specification version | R4 |
graphql_enabled | Enable the GraphQL API endpoint | true |
openapi_enabled | Enable Swagger UI and OpenAPI spec | true |
default_page_size | Default number of results per page | 20 |
max_page_size | Maximum results per page | 200 |
search_index_full_text_enabled | Enable full-text search (_text, _content parameters) | false |
cors.enabled | Enable CORS headers | true |
cors.allowed_origins | Allowed CORS origins | ["*"] |
subscription.resthook_enabled | Enable REST hook subscription channel | false |
subscription.message_enabled | Enable message subscription channel (used by Azure Queue delivery and the CarePlan nop channel) | false |
subscription.websocket_enabled | Enable WebSocket subscription channel | false |
subscription.email.enabled | Enable email subscription channel | false |
subscription.email.from | Sender address for email subscriptions | -- |
fire-arrow.authentication - Authentication Providers
Configure OAuth 2.0 / OIDC providers and API token support. See Authentication for a detailed guide.
fire-arrow:
authentication:
enabled: true
providers:
- name: my_oidc_provider
type: oidc
enabled: true
oidc-uri: "https://login.example.com"
audience: "api://fire-arrow"
api-scope: "fhir.access"
claim-mapping:
scope-claim: "scp"
roles-claim: "roles"
subject-claim: "sub"
email-claim: "email"
name-claim: "name"
fhir-resource-type-claim: "resource_type"
fhir-id-claim: "fhir_id"
identity-resolution:
identifier-system: "https://your-app.example.com/fhir/user-id"
auto-create-enabled: true
api-tokens:
hmac-secret: "${API_TOKEN_SECRET}"
| Property | Description | Default |
|---|---|---|
enabled | Enable authentication globally | false |
providers[].name | Unique provider name | -- |
providers[].type | Provider type (oidc, azure-identity) | -- |
providers[].enabled | Enable this provider | true |
providers[].oidc-uri | OIDC issuer URI | -- |
providers[].audience | Expected token audience | -- |
providers[].api-scope | Required API scope | -- |
providers[].claim-mapping.* | Maps token claims to identity fields | -- |
providers[].identity-resolution.identifier-system | FHIR identifier system for user lookup | -- |
providers[].identity-resolution.auto-create-enabled | Create FHIR resources for new users | false |
api-tokens.hmac-secret | Secret key for API token generation/validation | -- |
fire-arrow.authorization - Access Control
Configure role-based access control rules. See Authorization for a detailed guide.
fire-arrow:
authorization:
default-validator: Forbidden
debug: false
cache:
enabled: true
ttl-seconds: 300
validation-rules:
- client-role: "Patient"
resource: "Patient"
operation: "read"
validator: "PatientCompartment"
- client-role: "Patient"
resource: "Patient"
operation: "graphql-read"
validator: "PatientCompartment"
- client-role: "Practitioner"
resource: "Patient"
operation: "search"
validator: "LegitimateInterest"
| Property | Description | Default |
|---|---|---|
default-validator | Validator applied when no rule matches | Forbidden |
debug | Enable authorization debug mode (logs detailed rule evaluation) | false |
cache.enabled | Cache authorization decisions | true |
cache.ttl-seconds | Cache entry time-to-live in seconds | 300 |
validation-rules[] | List of authorization rules | [] |
validation-rules[].client-role | Role this rule applies to (Patient, Practitioner, RelatedPerson, Device, Public) | -- |
validation-rules[].resource | FHIR resource type this rule applies to | -- |
validation-rules[].operation | Operation (read, search, create, write, delete, graphql-read, graphql-search, me, binary-upload, subscribe, generate-durable-token, generate-one-time-token) | -- |
validation-rules[].validator | Validator to use (PatientCompartment, LegitimateInterest, CareTeam, Forbidden, Permit) | -- |
Set debug: true during development to see detailed logs of how each request is evaluated against your authorization rules. Disable it in production - debug mode logs sensitive information.
fire-arrow.binary-storage - Azure Blob Storage
Configure binary file storage. See Binary Storage for the full guide.
fire-arrow:
binary-storage:
enabled: false
azure:
connection-string: "${AZURE_STORAGE_CONNECTION_STRING}"
container-name: "fhir-binaries"
max-file-size: 10485760
pre-signed-url-expiration-seconds: 120
| Property | Description | Default |
|---|---|---|
enabled | Enable binary storage | false |
azure.connection-string | Azure Blob Storage connection string | -- |
azure.endpoint | Azure Blob endpoint (for managed identity) | -- |
azure.container-name | Blob container name | -- |
azure.max-file-size | Maximum upload size in bytes | 10485760 (10 MB) |
azure.pre-signed-url-expiration-seconds | Pre-signed URL lifetime | 120 |
fire-arrow.careplan-events - CarePlan Scheduling
Configure server-side CarePlan activity materialization. See CarePlan Events for the full guide, including Task Expiration and Validity.
fire-arrow:
careplan-events:
enabled: true
horizon-duration: "P30D"
subscriptions:
max-ttl: "P30D"
require-end: true
excess-end-action: reject
delivery:
max-consecutive-failures: 5
disable-after-no-success: "P7D"
cleanup:
sweep-interval: "PT1H"
delete-disabled-after: "P30D"
due-task-check-interval: "PT1M"
expired-task-check-interval: "PT1M"
task:
initial-status: requested
due-status: ready
auto-transition-to-ready: true
auto-transition-to-terminal: true
auto-transition-terminal-state: cancelled
default-validity-period: "PT4H"
task-validity-periods:
PT1H: "PT15M"
P1D: "PT1H"
P1W: "P1D"
careplan-validity-extension:
enabled: false
| Property | Description | Default |
|---|---|---|
enabled | Enable CarePlan event processing | true |
horizon-duration | How far ahead to materialize Tasks (ISO 8601 duration) | P30D |
subscriptions.max-ttl | Maximum allowed subscription lifetime | P30D |
subscriptions.require-end | Whether Subscription.end is mandatory | true |
subscriptions.excess-end-action | Action when end exceeds max-ttl (reject or truncate) | reject |
delivery.max-consecutive-failures | Consecutive failures before disabling a subscription | 5 |
delivery.disable-after-no-success | Duration without a successful delivery before disabling | P7D |
cleanup.sweep-interval | How often the subscription cleanup job runs | PT1H |
cleanup.delete-disabled-after | When to delete disabled subscriptions (P0D = keep forever) | P30D |
cleanup.due-task-check-interval | How often the due-task sweeper runs | PT1M |
cleanup.expired-task-check-interval | How often the expired-task sweeper runs | PT1M |
task.initial-status | Status of newly materialized Tasks | requested |
task.due-status | Status Tasks transition to when due | ready |
task.auto-transition-to-ready | Automatically move Tasks to due-status when due | true |
task.auto-transition-to-terminal | Automatically transition expired Tasks to terminal status (1.13.0+) | true |
task.auto-transition-terminal-state | Terminal status for expired Tasks (cancelled, failed, entered-in-error) (1.13.0+) | cancelled |
task.default-validity-period | How long after its due time a Task remains actionable (1.13.0+) | PT4H |
task.task-validity-periods | Map of scheduling interval → validity period (ceiling lookup) (1.13.0+) | PT1H: PT15M, P1D: PT1H, P1W: P1D |
task.careplan-validity-extension.enabled | Honor per-CarePlan validity overrides (1.13.0+) | false |
$subscribe-due-events also needs a subscription channelcareplan-events.enabled: true on its own does not activate subscription-based materialization. $subscribe-due-events relies on HAPI's subscription pipeline, which turns on only when at least one channel flag (hapi.fhir.subscription.resthook_enabled, message_enabled, websocket_enabled, or email.enabled) is true. There is no separate subscription.enabled flag. The enabled channel must match the subscription's channel: rest-hook needs resthook_enabled, and the polling-only nop channel needs message_enabled. With no matching channel enabled, the Subscription is created but stays in requested status and no Tasks are materialized. $materialize (1.11+) schedules Tasks without a channel. See CarePlan Events.
fire-arrow.subscription.azure-queue - Azure Storage Queue
Configure the Azure Storage Queue subscription delivery channel. See Subscriptions for details, including per-Subscription queue routing.
fire-arrow:
subscription:
azure-queue:
enabled: false
connection-string: "${AZURE_STORAGE_CONNECTION_STRING}"
queue-name: "fhir-subscription-events"
endpoint-prefix: "channel:fire-arrow-azure-queue"
auto-create-queue: true
| Property | Description | Default |
|---|---|---|
enabled | Enable Azure Storage Queue delivery | false |
connection-string | Azure Storage account connection string | -- |
service-url | Queue service URL when authenticating via managed identity | -- |
credential-mode | default or managed-identity (used with service-url) | default |
queue-name | Default queue used when a Subscription doesn't override it | fhir-subscription-events |
endpoint-prefix | Well-known prefix that opts a Subscription into per-queue routing via channel.endpoint = <prefix>:<queue-name> | channel:fire-arrow-azure-queue |
allowed-override-queues | Allow-list of queue names that may be selected via the endpoint suffix. Empty means no overrides accepted (deny-by-default). | [] |
auto-create-queue | Auto-create the default queue at boot | true |
auto-create-override-queues | Auto-create suffix-derived override queues on first delivery (off by default; provision per-tenant queues out-of-band instead) | false |
override-queue-cache-max-size | Maximum number of distinct override QueueClients kept cached in memory (bounded LRU) | 256 |
include-full-resource | Include the full FHIR resource payload in each message | true |
payload-format | Payload serialisation format (JSON or XML) | JSON |
channel-type | Subscription channel types to intercept (message, rest-hook, all) | message |
fire-arrow.license - License Configuration
Configure the Fire Arrow Server license. See Licensing for the full guide.
fire-arrow:
license:
source: file
path: "/etc/fire-arrow/license.key"
deployment-id: "my-deployment-prod"
runtime-environment: prod
| Property | Description | Values |
|---|---|---|
source | License delivery method | file, inline |
path | Path to license file | File path (when source: file) |
content | Inline license string | License content (when source: inline) |
deployment-id | Deployment identifier | Must match the issued license |
runtime-environment | Deployment tier | prod, nonprod |
fire-arrow.admin - Admin Web UI
Configure the browser-based administration interface.
fire-arrow:
admin:
enabled: true
config-viewer:
enabled: true
auth-profiles:
- name: "Development"
token: "${ADMIN_DEV_TOKEN}"
| Property | Description | Default |
|---|---|---|
enabled | Enable the admin web UI at /admin/ | true |
config-viewer.enabled | Show server configuration in the admin UI | true |
auth-profiles[] | Pre-configured auth profiles for the admin GraphQL explorer | [] |
auth-profiles[].name | Display name for the profile | -- |
auth-profiles[].token | Bearer token to use with this profile | -- |
Auth profiles let you switch between different user identities in the admin GraphQL explorer without manually copying tokens. This is useful during development when you want to test queries as different roles.
Web UI Login (web-ui-auth)
Interactive sign-in to the web UI is configured separately under fire-arrow.admin.web-ui-auth. Each login profile is a confidential OAuth client and must have a client-secret — the server signs users in through a server-side Backend-for-Frontend and never exposes tokens to the browser.
fire-arrow:
admin:
web-ui-auth:
profiles:
- profile: patient-login
name: Patient
authentication-system: azure-b2c
client-id: "${OIDC_PATIENT_CLIENT_ID}"
client-secret: "${OIDC_PATIENT_CLIENT_SECRET}"
scopes: "openid profile"
See Web UI Sign-In for the full property reference, the identity provider redirect URI, Content Security Policy options, and upgrade guidance from the pre-1.14.0 browser-based login.
fire-arrow.mutex - Distributed Locking
Controls how Fire Arrow Server coordinates background tasks across nodes.
fire-arrow:
mutex:
type: local
| Property | Description | Values |
|---|---|---|
type | Lock implementation | local (single node), jdbc (multi-node via PostgreSQL) |
Use jdbc when running multiple Fire Arrow Server instances to ensure CarePlan materialization and subscription processing run on exactly one node at a time.
Environment Variable Override Pattern
Every YAML property can be overridden with an environment variable. The conversion rules:
- Remove the YAML hierarchy and join with underscores
- Convert to uppercase
- Replace dots and hyphens with underscores
Examples:
| YAML Path | Environment Variable |
|---|---|
spring.datasource.url | SPRING_DATASOURCE_URL |
spring.datasource.password | SPRING_DATASOURCE_PASSWORD |
hapi.fhir.graphql_enabled | HAPI_FHIR_GRAPHQL_ENABLED |
fire-arrow.authentication.enabled | FIRE_ARROW_AUTHENTICATION_ENABLED |
fire-arrow.binary-storage.azure.connection-string | FIRE_ARROW_BINARY_STORAGE_AZURE_CONNECTION_STRING |
fire-arrow.careplan-events.scheduling.horizon-duration | FIRE_ARROW_CAREPLAN_EVENTS_SCHEDULING_HORIZON_DURATION |
fire-arrow.license.source | FIRE_ARROW_LICENSE_SOURCE |
fire-arrow.mutex.type | FIRE_ARROW_MUTEX_TYPE |
Complete Example
Here's a production-ready application.yaml with all major features enabled:
spring:
datasource:
url: jdbc:postgresql://db:5432/hapi
username: ${DB_USERNAME}
password: ${DB_PASSWORD}
driverClassName: org.postgresql.Driver
hikari:
maximum-pool-size: 20
jpa:
properties:
hibernate.dialect: ca.uhn.fhir.jpa.model.dialect.HapiFhirPostgres94Dialect
hapi:
fhir:
fhir_version: R4
graphql_enabled: true
openapi_enabled: true
default_page_size: 20
max_page_size: 200
cors:
enabled: true
allowed_origins:
- "https://your-app.example.com"
subscription:
resthook_enabled: true
websocket_enabled: true
fire-arrow:
authentication:
enabled: true
providers:
- name: primary_oidc
type: oidc
enabled: true
oidc-uri: "https://login.example.com"
audience: "api://fire-arrow"
api-scope: "fhir.access"
claim-mapping:
scope-claim: "scp"
roles-claim: "roles"
subject-claim: "sub"
email-claim: "email"
name-claim: "name"
fhir-resource-type-claim: "resource_type"
fhir-id-claim: "fhir_id"
identity-resolution:
identifier-system: "https://your-app.example.com/fhir/user-id"
auto-create-enabled: true
api-tokens:
hmac-secret: ${API_TOKEN_SECRET}
authorization:
default-validator: Forbidden
debug: false
cache:
enabled: true
ttl-seconds: 300
validation-rules:
- client-role: "Patient"
resource: "Patient"
operation: "read"
validator: "PatientCompartment"
- client-role: "Patient"
resource: "Patient"
operation: "graphql-read"
validator: "PatientCompartment"
- client-role: "Patient"
resource: "Observation"
operation: "graphql-search"
validator: "PatientCompartment"
- client-role: "Practitioner"
resource: "Patient"
operation: "search"
validator: "LegitimateInterest"
binary-storage:
enabled: true
azure:
connection-string: ${AZURE_STORAGE_CONNECTION_STRING}
container-name: "fhir-binaries"
max-file-size: 10485760
careplan-events:
enabled: true
scheduling:
horizon-duration: "P30D"
check-interval: "PT1H"
subscriptions:
max-ttl: "P90D"
delivery:
max-retries: 3
failure-threshold: 5
subscription:
azure-queue:
enabled: true
connection-string: ${AZURE_STORAGE_CONNECTION_STRING}
queue-name: "fhir-events"
license:
source: inline
content: ${FIRE_ARROW_LICENSE_CONTENT}
deployment-id: "production-01"
runtime-environment: prod
admin:
enabled: true
mutex:
type: jdbc