Documentation / Exploitation / Référence / Environment variables

Environment variables

This page lists every environment variable read by the Meridian runtime processes, the process(es) that read each one, its role, and its default. It mirrors the code; where a variable's behaviour matters, the source file is cited.

The processes referred to below are:

Process Entry point Log/service name Default PORT
proxy (runtime API) apps/api/src/server/api.ts meridian-proxy 4000
endpoint (Restate services) apps/api/src/restate/server.ts meridian-endpoint 9080
ui (ehr-lab mini-EHR) apps/ehr-lab (Next.js) 3000

For the deployment topology these processes form, see Topology.

.env loading

Both proxy and endpoint import apps/api/src/env.ts first. It reads a .env file at the repository root (path resolved relative to the module) if one exists, and copies each KEY=value line into process.env only when the key is not already set — an explicit export FOO=bar in the shell always wins (apps/api/src/env.ts). Lines starting with # and malformed keys are ignored; surrounding single or double quotes on the value are stripped. There is no dotenv dependency.

The ehr-lab app loads the same repository-root .env through its own loader (apps/ehr-labsrc/infrastructure/env.ts).

Consequences:

  • In a checkout, copy .env.example to .env at the repo root and restart the process after any change.
  • In a container/Kubernetes deployment, inject variables through the service environment (compose env_file/environment, or a Secret) rather than copying a .env. Instance manifests are version-controlled and must never contain secrets — see Security posture.

Instance and plugin resolution

Read by both proxy and endpoint at boot.

Variable Process(es) Role Default
INSTANCE_CONFIG proxy, endpoint Path to the instance manifest. Relative paths resolve from the repo root. Absent → instance.yaml at the repo root; if that is also missing, an empty instance (all-internal/in-memory dev default). A path that is set but missing fails the boot loudly. instance.yaml
PLUGINS_PATH proxy, endpoint Extra roots holding external compiled plugins, split on , or the OS path delimiter. Relative entries resolve from the process cwd. (empty)
MERIDIAN_REGISTRY proxy, endpoint Default plugin registry used to resolve instance-declared plugins when the manifest has no registry: key. Accepts gs://bucket[/prefix], file://…, or a repo-relative directory. (none)
MERIDIAN_PLUGIN_CACHE proxy, endpoint Local cache directory for plugins downloaded from the registry. Relative paths resolve from the repo root. .data/plugins

The manifest's own registry: key takes precedence over MERIDIAN_REGISTRY; a plugin listed with a local path bypasses the registry entirely (apps/api/src/registry.ts). A declared plugin that cannot be resolved fails the boot. See Set up a plugin registry, Declare and install plugins, and the Instance manifest reference.

Restate wiring

Variable Process(es) Role Default
RESTATE_URL proxy Restate ingress URL. Required — the proxy throws at startup if it is unset, because execution runs through Restate. A trailing slash is stripped. (required)
RESTATE_ADMIN_URL endpoint Restate admin API used for auto-registration (POST {admin}/deployments). A trailing slash is stripped. http://localhost:9070
RESTATE_ENDPOINT_URL endpoint URI under which the Restate server reaches this endpoint (advertised at registration). http://host.docker.internal:<endpoint PORT>
RESTATE_AUTO_REGISTER endpoint Set to the literal false to disable auto-registration; any other value (or unset) leaves it enabled. (enabled)
API_INTERNAL_URL endpoint Where the endpoint reaches the REST proxy to ingest schedule ticks (trigger.schedule, service meridianScheduler). Must point at the proxy in any multi-container deployment, or planned workflows never start. http://localhost:4000

The endpoint (re)registers its deployment on every start, idempotently (force: true) and with retry (up to ~3 min), so a manual registration step is not needed and the endpoint may start before the Restate server (apps/api/src/restate/register.ts). The registered services are generic and fixed (meridianWorkflow, record, meridianScheduler), so creating or editing a workflow never requires re-registration. See Restate integration and Why durable execution.

Run index (run store)

Read by the proxy.

Variable Process(es) Role Default
RUN_DB_URL proxy Backend for the persistent run index. sqlite:<path> (local / single node) or postgres://… / postgresql://… (deployment / multiple proxy replicas). An unrecognised prefix throws. sqlite:.data/runs.sqlite
DEFINITION_STORE_URL endpoint, proxy Required (postgres://…): the workflow/agent definition store. Falls back to RUN_DB_URL when that one is Postgres — the tables are disjoint, one database is enough. Boot fails with an explicit message if neither is set. See Manage workflow storage.
DEFINITION_SEED_DIR proxy Directory of the host's system definitions, imported as published v1 when the store is empty (default: apps/api — it carries only agent-invoke.workflow.yaml). Shipped content (demos, business workflows) is seeded through the instance manifest's seed: field instead — see Instance manifest.
DEFINITION_SEED_ALWAYS proxy 1 re-publishes the seed directory at every boot (idempotent by content hash), so editing a YAML and restarting puts it live. Development only — elsewhere it would overwrite definitions edited in the console.

The default path is relative to the process cwd, so set it explicitly (absolute path / mounted volume) in a deployment. The index only lists the runs the proxy started; the durable source of truth is Restate, so losing the index erases no runs (apps/api/src/server/run-store.ts). The SQLite driver (better-sqlite3) and the Postgres driver (pg) are imported lazily, so only the selected one is loaded. See Run store, Use a Postgres run index, and Back up and restore.

Ports and inter-process URLs

Variable Process(es) Role Default
PORT proxy, endpoint, ui Listening port. 4000 (proxy) / 9080 (endpoint) / 3000 (ui)
API_URL ui Proxy base URL used by ehr-lab for server-side requests. (deployment-specific)

The endpoint's PORT also feeds the default RESTATE_ENDPOINT_URL (apps/api/src/restate/server.ts, register.ts). See Configure ports and adapters.

Logging

Read by both proxy and endpoint via apps/api/src/observability/logger.ts (pino).

Variable Process(es) Role Default
LOG_LEVEL proxy, endpoint Pino level: trace, debug, info, warn, error. info
LOG_PRETTY proxy, endpoint 1 forces human-readable output; 0 forces JSON. Pretty when stdout is a TTY and NODE_ENV !== "production", JSON otherwise
SERVICE_NAME proxy, endpoint Service field stamped on log lines. Also set by each entry point via initLogger. meridian

Structured logs never contain patient payloads; a redaction list additionally censors common secret fields (*.authorization, *.apiKey, *.token, …).

Observability (OpenTelemetry)

Read by both proxy and endpoint via apps/api/src/observability/otel.ts. All OTel export is opt-in: with no OTLP endpoint set, the SDK is not started and the metric instruments are zero-cost no-ops.

Variable Process(es) Role Default
OTEL_EXPORTER_OTLP_ENDPOINT proxy, endpoint OTLP/HTTP collector endpoint (e.g. http://collector:4318). Presence enables traces + metrics + log export. (unset → export disabled)
OTEL_SERVICE_NAME proxy, endpoint Overrides the OTel service.name resource attribute. meridian-proxy / meridian-endpoint

The OTel service.version resource attribute is taken from npm_package_version (set by the package manager), defaulting to 0.0.0. When JSON logging is active and an OTLP endpoint is configured, logs are also shipped over OTLP. See Enable observability and Observability signals.

LLM providers

The shared low-level client (libs/llm-client/src/index.ts, @meridian/llm-client) resolves a provider's base URL and API key from the environment. It backs both the editor's workflow-generation assistant (llmComplete) and the agent runner (plugin @posos/llm). A provider is considered configured only when its API key is present; the assistant throws if called for an unconfigured provider, and an agent falls back to a mock runner when no key is set.

Variable Process(es) Role Default
ANTHROPIC_API_KEY proxy, endpoint Anthropic API key. (none)
ANTHROPIC_BASE_URL proxy, endpoint Anthropic base URL. https://api.anthropic.com
OPENAI_API_KEY proxy, endpoint OpenAI API key. (none)
OPENAI_BASE_URL proxy, endpoint OpenAI base URL. https://api.openai.com/v1
GEMINI_API_KEY proxy, endpoint Google Gemini API key (OpenAI-compatible endpoint). Falls back to GOOGLE_API_KEY. (none)
GOOGLE_API_KEY proxy, endpoint Fallback key for the gemini provider. (none)
GEMINI_BASE_URL proxy, endpoint Gemini base URL. https://generativelanguage.googleapis.com/v1beta/openai
MISTRAL_API_KEY proxy, endpoint Mistral API key (OpenAI-compatible). (none)
MISTRAL_BASE_URL proxy, endpoint Mistral base URL. https://api.mistral.ai/v1
AZURE_OPENAI_API_KEY proxy, endpoint Azure OpenAI API key. (none)
AZURE_OPENAI_BASE_URL proxy, endpoint Azure OpenAI deployment URL (full URL of the deployment). (empty)
LOCAL_LLM_API_KEY proxy, endpoint API key for a local OpenAI-compatible server (Ollama / vLLM / LM Studio). local
LOCAL_LLM_BASE_URL proxy, endpoint Base URL of the local LLM server. http://localhost:11434/v1

Workflow assistant

Read by the proxy for the editor's AI assistant endpoint (apps/api/src/server/api.ts).

Variable Process(es) Role Default
ASSIST_PROVIDER proxy Provider used by the workflow-generation assistant. anthropic
ASSIST_MODEL proxy Model used by the assistant. claude-sonnet-4-5

See Author an agent and Use the AI assistant.

Bundled-adapter fallbacks

These are read by adapters shipped with the bundled plugins only when the corresponding value is absent from the instance manifest's adapter config; config.baseUrl (etc.) in the manifest takes precedence. They apply to whichever process resolves the port (typically the endpoint for execution ports, the proxy for terminology). See Bundled plugins.

Variable Process(es) Role Default
FHIR_BASE_URL proxy, endpoint Base URL of the FHIR R4 server used by the @posos/fhir adapters when config.baseUrl is not provided. (none — error if neither is set)
HERMES_BASE_URL proxy, endpoint SNOMED CT terminology server (Hermes) used by the @posos/snomed adapter when config.baseUrl is not provided. http://localhost:8081
NOTIFY_WEBHOOK_URL proxy, endpoint Target URL for the @posos/notify webhook adapter when config.url is not provided. (none — error if neither is set)

See Connect a FHIR warehouse and Configure terminology.

Posos plugin (@posos/posos)

Read by the external Posos plugin client (external-plugins/posos/lib/client.ts) in whichever process loads it.

Variable Process(es) Role Default
POSOS_API_URL proxy, endpoint Posos edge API base URL. https://api.preprod.posos.co
POSOS_AUDIENCE proxy, endpoint OAuth client ID (IAP audience) for authenticated Posos calls. (preprod IAP audience)
POSOS_REGION proxy, endpoint Locale/region selector; fr-BE selects the Belgian client, anything else defaults to fr-FR. fr-FR
GOOGLE_APPLICATION_CREDENTIALS proxy, endpoint Google service-account key file, read by google-auth-library for IAP auth (also honours Application Default Credentials / Workload Identity Federation). (none)

ehr-lab (mini-EHR)

Read server-side by the ehr-lab app (apps/ehr-lab/.env.example); none are exposed to the browser. In development the localhost defaults apply; on a remote host they become required and must be injected through the service environment.

Variable Process(es) Role Default
FHIR_BASE_URL ui FHIR warehouse (Blaze) — the app's sole datastore (records, directory, messaging, audit, documents). http://localhost:8090/fhir (dev)
NODE_ENV ui, proxy, endpoint Standard Node environment; affects the logger's pretty/JSON default and the ehr-lab runtime. (unset)
GOOGLE_APPLICATION_CREDENTIALS ui Google service-account key (JSON) enabling Posos autocompletion, MedicalDB (BIM) dosage suggestions, Scan&Go partner-connect auth, and Google FHIR warehouse access. (none)
POSOS_API_URL ui Posos edge API base URL (autocomplete + bim-v2 GraphQL). https://api.preprod.posos.co
POSOS_AUDIENCE ui IAP audience; gates drug autocompletion and BIM dosage suggestions (labelled demo mode when absent); shared fallback for SCANGO_AUDIENCE. (preprod)
SCANGO_BASE ui Scan&Go partner-connect base URL. https://partner-connect.preprod.posos.co
SCANGO_COMPLETE_ORIGIN ui Expected postMessage origin for Scan&Go completion. https://scan-complete.preprod.posos.co
SCANGO_AUDIENCE ui IAP audience for Scan&Go. POSOS_AUDIENCE
SCANGO_FACILITY_SLUG ui Target fhirStore in the Google warehouse. hopital-demo
SCANGO_FHIR_BASE ui Google Healthcare fhirStores base URL. (none)
SCANGO_CREDENTIALS ui Service-account key file for Scan&Go. GOOGLE_APPLICATION_CREDENTIALS

The ehr-lab app does not talk to the proxy directly: clinical validations pass through the FHIR warehouse (a Task), and the two apps share only Blaze (FHIR_BASE_URL). See Connect a FHIR warehouse, Scan&Go / FHIR mapping (apps/ehr-lab/docs/resources/reference/fhir-mapping.md), and Set the instance locale.

75 documents13 sectionssource : /docs · généré au build