This server provides a set of server-side services that are useful for the FHIR Community. The set of are two kinds of services:
- (Coming) R4/R6 interconverter
- terminology server (as running on tx.fhir.org)
- SHL Server - SHL/VHL support services (running on healthintersections.com.au, supporting the ICVP demo and and the Patient Document Generator)
- TX Registry - Terminology System Registry as described by the terminology ecosystem specification (as running at http://tx.fhir.org/tx-reg). Its API is described by an OpenAPI 3.1 spec at
/tx-reg/openapi.json(and.yaml), with a browsable reference at/tx-reg/openapi - Package server - NPM-style FHIR package registry with search, versioning, and downloads, consistent with the FHIR NPM Specification (as running at http://packages2.fhir.org/packages). Its API is described by an OpenAPI 3.1 spec at
/packages/openapi.json(and.yaml), with a browsable reference at/packages/openapi - XIG server - Comprehensive FHIR IG analytics with resource breakdowns by version, authority, and realm (as running at http://packages2.fhir.org/packages)
- Publisher - FHIR publishing services (as running at healthintersections.com.au)
- Testing - TestReport repository: receives FHIR TestReports from TxTester and other test tools, with a FHIR API and web pages (as running at https://npm.fhir.org/testing). Its API is described by an OpenAPI 3.1 spec at
/testing/openapi.json(and.yaml), with a browsable reference at/testing/openapi - VCL - Parse VCL expressions into FHIR ValueSet resources (as running at http://fhir.org/vcl)
- (Coming) Token services
- Maintainers: Grahame Grieve, Italo Macêdo, Josh Mandel, Jose Costa Teixeira
- Issues / Discussion: Use github issues
- License: BSD-3
- Contribution Policy: Make PRs. PRs have to pass all the tests
- Security Information: See security.md
Note: In production, this server always runs behind an nginx reverse proxy, so there's no in-build support for SSL, rate limiting etc. See nginx.md for how to configure it.
There are 4 executable programs:
- the server (
node server) - the terminology importer (
node --max-old-space-size=8192 tx/importers/tx-import XXX) - see Doco - the test cases (
npm test) - the test cases generater (
node tx/tests/testcases-generator.js)
Unless you're developing, you only need the first two
FHIRsmith is open source - see below, and you're welcome to use it for any kind of use. Note, though, that if you support FHIRsmith commercially as part of a managed service or product, you are required to be a Commercial Partner of HL7 - see (link to be provided).
- Install FHIRSmith (using docker, or an NPM release, or just get the code by git)
- Figure out the data directory
- Provide a configuration to tell the server what to run (see documentation below, or use a [prebuilt configuration]/configurations/readme.md)
- Run the server
For further details of these steps, read on
The server separates code from runtime data. All databases, caches, logs, and downloaded files are stored in a single data directory. The location is determined by:
- The
FHIRSMITH_DATA_DIRenvironment variable (if set) - Otherwise, defaults to
./datarelative to the working directory (development set up)
The data directory contains (depending on which modules are in use):
config.json— server and module configurationlogs/— server and nginx log filesterminology-cache/— downloaded terminology packages and FHIR packagespackages/— package server databasexig/— XIG databaseshl/— SHL databases and certificatesregistry/— registry crawler datapublisher/— publisher database and build workspacetoken/— token database
During development with a cloned repository, the data directory defaults to [root]/data
(the test cases require this setup). When deployed via Docker or npm, the data directory
is provided by the host — see Deployment below.
- Node.js 24+
- NPM or Yarn
- Java 17+ (for FHIR validator, also for the test cases)
These instructions are for Development. For deployment, see below.
# Clone the repository
git clone https://github.com/HealthIntersections/FHIRsmith
cd FHIRsmith
# Install dependencies
npm install
# Create required directories
mkdir -p data data/logs
# Copy example configuration
cp config.example.json data/config.json
# Edit configuration as needed
nano data/config.jsonEach Module has it's own entry in the config, as described by the module
Create a config.json file in your data directory (use config-template.json as a starting point):
{
"hostName" : "[descriptive name for the server]",
"server": {
"port": 3000,
"cors": {
"origin": "*",
"credentials": true
}
},
"modules": {
// per modules...
}
}Add a logging section to config.json to control log behaviour. All fields are optional and have sensible defaults:
{
"logging": {
"level": "info",
"console": true,
"consoleErrors": false,
"maxFiles": 14,
"maxSize": "50m",
"flushInterval": 2000,
"flushSize": 200
}
}| Option | Default | Description |
|---|---|---|
level |
"info" |
Minimum level to log: error, warn, info, debug, or verbose |
console |
true |
Write log lines to stdout/stderr. Disable when running as a systemd service where console output goes to the journal and is redundant |
consoleErrors |
false |
Whether error and warn levels appear on the console. When false, errors and warnings are written to the log file only |
maxFiles |
14 |
Number of daily log files to retain before old ones are deleted |
maxSize |
0 (unlimited) |
Maximum size per log file before rotation. Accepts human-readable strings: "20m", "1g", or a raw byte count |
flushInterval |
2000 |
Milliseconds between buffered writes to disk. Increase to reduce I/O under heavy load |
flushSize |
200 |
Number of buffered log lines that trigger an immediate flush regardless of the timer |
Log files are written to the logs/ subdirectory of the data directory as server-YYYY-MM-DD.log. A server.log symlink always points to the current day's file, so tail -f data/logs/server.log tracks the active log without needing to know the date.
# Development mode
npm run dev
# Production mode
npm startThe server will be available at http://localhost:{port} using the port specified in the config.
In the production servers listed above, the server always sits behind an NGINX server which manages
SSL, security, rate limiting etc. See nginx.md for configuration advice, including
running several servers behind one front door.
npm testThere are three deployment options: npm global install, Docker, or clone-and-run. All three
use the FHIRSMITH_DATA_DIR environment variable to locate the data directory.
# Install globally
npm install -g fhirsmith
# Create a data directory
mkdir -p /var/lib/fhirsmith
cp node_modules/fhirsmith/config-template.json /var/lib/fhirsmith/config.json
# Edit config.json as needed
# Set the data directory and run
export FHIRSMITH_DATA_DIR=/var/lib/fhirsmith
fhirsmithOr run it inline:
FHIRSMITH_DATA_DIR=/var/lib/fhirsmith fhirsmithSome of FHIRsmith's dependencies (the SQLite drivers) are native modules, built for the
version of Node.js that installed them. After upgrading Node.js, rebuild them - npm rebuild
in the FHIRsmith folder, or npm rebuild -g fhirsmith for a global install - or reinstall
FHIRsmith. Otherwise the server stops at startup with "compiled against a different Node.js
version". (With nvm, each Node.js version has its own global packages, so install FHIRsmith
again under the new version.) Docker images aren't affected.
The server is available as a Docker image. Mount a host directory as the data directory:
# Pull the latest image
docker pull ghcr.io/healthintersections/fhirsmith:latest
# Create and populate data directory on host
mkdir -p /path/to/data
cp config-template.json /path/to/data/config.json
# Edit config.json as needed
# Run with data directory mounted
docker run -d --name fhirsmith \
-p 3000:3000 \
-e FHIRSMITH_DATA_DIR=/app/data \
-v /path/to/data:/app/data \
ghcr.io/healthintersections/fhirsmith:latestAvailable tags:
latest: Latest stable releasevX.Y.Z: Specific version (e.g.,v1.0.0)cibuild: Latest build from the main branch
| Variable | Description | Default |
|---|---|---|
FHIRSMITH_DATA_DIR |
Path to the data directory | ./data |
PORT |
Server port (overrides config) | from config.json |
NODE_ENV |
Node environment | production |
You can install as a windows service using windows-install.js. You might need to hack that.
This project follows Semantic Versioning and uses a CHANGELOG.md file to track changes.
Each GitHub Release includes:
- Release notes extracted from CHANGELOG.md
- Source code archives (zip and tar.gz)
- Docker images pushed to GitHub Container Registry:
ghcr.io/healthintersections/fhirsmith:latestghcr.io/healthintersections/fhirsmith:vX.Y.Zghcr.io/healthintersections/fhirsmith:X.Y.Z
- npm package published to npmjs.org as
fhirsmith
Release images carry OCI labels, so an image says which release it is without having to trust the tag it was pulled under:
docker inspect --format '{{json .Config.Labels}}' ghcr.io/healthintersections/fhirsmith:latestorg.opencontainers.image.version is the release, .revision the commit it was
built from, and .source is what links the package to this repository on GHCR.
Server administrators should follow releases: a server is only as safe as the release it runs.
- Email: on the GitHub repository, choose Watch → Custom → Releases. Each release is emailed with its notes (needs a GitHub account)
- Atom feed:
https://github.com/HealthIntersections/FHIRsmith/releases.atom- each entry carries the release notes, for a feed reader or a Slack/Teams feed integration - The server itself: once a day the server looks up the latest release on npm, and the
dashboard says whether a newer one is available (this is part of the npm audit check, so
npmAudit.enabled = falseturns it off too)
Every push to main also publishes :cibuild and :cibuild-<sha> to the same
package. These are not releases - they are whatever was last merged. The
Docker Build workflow prunes all but the ten most recent afterwards, so they do
not bury the current release on the package page. To prune by hand (or to run
the one-off backfill of images published before that job existed), run the
GHCR Cleanup workflow from the Actions tab with dry_run on first, read the
log, then run it again with dry_run off.
GitHub Actions will automatically:
- Run tests
- Create a GitHub Release with notes from CHANGELOG.md
- Build and publish Docker images with appropriate tags
Prerequisites:
- All tests passing on main branch
- CHANGELOG.md updated with changes
Steps:
- Update
CHANGELOG.mdwith your changes under a new version section:
## [vX.Y.Z] - YYYY-MM-DD
### Added
- New feature description
### Changed
- Change description
### Fixed
- Bug fix description
### Tx Conformance Statement
{copy content from text-cases-summary.txt}- Update
package.json&package-lock.jsonto the release version:
npm version --no-git-tag-version X.Y.Z
npm install --package-lock-onlyThis matters more than it looks. The server reports its version from
package.json (server.js, tx/tx.js) - not from the APP_VERSION build
arg - so a package.json left on the previous number ships a Docker image that
calls itself by the wrong release for good. The Verify Version job fails
the release if package.json or package-lock.json disagrees with the tag.
- Commit your changes:
git commit -m "Prepare release vX.Y.Z"
git push origin main:XXXXXXor do it via a PR
- Run the tx tests (
npx jest tests/tx/test-cases.test.js), then tag and push the release:
./release.sh X.Y.Zgr.sh checks that the release is ready - on main and pushed, the three versions in
package.json and package-lock.json match, CHANGELOG.md has a dated section with the
conformance statement, and test-cases-report.json passed, is from this version and is
newer than the last code change - then submits the report to
npm.fhir.org (set FHIRSMITH_TESTING_TOKEN if it needs a
token), and only if that is accepted, tags vX.Y.Z and pushes the tag.
The tx test run writes test-cases-report.json next to test-cases-summary.txt (both
are ignored by git). The report records the version in package.json when the tests
ran, so run the tx tests after step 2. To submit a report on its own (to a different
/testing server, say): node utilities/submit-test-report.js [-server {url}] [-token {token}].
-
Monitor the release:
- Check GitHub Actions for the Release workflow
- Verify the GitHub Release was created
- Confirm Docker images are available at GHCR
-
Update
package.jsonto have the next release version -SNAPSHOT
If a release fails:
- Delete the tag:
git tag -d vX.Y.Z && git push origin :refs/tags/vX.Y.Z - Fix the issue
- Re-tag and push
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests if applicable
- Submit a pull request
- Issues: GitHub Issues
- Documentation: Wiki
- FHIR Community: chat.fhir.org
