Skip to main content

Server Configuration

The FHIR server loads its configuration with Figment, merging two sources:

let config: ServerConfig = Figment::new()
.merge(Toml::file("haste.toml"))
.merge(Env::prefixed("HASTE_"))
.extract()?;
  1. haste.toml — read relative to the process's working directory (backend/, when running cargo run server start from there). If the file doesn't exist, this step is silently skipped — there's no error, the server just falls through to defaults/env.
  2. HASTE_-prefixed environment variables — merged after the TOML file, so environment variables win on any key set in both.

Anything left unset by either source falls back to the default listed below.

Environment Variable Naming​

  • Top-level fields: HASTE_<FIELD> — e.g. HASTE_API_URI, HASTE_CERTIFICATION_DIR, HASTE_MAX_REQUEST_BODY_SIZE.
  • Nested sections: HASTE_<SECTION>.<field> — the prefix plus the section name, then a literal dot, then the field name exactly as it appears in TOML (lowercase) — e.g. HASTE_REPO.database_url, HASTE_SEARCH.username, HASTE_SECURITY.publicize_fhir_metadata.
  • Sections that select a backend/provider via a tag (repo, search, email, security.encryption) need that tag set too, e.g. HASTE_REPO.backend=postgres.

Reference​

Top level​

KeyEnv varDefaultNotes
api_uriHASTE_API_URIhttp://localhost:3000Root URL the FHIR server is hosted at; used to build absolute URLs (OIDC discovery, FHIR base URLs, etc).
certification_dirHASTE_CERTIFICATION_DIRcertificationsDirectory used for JWT signing/verification key material.
admin_app_redirect_uriHASTE_ADMIN_APP_REDIRECT_URIhttp://*.localhost:3001Redirect target for the hardcoded admin app OIDC client.
allow_artifact_mutationsHASTE_ALLOW_ARTIFACT_MUTATIONSfalseAllows mutating built-in/embedded artifact resources.
max_request_body_sizeHASTE_MAX_REQUEST_BODY_SIZE4194304 (4MB)Max accepted request body size, in bytes.
portHASTE_PORT3000Port the server listens on.

[fhir]​

KeyEnv varDefault
fhir.delete_limitHASTE_FHIR.delete_limit100 — max resources removed by a single type/system-level delete.

[repo] — resource storage backend​

Tagged by backend; only postgres exists today.

KeyEnv varDefault
repo.backendHASTE_REPO.backendpostgres
repo.database_urlHASTE_REPO.database_urlpostgresql://postgres:postgres@127.0.0.1/haste_health
repo.max_connectionsHASTE_REPO.max_connections20

[search] — search index backend​

Tagged by backend; two backends exist: elasticsearch (the default) and postgres (search indexed in the same Postgres server as [repo], no Elasticsearch cluster required).

backend = "elasticsearch" (default):

KeyEnv varDefault
search.urlHASTE_SEARCH.urlhttp://localhost:9200
search.usernameHASTE_SEARCH.usernameelastic
search.passwordHASTE_SEARCH.passwordelastic
search.prune_removed_search_parametersHASTE_SEARCH.prune_removed_search_parametersfalse — lets migrate search drop the mapping (and indexed data) for a removed search parameter. Off by default: removed parameters are logged, never deleted, since Elasticsearch mappings are append-only and dropping one needs a reindex.

backend = "postgres":

KeyEnv varDefault
search.database_urlHASTE_SEARCH.database_urlpostgresql://postgres:postgres@127.0.0.1/haste_health_search — a separate database from [repo]'s
search.max_connectionsHASTE_SEARCH.max_connections20

[email] — optional​

None/absent by default (email sending disabled). Tagged by backend; only sendgrid exists today.

KeyEnv var
email.backendHASTE_EMAIL.backend (sendgrid)
email.api_keyHASTE_EMAIL.api_key
email.from_addressHASTE_EMAIL.from_address

[rate_limits]​

KeyEnv varDefault
rate_limits.rate_limit_subscription_tiersHASTE_RATE_LIMITS.rate_limit_subscription_tiersunset — a 4-element array, one limit per subscription tier (Free/Professional/Team/Unlimited).
rate_limits.rate_limit_window_secondsHASTE_RATE_LIMITS.rate_limit_window_seconds86400 (1 day)
rate_limits.rate_limit_operation_pointsHASTE_RATE_LIMITS.rate_limit_operation_points100

[monitoring]​

KeyEnv varDefault
monitoring.audit_enabledHASTE_MONITORING.audit_enabledfalse — gates the auditing middleware.
monitoring.ip_sourceHASTE_MONITORING.ip_sourceconnect_info — one of connect_info, cf_connecting_ip, x_real_ip; how client IP is derived.

[security]​

KeyEnv varDefault
security.publicize_fhir_metadataHASTE_SECURITY.publicize_fhir_metadatatrue — exposes /fhir/{version}/metadata without authentication. Set to false to require auth on the capability statement.
security.aes_keyHASTE_SECURITY.aes_keyunset
security.certification_keyHASTE_SECURITY.certification_keyunset

[security.mfa]​

KeyEnv varDefault
security.mfa.max_credentials_per_userHASTE_SECURITY.mfa.max_credentials_per_user1

[security.encryption] — secret provider for aes_key / certification_key​

Tagged by type: environment (default), gcp, or aws.

KeyEnv varDefault
security.encryption.typeHASTE_SECURITY.encryption.typeenvironment
security.encryption.prefix (environment only)HASTE_SECURITY.encryption.prefixHASTE_SECRET_
security.encryption.project_id (gcp only)HASTE_SECURITY.encryption.project_id—
security.encryption.region (aws only)HASTE_SECURITY.encryption.region—

[operations]​

KeyEnv varDefaultNotes
operations.deno_pool_threadsHASTE_OPERATIONS.deno_pool_threadsRoughly half the host's available parallelism (minimum 2)Dedicated OS threads executing custom (tenant-authored) FHIR operation scripts in isolated Deno/V8 sandboxes. Each thread runs one script at a time — this is a hard ceiling on concurrent custom-operation invocations.

Example haste.toml​

api_uri = "http://localhost:3000"
certification_dir = "certifications"
admin_app_redirect_uri = "http://*.localhost:3001"
max_request_body_size = 20971520 # 20MB

[repo]
backend = "postgres"
database_url = "postgresql://postgres:postgres@localhost:5432/haste_health"
max_connections = 20

[search]
backend = "elasticsearch"
url = "http://localhost:9200"
username = "elastic"
password = "elastic"

# Alternative to the [search] block above -- no Elasticsearch cluster needed:
# [search]
# backend = "postgres"
# database_url = "postgresql://postgres:postgres@127.0.0.1/haste_health_search"
# max_connections = 20

[operations]
deno_pool_threads = 4

[monitoring]
audit_enabled = false

[security]
publicize_fhir_metadata = true
aes_key = "AES_KEY"
certification_key = "CERTIFICATE_KEY"

[security.mfa]
max_credentials_per_user = 1

[security.encryption]
type = "environment"
prefix = "HASTE_SECRET_"

Example Environment Variables (Container Deployment)​

HASTE_API_URI=http://localhost:3000
HASTE_CERTIFICATION_DIR=certifications
HASTE_ADMIN_APP_REDIRECT_URI=http://*.localhost:3001

HASTE_REPO.backend=postgres
HASTE_REPO.database_url=postgresql://postgres:postgres@postgres:5432/haste_health
HASTE_REPO.max_connections=20

HASTE_SEARCH.backend=elasticsearch
HASTE_SEARCH.url=http://elasticsearch:9200
HASTE_SEARCH.username=elastic
HASTE_SEARCH.password=elastic