Introduction
Setting up a FHIR server from scratch is no small feat. The traditional route means provisioning backend infrastructure, configuring a database, building a CI/CD pipeline, managing server patches, and locking down networking with subnets, security groups, and ACLs — and that's before you've written a single line of application code.
AWS HealthLake cuts through all of that. It's a fully managed, HIPAA-eligible service that gives you a production-grade FHIR R4 repository without the operational overhead. In this guide, you'll learn how to spin one up, connect to it, and start working with real patient data using Postman — then see how to wire it into a live application.
Why HealthLake?
- Fully managed FHIR R4 infrastructure — no servers to patch or scale
- HIPAA-eligible with built-in encryption and access controls
- Sub-millisecond latency at petabyte scale
- SMART on FHIR support for standards-based authentication and authorization
- Automatic export to Apache Iceberg for SQL-on-FHIR analytics
- Built-in NLP to extract clinical context from unstructured medical text
Part 1: Provisioning Your HealthLake Data Store
Step 1 — Navigate to AWS HealthLake
Log in to your AWS Management Console and use the search bar at the top to search for HealthLake. Click on the AWS HealthLake result to open the service dashboard.
Step 2 — Open the Data Stores Panel
On the HealthLake landing page, click View Data Stores (or Create Data Store if you're starting fresh). This is your central hub for managing FHIR repositories.
Step 3 — Create a New Data Store
Click Create Data Store and fill in the configuration:
-
Data Store Name: Give it a meaningful name, e.g.
my-fhir-app - Format: Select FHIR R4. This is the data schema all your FHIR resources will conform to.
- Preload Sample Data (Optional): If you'd like to explore the service with synthetic patient data right away, enable this. The data is generated by Synthea — a realistic but fictional patient population. Note: enabling this adds 10–20 minutes to initialization time.
Step 4 — Configure Encryption
Under Data Store encryption, you have two options:
- AWS Owned Key (Default): AWS manages the key on your behalf. This is the quickest option and appropriate for most use cases.
- Customer Managed Key (Advanced): Bring your own AWS KMS key if your compliance requirements demand it. This gives you full key lifecycle control.
Tip: For most development and production workloads, the AWS-owned key is sufficient. Use a customer-managed key only if your security policy requires explicit key rotation or audit trails.
Step 5 — Add Tags (Optional)
Tags are key-value metadata labels, useful for cost allocation, access policies, and resource organization — for example Environment: production or Team: clinical-apps. Skip this for quick experiments.
Step 6 — Create and Wait
Click Create Data Store. Provisioning typically takes between 10 and 30 minutes. The status will show as Creating during this time.
Note: HealthLake is spinning up dedicated infrastructure for your FHIR repository. You can stay on the Data Stores page and refresh periodically to check progress.
Step 7 — Copy Your Endpoint
Once the status changes to Active, open the data store details. You'll see:
- Data Store ID
- ARN (Amazon Resource Name)
- Endpoint — this is the FHIR base URL you'll use for all API calls
Copy the endpoint. It will look something like this:
https://healthlake.us-east-1.amazonaws.com/datastore/<YOUR_DATASTORE_ID>/r4/
Part 2: Testing Your FHIR Endpoint with Postman
Before wiring HealthLake into your application, it's good practice to validate the endpoint manually. Postman is ideal for this — it supports AWS Signature V4 authentication out of the box, which HealthLake requires.
Authentication: AWS Signature V4
HealthLake uses IAM-based authentication. Every request must be signed using AWS Signature V4. In Postman, this is handled automatically once configured.
Open the Authorization tab in your Postman request and set the following:
| Field | Value |
|---|---|
| Auth Type | AWS Signature |
| AccessKey | Your IAM Access Key ID |
| SecretKey | Your IAM Secret Access Key |
| AWS Region |
us-east-1 (or your deployment region) |
| Service Name | healthlake |
IAM: Make sure the IAM identity you're using has the
AmazonHealthLakeFullAccesspolicy attached, or at minimum thehealthlake:CreateResourceandhealthlake:ReadResourceactions scoped to your data store's ARN.
Creating a Patient Resource (POST)
Set up your Postman request as follows:
-
Method:
POST -
URL:
https://healthlake.us-east-1.amazonaws.com/datastore/<YOUR_DATASTORE_ID>/r4/Patient -
Headers:
Content-Type: application/json - Body: Raw JSON
{
"resourceType": "Patient",
"id": "example-patient-1",
"name": [{
"use": "official",
"family": "Doe",
"given": ["John"]
}],
"gender": "male",
"birthDate": "1990-05-15",
"telecom": [{
"system": "phone",
"value": "+2348012345678",
"use": "mobile"
}],
"address": [{
"city": "Lagos",
"country": "Nigeria"
}]
}
Hit Send. A successful response returns HTTP 201 Created with the full resource body, including a server-generated UUID as the resource ID and a meta.lastUpdated timestamp — confirming your record was persisted.
Reading a Patient Resource (GET)
To retrieve the patient you just created, use the resource ID from the 201 response:
GET .../r4/Patient/<RESOURCE_ID>
You can also search across all patients using query parameters:
# Search by family name
GET .../r4/Patient?family=Doe
# Search by birthdate
GET .../r4/Patient?birthdate=1990-05-15
# Get all patients (paginated)
GET .../r4/Patient
Updating a Patient Resource (PUT)
To update an existing patient, use a PUT request with the full updated resource body:
PUT .../r4/Patient/<RESOURCE_ID>
HealthLake performs a full replace — not a partial update. For partial updates, use the PATCH method with a FHIR Patch document.
Deleting a Resource (DELETE)
DELETE .../r4/Patient/<RESOURCE_ID>
Note: HealthLake soft-deletes resources by default — they're marked as deleted but remain in the audit trail. This supports HIPAA compliance requirements around data retention and auditability.
Part 3: Using HealthLake in a Live Application
Now that you've confirmed the endpoint works, let's integrate HealthLake into a real application. We'll use Node.js with the AWS SDK v3, which handles Signature V4 signing automatically.
Setup: Install Dependencies
npm install @aws-sdk/client-healthlake
npm install @aws-sdk/signature-v4
npm install axios
npm install @aws-sdk/credential-provider-node
Initializing the AWS HTTP Client with SigV4 Signing
Rather than using the HealthLake SDK client (which has limited FHIR-specific support), the recommended approach is to sign requests manually using the AWS HTTP signing library, then use any HTTP client to call the endpoint directly.
const { SignatureV4 } = require('@aws-sdk/signature-v4');
const { defaultProvider } = require('@aws-sdk/credential-provider-node');
const { Sha256 } = require('@aws-crypto/sha256-js');
const axios = require('axios');
const REGION = 'us-east-1';
const DATASTORE_ID = process.env.HEALTHLAKE_DATASTORE_ID;
const BASE_URL = `https://healthlake.${REGION}.amazonaws.com/datastore/${DATASTORE_ID}/r4`;
async function signedRequest(method, path, body = null) {
const credentials = await defaultProvider()();
const signer = new SignatureV4({
credentials,
region: REGION,
service: 'healthlake',
sha256: Sha256
});
const url = new URL(`${BASE_URL}${path}`);
const request = {
method,
hostname: url.hostname,
path: url.pathname + url.search,
headers: {
host: url.hostname,
'content-type': 'application/json',
},
body: body ? JSON.stringify(body) : undefined
};
const signed = await signer.sign(request);
return axios({
method,
url: url.toString(),
headers: signed.headers,
data: body
});
}
Creating a Patient from Your App
async function createPatient(patientData) {
const response = await signedRequest('POST', '/Patient', patientData);
console.log('Created patient:', response.data.id);
return response.data;
}
// Usage
createPatient({
resourceType: 'Patient',
name: [{ use: 'official', family: 'Adeyemi', given: ['Amara'] }],
gender: 'female',
birthDate: '1988-03-22',
address: [{ city: 'Abuja', country: 'Nigeria' }]
});
Searching for Patients
async function searchPatients(params) {
const query = new URLSearchParams(params).toString();
const response = await signedRequest('GET', `/Patient?${query}`);
const bundle = response.data;
console.log(`Found ${bundle.total} patients`);
return bundle.entry?.map(e => e.resource) ?? [];
}
// Search by name
const patients = await searchPatients({ family: 'Adeyemi' });
Environment Configuration
Store your configuration in environment variables — never hardcode credentials:
# .env
AWS_REGION=us-east-1
AWS_ACCESS_KEY_ID=your_access_key
AWS_SECRET_ACCESS_KEY=your_secret_key
HEALTHLAKE_DATASTORE_ID=your_datastore_id
Security: In production, use IAM roles attached to your EC2/ECS/Lambda instance instead of static credentials. This avoids storing secrets entirely and is the AWS-recommended approach.
Production Best Practices
IAM Least Privilege
Create a dedicated IAM role for your application with only the HealthLake permissions it needs. Avoid attaching broad policies like AdministratorAccess.
Error Handling
HealthLake returns standard FHIR OperationOutcome resources on errors. Parse these to surface meaningful messages to your logs:
try {
const result = await signedRequest('POST', '/Patient', patient);
} catch (err) {
if (err.response?.data?.resourceType === 'OperationOutcome') {
const issues = err.response.data.issue;
issues.forEach(i => console.error(`[${i.severity}] ${i.diagnostics}`));
}
}
SMART on FHIR for Multi-Tenant Apps
If you're building a patient-facing or clinician-facing application that needs OAuth2-based access control, HealthLake supports SMART on FHIR. This lets you scope access tokens to specific patients, resource types, and operations — a key requirement for EHR integrations.
Wrapping Up
AWS HealthLake removes the infrastructure complexity from FHIR development. Instead of managing servers, databases, and networking, you can focus on building healthcare applications that matter.
Here's a recap of what you've covered:
- Provisioned a fully managed FHIR R4 data store on AWS HealthLake
- Configured AWS Signature V4 authentication in Postman
- Created, read, updated, and deleted FHIR Patient resources via REST
- Integrated the HealthLake endpoint into a Node.js application
- Applied security and production best practices
From here, you can explore other FHIR resource types — Observation, Encounter, Condition, MedicationRequest — and start building out a full clinical data platform, all without a single server to manage.





Top comments (0)