SWIRL for Backstage

Configuration Reference

Two surfaces configure SWIRL for Backstage. The Backstage side is the search.swirl block in app-config.yaml. The SWIRL side is environment variables on the container.

app-config.yaml: search.swirl

The whole block carries @visibility backend. None of it reaches the browser. baseUrl is the only required key.

search:
  swirl:
    baseUrl: http://swirl-backstage:8000
    audience: search
    indexerBatchSize: 500
    queryTimeoutMs: 8000

    federated:
      enabled: true
      providerTags: [backstage]
      timeoutMs: 5000

    tuning:
      fieldBoosts:
        titleExact: 3.0
        titleNgram: 1.0
        text: 1.0
      ngram:
        min: 4
        max: 8
      stemmer: english
      fuzzy:
        enabled: false
        distance: 1

    highlight:
      enabled: true
      maxChars: 200
      startMarker: <em>
      endMarker: </em>

Key reference

Key Type Default Meaning
baseUrl string required Base URL of the SWIRL service, as the Backstage backend reaches it.
audience string search Backstage plugin id the module mints its tokens for. Must match SWIRL_BACKSTAGE_AUDIENCE.
indexerBatchSize number 500 Documents per ingest request. SWIRL rejects a batch larger than 1,000.
queryTimeoutMs number 8000 HTTP timeout the module applies to a query call to SWIRL.
federated.enabled boolean true Register the swirl-federated document type. Set to false to run the indexed lane only.
federated.providerTags string[] ["backstage"] SWIRL SearchProvider tags to fan out to. A source joins the federated lane by carrying one of these tags.
federated.timeoutMs number 5000 Federation timeout for one query, sent to SWIRL as backstage_timeout_ms. SWIRL rounds it to whole seconds and clamps it between 1 and 180.
tuning object empty Relevance tuning, sent to SWIRL on startup. See below.
highlight.enabled boolean true Ask for snippets with the hit terms marked.
highlight.maxChars number 200 Longest snippet per field, counted in visible characters rather than markup.
highlight.startMarker string <em> The opening marker SWIRL uses, from its SWIRL_HIGHLIGHT_START_CHAR setting. Override both markers together.
highlight.endMarker string </em> The closing marker, from SWIRL_HIGHLIGHT_END_CHAR.

Relevance tuning

The tuning block is posted to SWIRL at POST /swirl/index/config/ when the backend starts. SWIRL stores it and applies it on the next indexing run, because changing the n-gram bounds or the stemmer requires a rebuilt index. A tuning block SWIRL cannot read is logged and ignored, and SWIRL keeps its current tuning.

Write the tuning block with the nested, camelCase names in the table below. They are the ones the package declares in its config schema. The flat names SWIRL uses internally, such as title_exact_boost, are rejected by yarn backstage-cli config:check --strict, which most Backstage repositories run in CI. After a restart, confirm what SWIRL actually stored with GET /swirl/index/config/.

Key Type Default Meaning
fieldBoosts.titleExact number 3.0 Weight of the stemmed, ASCII-folded title field.
fieldBoosts.titleNgram number 1.0 Weight of the n-gram title field, which is what matches partial words.
fieldBoosts.text number 1.0 Weight of the body text field.
ngram.min integer 4 Shortest n-gram indexed on titles.
ngram.max integer 8 Longest n-gram indexed on titles. Maximum 32.
stemmer string english Stemmer language name.
stopwords string or string[] english A string names the stop word language for the body text field. A list adds extra stop words, lowercased on save.
fuzzy.enabled boolean false Typo tolerance on titles. Off by default.
fuzzy.distance integer 1 Edit distance when typo tolerance is on. 0, 1, or 2.

The schema also declares bm25.k1 and bm25.b. SWIRL accepts and stores both and then reports them as not applied by this engine version, because the Tantivy binding exposes no way to set them. They change nothing about ranking today, so the example above leaves them out.

SWIRL's own config endpoint takes a few more knobs than the package declares, among them fieldBoosts.phraseMultiplier, removeLong, and its snippet settings. Those are not in the package schema, so putting them in app-config.yaml fails config:check --strict. Set them with a direct POST /swirl/index/config/ if you need them.

SWIRL environment variables

These are the defaults the Backstage image ships, from .env.backstage.dist in the SWIRL repository. Override any of them with environment: in compose or env: in the Kubernetes manifest.

Variable Default in the image Meaning
SECRET_KEY a development placeholder Django secret key. Replace it on anything another person can reach.
ALLOWED_HOSTS localhost,127.0.0.1,swirl Host names SWIRL will answer on.
CSRF_TRUSTED_ORIGINS http://localhost:8000 Origins trusted for form posts to the admin.
PROTOCOL http Scheme SWIRL builds its own URLs with.
SWIRL_EXPLAIN True Include relevancy explanations in results.
SQL_ENGINE django.db.backends.sqlite3 Database backend. The Backstage image uses SQLite.
SQL_DATABASE /data/db.sqlite3 Database file on the volume.
SQL_USER, SQL_PASSWORD, SQL_HOST, SQL_PORT placeholders Unused with SQLite. Set them only if you point SWIRL at PostgreSQL.
CELERY_BROKER_URL redis://127.0.0.1:6379/0 Redis broker. A local address makes the entrypoint start Redis inside the container.
CELERY_RESULT_BACKEND redis://127.0.0.1:6379/0 Redis result backend.
SWIRL_TANTIVY_DATA_DIR /data/tantivy Directory holding one subdirectory per document type.
SWIRL_TANTIVY_WRITER_HEAP_MB 64 Index writer heap. The SWIRL default outside the image is 128.
SWIRL_TANTIVY_BEGIN_TTL 7200 Seconds before an open generation is treated as stale, so a new begin is allowed.
SWIRL_SPACY_MODEL_EN en_core_web_sm The one spaCy model the Backstage profile installs.
SWIRL_BACKSTAGE_JWKS_URL empty JWKS URL of the Backstage backend. Empty disables Backstage token verification.
SWIRL_BACKSTAGE_AUDIENCE search Expected aud claim. Must match search.swirl.audience.
SWIRL_TIMEOUT 10 Seconds SWIRL waits for all federated sources. A query can override it with backstage_timeout_ms.
SWIRL_HIGHLIGHT_START_CHAR, SWIRL_HIGHLIGHT_END_CHAR <em>, </em> Markers SWIRL wraps hit terms in. Change these together with the highlight markers in app-config.
SWIRL_ADMIN_PASSWORD unset Sets the admin password on start. Left alone when unset.
SWIRL_PRINT_ADMIN_TOKEN unset Set to true to print the admin API token to the container log on start.
MICROSOFT_CLIENT_ID, MICROSOFT_CLIENT_SECRET, MICROSOFT_REDIRECT_URI empty Microsoft sign-in for the SWIRL Galaxy UI. Not used by Backstage.

Checking what is in effect

Both calls need the admin API token or a Backstage service token.

# the tuning SWIRL actually stored
curl -s -H "Authorization: Token <admin-api-token>" \
    http://localhost:8000/swirl/index/config/

# the live index per document type
curl -s -H "Authorization: Token <admin-api-token>" \
    http://localhost:8000/swirl/index/