13.17.1Externalized Resource Body Storage
Experimental

 
This feature is currently provided as an early preview for testing, and will be changed in upcoming releases. Do not use this feature in production environments.

FHIR resource bodies (JSON payloads) are stored by default in the database. However, in systems that manage high volumes of resources or require more cost-effective storage, it is possible to externalize resource body storage to an object storage system such as Amazon S3, MinIO, or Azure Blob Storage. This is especially useful for high-volume databases, enabling up to 20% storage savings depending on the selected resource body offload mode and the number of resource bodies stored in the database.

Externalized resource storage is controlled by two configuration parameters:

The following sections describe options for resource body offload:

13.17.1.1Resource Body Offload Mode: OFF (Default)

By default, saving resource body to external storage is disabled, all resource body content is stored in the relational database.

13.17.1.2Resource Body Offload Mode: SAVE

In this mode, all resource body content continues to be stored in the database. Additionally, each newly created or updated resource is also saved to the configured external object storage system (e.g., S3, MinIO, or Azure Blob Storage). Resource bodies are not removed from the database, and the external storage acts as an archive. This setup allows the FHIR server to operate entirely from the database for reads, updates, searches, and retrieving historical versions of resources. It can serve as a foundation for future migration to offload modes that reduce database size.

13.17.1.3Resource Body Offload Mode: SAVE_AND_CLEAR_OLD

In this mode, all older versions of a resource (i.e., versions prior to the latest version) are moved to the configured external object storage system (e.g., S3, MinIO, or Azure Blob Storage) and removed from the relational database. The latest version is saved to external storage as well, but it remains in the database. This setup reduces database size while preserving quick access to the most recent resource body version. Historical versions are retrieved on demand from external storage when needed (e.g., via the _history operation). This mode offers an optimal balance between minimizing database storage and maintaining high performance for read, update, and search operations.

13.17.1.4Resource Body Offload Mode: SAVE_AND_CLEAR_ALL

In this mode, all resource body versions, including the latest, are moved to the configured external object storage system (e.g., S3, MinIO, or Azure Blob Storage), and none are stored in the database. Only resource metadata remains in the relational database, significantly reducing its size. All resource bodies must be retrieved from external storage when needed, including for reads, updates, or historical access. This mode offers maximum storage efficiency and is best suited for systems where minimizing database storage is a priority and latency introduced by external storage is acceptable. Note that read, update, and search operations may be slower due to network overhead and object storage performance.

The following sections describe options for resource body storage:

13.17.1.5Resource Body Storage Mode: Database (Default)

By default, all resource body content is stored in the database, including all historical versions as well as resource metadata.

This provides efficient reads, writes, and searches. However, as the number of resources and versions grows, database size can increase significantly.

13.17.1.6Resource Body Storage Mode: AWS S3

In this mode, FHIR resource bodies are stored in an AWS S3 bucket. Resource bodies will be stored in one bucket, which can be named via the Blob Service Bucket / Container property. You can also configure the region by setting the Blob Service Region property. On boot, Smile CDR will create a bucket if it does not already exist.

Authentication to S3 is done using the DefaultAwsCredentialsProviderChain. This means that credentials can be provided in a variety of ways, including:

  • Environment Variables
  • Java System Properties
  • Credential Profiles File

However, you also have the option to provide your own credentials via the Blob Service S3 Access Key property and the Blob Service S3 Secret Key property. If credentials are provided in this fashion, they will be used instead of the default credentials.

The account you authenticate with will need permissions to create buckets, as well as to put/head/get/delete objects in the bucket.

13.17.1.7Resource Body Storage Mode: MinIO

In this mode, resource bodies are stored in a MinIO server. All data will be stored in one bucket, which can be named via the Blob Service Bucket / Container property.

Authentication for MinIO must be provided via the Blob Service S3 Access Key and Blob Service S3 Secret Key properties.

Currently, MinIO is only recommended for development purposes.

13.17.1.8Resource Body Storage Mode: Azure Blob Storage

In this mode, resource bodies are stored in an Azure Blog Storage container. All data will be stored in one container, which can be named via the Blob Service Bucket / Container property. You can also configure the account name by setting the Blob Service Azure Account property. On boot, Smile CDR will create a container if it does not already exist.

There are three different supported authentication methods:

  1. Access Key
  2. Account-level Shared Access Signatures (SAS) token
  3. Azure Active Directory

The authenticated account will need permissions to create containers, as well as to PUT/HEAD/GET/DELETE objects in the container.

13.17.1.9Blob Service Path Prefix For Resource Body Storage

When resource bodies are stored in an external object storage system (e.g., S3, MinIO, or Azure Blob Storage), each version is written using a path format provided below:

{resource_type}/{fhir_id}/_history/{resource_version}

Example Path:

Patient/1706/_history/5

This corresponds to storing the fifth version of a Patient resource with FHIR ID 1706. A mandatory Blob Service Path Prefix is required be configured to prepend a logical folder structure to all object keys. For example, if the prefix is set to fhir-resource-body/dev, the full object key becomes:

fhir-storage/dev/Patient/1706/_history/5

This is required as storage bucket for resource bodies is shared with Externalized Binary Storage.

13.17.1.10Performance And Storage Implications

When enabling externalize resource body storage, consider the following operational impacts:

  • Moving resource bodies to external storage introduces additional database load and processing overhead. Each create or update operation requires both saving to the database and writing to external storage, which may increase overall system load.
  • When a resource body is externalized, it is first written to the database and then saved to external storage. Depending on the database engine, the space used by the removed data may not be reclaimed immediately. Additional maintenance (e.g., VACUUM/ VACUUM FULL operations for PostgreSQL etc.) may be required to recover disk space.

13.17.1.11Limitations

  • Externalizing resource bodies is only supported for relational database backends (e.g., PostgreSQL, MSSQL, Oracle). MongoDB is not supported for this feature.
  • During search operations in SAVE_AND_CLEAR_ALL mode, resource bodies are retrieved sequentially from external storage. As this process is not asynchronous, it may result in slower search performance compared to modes where resource bodies are stored in the database.

13.17.2Implementation Roadmap

 

Externalized Resource Body Storage functionality is under active development. Below is a roadmap of planned features.

13.17.2.1November 2025 Release

  • Asynchronous reading of resource bodies during search to improve performance when the latest resource bodies are stored externally.
  • System-level batch job to allow triggering the migration of existing resource bodies from the database to external storage.