Skip to main content

Search results and paging

Result parameters change how matches are counted, ordered, paged, and shaped. They never change which resources match — for that see Search and Search across references.

Paging​

Paging is offset-based, using _count for the page size and _page for a 1-based page number.

Request
curl -sS "http://localhost:9090/fhir/r4/Patient?_count=50&_page=2" | jq '.link'
ParameterBehaviour
_countPage size. Defaults to search.defaultPageSize (20) and is clamped by search.maxPageSize when that is set
_pagePage number, 1-based. This is a server extension, not a FHIR-defined parameter

The response Bundle carries navigation links:

LinkWhen present
self, firstAlways
previousWhen _page is greater than 1
nextWhen a total is known and more pages remain; otherwise when the current page came back full
lastOnly when a total was computed — see _total
Response
{
"link": [
{"relation": "self", "url": ".../Patient?_count=2&_page=2"},
{"relation": "first", "url": ".../Patient?_count=2&_page=1"},
{"relation": "previous", "url": ".../Patient?_count=2&_page=1"},
{"relation": "next", "url": ".../Patient?_count=2&_page=3"}
]
}
note

_count=0 does not mean "count only" on this server; it falls back to the default page size. Use _summary=count to get a count without entries.

Totals​

Computing an exact total requires counting every match, so it is opt-in.

Request
curl -sS "http://localhost:9090/fhir/r4/Patient?_total=accurate" | jq '.total'
_totalBehaviour
absent (default)Bundle.total is omitted and no count query runs
accurateExact COUNT(*) over the full match set
estimateCurrently identical to accurate — an exact count

The difference is visible in the links — without a total there is no last:

Request
curl -sS "http://localhost:9090/fhir/r4/Patient?_count=2" | jq '{total, links:[.link[].relation]}'
Response
{ "total": null, "links": ["self", "first", "next"] }
Request
curl -sS "http://localhost:9090/fhir/r4/Patient?_count=2&_total=accurate" | jq '{total, links:[.link[].relation]}'
Response
{ "total": 23, "links": ["self", "first", "last", "next"] }

Because the default omits the total, a client that needs last links or a match count must ask for _total=accurate (or use _summary=count).

Ordering​

_sort takes a comma-separated list of keys, applied in order. Prefix a key with - for descending.

Request
curl -sS "http://localhost:9090/fhir/r4/Patient?_sort=family,-_lastUpdated" | jq '[.entry[].resource.id]'

Sortable keys are _id, _lastUpdated, and any search parameter backed by a sortable indexed value — string, token, date, number, quantity, uri, and reference parameters. Without _sort, results are ordered by last-updated descending.

note

A _sort key that cannot be resolved — an unknown parameter, a composite parameter, or _score — is skipped silently rather than rejected. Check that ordering is what you expect rather than assuming an unsupported key errored.

Shaping the response​

Two parameters reduce the payload. Both add a SUBSETTED tag to meta.tag so clients know the resources are incomplete, and _elements wins when both are supplied.

Request
# only these top-level elements
curl -sS "http://localhost:9090/fhir/r4/Patient?_elements=name,birthDate" | jq '.entry[0].resource'

# a count with no entries
curl -sS "http://localhost:9090/fhir/r4/Patient?_summary=count" | jq '{total, entries: (.entry | length)}'
_summaryBehaviour
countReturns the total only, with no entries
trueKeeps the R4 summary element set for the type
textKeeps text, id, meta, and resourceType
dataDrops text
falseFull resources — the default

A reduced resource is tagged SUBSETTED so clients can tell it is incomplete:

Response
{
"resourceType": "Patient",
"id": "25178ae2-f6f2-429d-a540-3b44ef510a05",
"meta": {
"versionId": "1",
"lastUpdated": "2026-09-03T06:22:16Z",
"tag": [
{"system": "http://terminology.hl7.org/CodeSystem/v3-ObservationValue", "code": "SUBSETTED"}
]
},
"name": [{"family": "Alison"}]
}

_elements accepts a comma-separated list of top-level element names. resourceType, id, and meta are always retained. Dotted paths such as name.family are not supported.

Filtering by metadata​

These parameters work on every resource type:

ParameterTypeExample
_idid_id=8ccfcd49-… (comma-separated values are OR'd)
_lastUpdateddate_lastUpdated=ge2026-01-01
_tagtoken_tag=http://example.org/tags%7Creviewed
_profileuri_profile=http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient
_securitytoken_security=http://terminology.hl7.org/CodeSystem/v3-Confidentiality%7CR
_sourceuri_source=http://example.org/feed
_languagetoken_language=en
note

_lastUpdated fully supports the gt, lt, ge, and le prefixes. The eq, ne, sa, eb, and ap prefixes all behave as a plain range match at the stated precision, so ne does not negate.

Searching a List​

_list restricts a search to the members of a List resource.

First create the List, then search against its id:

Request
LIST_ID=$(curl -sS -X POST "http://localhost:9090/fhir/r4/List" \
-H "Content-Type: application/fhir+json" \
-d '{
"resourceType": "List",
"status": "current",
"mode": "working",
"entry": [
{"item": {"reference": "Patient/<id-1>"}},
{"item": {"reference": "Patient/<id-2>"}}
]
}' | jq -r .id)

curl -sS "http://localhost:9090/fhir/r4/Patient?_list=$LIST_ID" \
| jq '[.entry[].resource.name[].family]'
Response
["Cohort-B", "Cohort-A"]

The list's entry[].item.reference values become the candidate ids.

warning

_list replaces any _id you also supply rather than intersecting with it, and a _list naming a List that does not exist fails the request with 500. Confirm the List exists first.

_filter​

_filter expresses conditions the plain parameter syntax cannot, combining them with and/or.

Request
curl -sS --get "http://localhost:9090/fhir/r4/Patient" \
--data-urlencode '_filter=family co "smi" and birthdate ge 1980-01-01' | jq '.entry | length'

Supported operators:

OperatorMeaning
eqEquals — the parameter's default match
neNot equal
coContains
swStarts with
gt, lt, ge, leOrdered comparison for date, number, and quantity parameters

An unsupported operator is rejected with 400:

Response
{
"resourceType": "OperationOutcome",
"issue": [
{
"severity": "error",
"code": "not-supported",
"diagnostics": "_filter operator ew is not supported"
}
]
}
warning

_filter is partially implemented. Known gaps: the pr (present) operator does not work as specified; ew (ends with) is rejected; re, in, ni, ap, sa, and eb are not implemented; and and/or are combined left to right rather than with and binding tighter than or. Group conditions into separate parameters, or express them with ordinary search parameters, when precedence matters.

Not currently functional​

Two advertised parameters do not return results on this release. They appear in the CapabilityStatement but should not be relied on:

ParameterBehaviour
_text, _contentFull-text search matches nothing — the underlying text index is not populated. Use :contains on a string parameter instead, for example name:contains=smi
_scoreRelevance scores are never returned, and _score is not usable as a _sort key

Verify on your server​

Request
curl -sS "http://localhost:9090/fhir/r4/Patient?_total=accurate&_count=1" \
| jq '{total, links: [.link[].relation]}'