Skip to content

Configuration

The API is configured through a config.yaml file in the project root. A JSON Schema is available at schemas/config.schema.json for editor autocompletion.

Reference environment variables anywhere in the config with ${VAR_NAME} syntax:

apiKey: ${API_KEY}
indexes:
my_index:
host: ${ES_HOST}
apiKey: ${ES_API_KEY}

The server will exit with an error if a referenced variable is not set.

Use ${VAR_NAME:-default} to provide a fallback value when the variable is unset:

port: ${PORT:-3000}
SettingTypeDefaultDescription
portnumber3000Server listen port
apiKeystring?Bearer token for API authentication
corsOrigins"*" | string[]Allowed CORS origins. "*" for all, array for specific, omit to disable.

When apiKey is set (or the API_KEY env var exists), all requests except /health and /openapi* require a Authorization: Bearer <token> header.

These environment variables are read directly (not from config.yaml):

VariableDescription
API_KEYBearer token for API auth (alternative to apiKey in config)
REDIS_URLRedis connection URL to enable response caching. See Caching.

Each key under indexes becomes the URL handle for that index’s endpoints.

indexes:
collections:
engine: elasticsearch
host: https://elasticsearch.example.com
apiKey: ${ES_API_KEY}
indexName: museum_collections
SettingTypeRequiredDescription
engine"elasticsearch" | "opensearch" | "meilisearch" | "typesense"YesSearch engine backend
hoststringYesSearch engine host URL
apiKeystring?NoAPI key (ES apiKey auth, or Meilisearch API key)
usernamestring?NoBasic auth username (ES, OpenSearch)
passwordstring?NoBasic auth password (ES, OpenSearch)
indexNamestring | string[]YesIndex name(s). Multi-index arrays are supported by ES/OpenSearch; Meilisearch and Typesense use only the first entry.
dateFieldsstring[]?NoField names containing dates stored as Unix timestamps. Used by Typesense to convert int64 values back to ISO 8601 strings in responses.
  • Supports apiKey or username/password auth
  • Full feature support including histograms, geo grid, and phrase suggestions
  • Multi-index search via array indexName

Pass an array to indexName to search across multiple Elasticsearch/OpenSearch indexes with a single handle. Results are unified and relevance-ranked. Each hit includes an _index field identifying its source. Meilisearch uses only the first entry in the array.

indexes:
all_content:
engine: elasticsearch
host: https://elasticsearch.example.com
indexName:
- museum_collections
- library_catalogue

Optional defaults applied when query parameters are omitted:

indexes:
collections:
# ...
defaults:
perPage: 20
facets:
- category
- period
highlight: true
suggestField: title
SettingTypeDescription
perPagenumberDefault results per page (overridden by query)
facetsstring[]Default facet fields returned with every search
highlightbooleanEnable highlighting by default
suggestFieldstringField for phrase suggestions. Should have a shingle analyzer configured in your ES mapping.
See Search — Phrase suggestions.

The fields config provides a unified way to configure field boost weights, searchability, and field name aliases. Define it at the index level:

indexes:
collections:
# ...
fields:
title:
weight: 10
description:
weight: 2
body:
searchable: true
country:
field: placeCountry
region:
field: placeRegion
PropertyTypeDescription
weightnumber?Boost weight for relevance scoring. Implies the field is searchable.
searchableboolean?Include in search queries without boosting. Only applies when weight is not set.
fieldstring?Maps this key as a consumer-friendly alias to the real field name. Works with all engines — aliasing operates at the API route layer before reaching the engine.
nestedPathstring?Elasticsearch nested path for fields inside nested object arrays. When set, aggregations and filters are automatically wrapped in nested queries. Only used by ES/OpenSearch.
  • weight — The field gets a boost multiplier in relevance scoring. This implicitly makes it searchable; you don’t need to also set searchable: true.
  • searchable: true (without weight) — The field is included in search queries at default relevance. Useful for fields you want to search but don’t want to boost.
  • field — The key acts as an alias. API consumers use the alias; the API translates to the real field name automatically and bidirectionally.
  • No fields config — All fields are searched with default relevance (equivalent to ["*"]).

Elasticsearch nested objects are arrays of objects stored as separate hidden documents. Aggregations and filters on nested fields require special nested query wrapping — set nestedPath to handle this automatically.

fields:
facilityType:
field: facilities.type
nestedPath: facilities

When nestedPath is set:

  • Filters on the field are wrapped in { nested: { path, query } }
  • Aggregations are wrapped in { nested: { path }, aggs: { ... } }
  • Post-filters (for disjunctive facets) are wrapped correctly
  • The facets endpoint wraps both filters and aggregations

This works with field aliases — define both on the same field. Only used by Elasticsearch and OpenSearch engines.

When field is set, the key acts as a consumer-friendly alias. Translation is automatic and bidirectional — use aliases in query parameters and they appear in responses.

See Field Aliases for details on which parameters support aliases.

port: 3000
apiKey: ${API_KEY}
corsOrigins: "*" # or an array: ["https://example.com"]
indexes:
collections:
engine: elasticsearch
host: ${ES_HOST}
apiKey: ${ES_API_KEY}
indexName: museum_collections
defaults:
perPage: 20
facets:
- category
- period
highlight: true
suggestField: title
fields:
title:
weight: 10
description:
weight: 2
country:
field: placeCountry
region:
field: placeRegion
catalogue:
engine: opensearch
host: ${OS_HOST}
username: ${OS_USERNAME}
password: ${OS_PASSWORD}
indexName: library_catalogue
products:
engine: meilisearch
host: ${MEILI_HOST}
apiKey: ${MEILI_API_KEY}
indexName: products
defaults:
perPage: 20
facets:
- category
blog:
engine: typesense
host: ${TYPESENSE_HOST}
apiKey: ${TYPESENSE_API_KEY}
indexName: blog_posts
dateFields:
- postDate
defaults:
perPage: 20
facets:
- category