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

[signup]​

Self-service sign-up and login at /auth/signup and /auth/login.

Set signup.enabled = false on a deployment where visitors must not create tenants (workspaces) for themselves. /auth/signup then answers 403, the links to it are hidden, and an address with no account that logs in at /auth/login is told there is no account instead of being offered a new tenant. Login for existing users is unaffected, and tenants are created with haste-health admin tenant create.

KeyEnv varDefault
signup.enabledHASTE_SIGNUP.enabledtrue
signup.turnstile.site_keyHASTE_SIGNUP.turnstile.site_keyunset — with secret_key, adds a Cloudflare Turnstile bot check to the forms.
signup.turnstile.secret_keyHASTE_SIGNUP.turnstile.secret_keyunset

[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—

[packages]​

Settings for installing FHIR packages (implementation guides) with ImplementationGuide/$install. See Implementation Guides.

KeyEnv varDefaultNotes
packages.registry_urlHASTE_PACKAGES.registry_urlhttps://packages.fhir.orgThe FHIR package registry packages are fetched from. Must be https; redirects are followed only within it. Empty turns off fetching, so packages can only be uploaded.
packages.skip_dependenciesHASTE_PACKAGES.skip_dependencieshl7.terminology, hl7.terminology.r4, hl7.terminology.r5, us.nlm.vsac, us.cdc.phinvads, hl7.fhir.uv.xver-r5.r4, hl7.fhir.uv.xver-r4b.r4, hl7.fhir.uv.xver-r3.r4, hl7.fhir.uv.xver-r2.r4Packages not installed as a dependency. Naming one directly still installs it.
packages.max_package_bytesHASTE_PACKAGES.max_package_bytes20971520 (20 MiB)Largest package download or upload, compressed.
packages.max_filesHASTE_PACKAGES.max_files20000Most files in one package.
packages.max_install_packagesHASTE_PACKAGES.max_install_packages50Most packages one install fetches or uploads, dependencies included. A fetch that fails still counts.
packages.max_install_bytesHASTE_PACKAGES.max_install_bytes209715200 (200 MiB)Most the packages of one install may unpack to together, uploads included. Checked while unpacking. An install's peak memory is about four times this.
packages.max_concurrent_installsHASTE_PACKAGES.max_concurrent_installs1Installs one server runs at once. Another is refused with 429.
packages.free_tier_install_interval_secondsHASTE_PACKAGES.free_tier_install_interval_seconds120How often one Free tier tenant may start an install, in seconds. Another within this time is refused with 429. 0 turns the wait off.
packages.free_tier_shared_install_interval_secondsHASTE_PACKAGES.free_tier_shared_install_interval_seconds60How often any Free tier tenant may start an install, all of them together, in seconds. Another within this time is refused with 429. Set it well above how long one install takes. 0 turns the wait off.

[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