Skip to main content
Related: Installation, Client, CLI This engine centralizes all knobs under SearchEngine.config. These values drive the client and relation layers and are hydrated from ENV at boot by the engine initializer.

Field reference

FieldTypeDefaultNotes
hostString"localhost"Typesense node host
portInteger8108Typesense node port
protocolString"http""http" or "https"
api_keyString, nilnilRequired for real requests; redacted in logs
timeout_msInteger3_600_000Total request timeout (ms)
open_timeout_msInteger1000Connect/open timeout (ms)
retriesHash{ attempts: 2, backoff: 10.0..60.0 }Backoff supports Float or Range (seconds)
loggerLogger-likeRails logger or stdoutMust respond to #info/#warn/#error
default_query_byString, nilnilComma-separated fields for query_by default
default_infixString"fallback"Typesense infix option
use_cacheBooleantrueURL-level option only
cache_ttl_sInteger60URL-level option: TTL seconds -> cache_ttl
strict_fieldsBooleantrue in development/test; else falseParser validates unknown fields when true; see Query DSL
multi_search_limitInteger50Hard cap on searches per multi-search; validated before network call
test_modeBooleantrue in test; else falseUses OfflineClient when true
search_engine_modelsString"app/search_engine"Path (relative or absolute) to host app SearchEngine models; drives the dedicated loader
relation_print_materializesBooleantrueWhen true, Relation#inspect materializes a preview; set false for zero-I/O console output

ENV mapping

Only blank/unset fields are hydrated from ENV during engine boot; explicit initializer values win.
ENV varField
TYPESENSE_HOSThost
TYPESENSE_PORTport
TYPESENSE_PROTOCOLprotocol
TYPESENSE_API_KEYapi_key
TYPESENSE_STRICT_FIELDSstrict_fields
SEARCH_ENGINE_TEST_MODEtest_mode
SEARCH_ENGINE_OFFLINEtest_mode
SEARCH_ENGINE_TEST_MODE accepts 1/0, true/false, yes/no, on/off. When it is unset, SEARCH_ENGINE_OFFLINE is treated as a legacy alias.

Initializer

Place the following in your host app at config/initializers/search_engine.rb:
# config/initializers/search_engine.rb
SearchEngine.configure do |c|
  c.host             = ENV.fetch("TYPESENSE_HOST", "localhost")
  c.port             = ENV.fetch("TYPESENSE_PORT", 8108).to_i
  c.protocol         = ENV.fetch("TYPESENSE_PROTOCOL", "http")
  c.api_key          = ENV.fetch("TYPESENSE_API_KEY")
  c.timeout_ms       = 3_600_000
  c.open_timeout_ms  = 1_000
  c.retries          = { attempts: 2, backoff: 10.0..60.0 }
  c.default_query_by = "name, description"
  c.default_infix    = "fallback"
  c.use_cache        = true
  c.cache_ttl_s      = 60
  c.strict_fields    = Rails.env.development? || Rails.env.test?
  c.logger           = Rails.logger
  c.multi_search_limit = 50
end
Note: ENV.fetch(“TYPESENSE_API_KEY”) will raise if not set. This is intentional for production/staging. In development you can omit an initializer and rely on defaults/ENV.

URL-level caching knobs

  • use_cache and cache_ttl_s are URL-level options consumed by the client. They should not be included in request bodies.

Timeouts & retries

  • timeout_ms: total request timeout (ms). Default is 60 minutes (3_600_000 ms) and maps to Typesense::Client’s connection_timeout_seconds.
  • open_timeout_ms: connect/open timeout (ms).
  • retries: { attempts: Integer, backoff: Float or Range<Float> } where backoff is in seconds.
    • When backoff is a Range (e.g., 10.0..60.0), the client samples a single value at build time to introduce jitter between retries.
Example overrides:
SearchEngine.configure do |c|
  # Keep long writes from aborting prematurely
  c.timeout_ms = 3_600_000

  # Introduce jitter to avoid thundering herd on retries
  c.retries = { attempts: 3, backoff: 10.0..60.0 }
end

Logger

Defaults to Rails.logger when available; otherwise a $stdout logger at INFO level. You may supply any object responding to #info, #warn, and #error.

Test mode

When test_mode is true, the engine uses SearchEngine::Test::OfflineClient via SearchEngine.client. This avoids network I/O and returns safe empty responses.
  • Defaults to true in Rails test (Rails.env.test?) or when RACK_ENV=test is set
  • Can be overridden via SEARCH_ENGINE_TEST_MODE=1 or SEARCH_ENGINE_TEST_MODE=0
  • Legacy SEARCH_ENGINE_OFFLINE env var is supported as an alias
  • If SearchEngine.config.client is set (e.g., StubClient), it always takes precedence
Use SearchEngine.client to access the configured client instance. It respects SearchEngine.config.client when set, otherwise returns OfflineClient in test mode or a new Client instance.

Advanced Configuration

Beyond the top-level keys, several nested configurations control specific subsystems. These can be set in the configure block.

Indexer

Settings for bulk import and background processing.
SearchEngine.configure do |c|
  c.indexer.batch_size = 2000 # default
  c.indexer.gzip = true       # compress payloads (default: false)
  c.indexer.dispatch = :active_job # or :inline (default: :active_job if available)
  c.indexer.queue_name = 'search_index'
end
FieldDefaultNotes
batch_size2000Documents per batch during bulk operations
timeout_msnilOptional override for import read timeout (ms)
retries{ attempts: 3, base: 0.5, max: 5.0, jitter_fraction: 0.2 }Retry policy for batch imports
gzipfalseCompress JSONL bodies (requires Typesense support)
dispatch:active_jobControls SearchEngine::Indexer (rebuild/bulk) behavior. Does not apply to ActiveRecordSyncable (which is always inline).
queue_name"search_index"Queue for ActiveJob

Sources

Settings for data ingestion adapters.
SearchEngine.configure do |c|
  # ActiveRecord adapter
  c.sources.active_record.batch_size = 2000      # default: 2000
  c.sources.active_record.readonly = true        # avoid dirty tracking (default: true)
  c.sources.active_record.use_transaction = false # wrap in read-only transaction (default: false)

  # SQL adapter
  c.sources.sql.fetch_size = 5000                # server-side cursor batch (default: 2000)
  c.sources.sql.statement_timeout_ms = nil       # optional per-statement timeout
  c.sources.sql.row_shape = :auto                # :auto or :hash (default: :auto)

  # Lambda adapter
  c.sources.lambda.max_batch_size_hint = nil     # validation/metrics hint only
end
AdapterFieldDefaultNotes
active_recordbatch_size2000ORM batching size
active_recordreadonlytrueMark relations as readonly
active_recorduse_transactionfalseWrap fetching in read-only transaction
sqlfetch_size2000Server-side cursor batch size
sqlstatement_timeout_msnilOptional per-statement timeout
sqlrow_shape:autoRow shape preference (:auto or :hash)
lambdamax_batch_size_hintnilValidation/metrics hint only

Mapper

Settings for attribute mapping and coercions.
SearchEngine.configure do |c|
  c.mapper.strict_unknown_keys = true # raise on extra fields (default: false)
  c.mapper.coercions = { enabled: true, rules: {} } # enable type coercions
  c.mapper.max_error_samples = 5 # max error samples in reports (default: 5)
end
FieldDefaultNotes
strict_unknown_keysfalseWhen true, extra fields raise InvalidField
coercions{ enabled: false, rules: {} }Type coercion settings (safe integer/float/bool only)
max_error_samples5Maximum error samples included in batch reports

Partitioning

Settings for partitioned indexing and hooks.
SearchEngine.configure do |c|
  c.partitioning.default_into_resolver = nil # optional proc to resolve physical collection
  c.partitioning.before_hook_timeout_ms = nil # timeout for before_partition hooks
  c.partitioning.after_hook_timeout_ms = nil  # timeout for after_partition hooks
  c.partitioning.max_error_samples = 5        # max error samples in payloads
end
FieldDefaultNotes
default_into_resolvernilOptional Proc to resolve default physical collection name
before_hook_timeout_msnilTimeout for before_partition hooks (ms)
after_hook_timeout_msnilTimeout for after_partition hooks (ms)
max_error_samples5Maximum error samples in hook payloads

Stale Deletes

Settings for stale document cleanup operations.
SearchEngine.configure do |c|
  c.stale_deletes.enabled = true           # global kill switch (default: true)
  c.stale_deletes.strict_mode = false     # block suspicious filters (default: false)
  c.stale_deletes.timeout_ms = nil        # optional timeout for delete requests
  c.stale_deletes.estimation_enabled = false # enable found estimation via search
end
FieldDefaultNotes
enabledtrueGlobal kill switch for stale delete operations
strict_modefalseWhen true, blocks suspicious catch-all filters
timeout_msnilOptional timeout for delete requests (ms)
estimation_enabledfalseEnable found estimation via search before delete

Observability & logging

SearchEngine.configure do |c|
  c.observability.enabled = true      # turn on compact logging subscriber
  c.observability.log_format = :kv    # :kv or :json
  c.observability.max_message_length = 200
  c.observability.include_error_messages = false
  c.observability.emit_legacy_event_aliases = true
end
FieldDefaultNotes
enabledfalseEnable compact logging subscriber automatically
log_format:kv:kv or :json
max_message_length200Truncation for error samples
include_error_messagesfalseInclude short error messages in logs
emit_legacy_event_aliasestrueEmit legacy aliases alongside new events
See Observability for event payloads and redaction.

Grouping UX

SearchEngine.configure do |c|
  c.grouping.warn_on_ambiguous = true
end
FieldDefaultNotes
warn_on_ambiguoustrueEmit non-fatal warnings for ambiguous grouping combos

Loader & console

SearchEngine.configure do |c|
  c.search_engine_models = "app/search_engine" # loader path
  c.relation_print_materializes = false        # keep console inspect zero-I/O
end
FieldDefaultNotes
search_engine_models"app/search_engine"Path (relative to Rails.root or absolute) used by the dedicated Zeitwerk loader
relation_print_materializestrueWhen false, Relation#inspect stays concise without materialization

Validation & warnings

Calling SearchEngine.configure { ... } validates obvious misconfigurations (bad protocol, negative timeouts, etc.). At boot, the engine logs a one-time warning if api_key or default_query_by are missing; secrets are not printed.