Independent demo based on public GitHub data. PRA is not affiliated with or endorsed by Typesense, Inc.
typesense/typesense · v31 branch · 2026-10-01 to
2026-11-01, UTC
The month went into keeping a node up under concurrent load and into
access control. Four ways to stall or crash a server were closed. API
keys gained a join policy: a key scoped to one collection no longer
reaches arbitrary fields of the collections it joins. Three branches
from September reached
v31.
September integrated twelve units, eleven through pull requests. October integrated eighty-seven commits, sixty-seven of them pushed directly, most of those a rebuild of the test suite and the build pipeline.
An API key can now carry a joins object naming each
collection the key may read through a reference, with the allowed and
denied fields for each. A field outside it returns 403, a key created
without joins keeps the previous unrestricted access, and a
scoped key cannot widen the policy it inherits. The policy covers
search, document get and export. Until this change a key described which
collections it could act on and nothing about joins, so a key restricted
to one collection could read any field of any collection that one
referenced. A second way to widen a scoped key closed in the same month,
in how the key’s own filter combines with the request’s.
Sources: #3119, #3125, #3111 · review, sections 1 and 2.
A turnstile now makes searches that arrive after a pending document
write queue behind it, for a bounded share of the time: at the default a
write holds searches back for half a second, after which the gate stays
open three times as long. The new
write-priority-max-percentage setting, from 0 to 100 and
defaulting to 25, sets both numbers, and 0 removes the turnstile. Before
it, a collection’s lock admitted readers while a writer waited, so a
steady stream of searches could keep a write out indefinitely. A second
stall, where a write waited out a storage compaction, was fixed
separately.
Sources: direct commits 5def5b4 and f15f778, with six more of 24 October · review, section 3.
A cascade delete now takes its locks one at a time and releases everything it holds as soon as one of them is contended, which lets a search finish first. It used to lock a collection and then everything referencing it, while a search locked its own collection and then a referenced one, so two requests running in opposite directions could each hold what the other needed. Neither a search cutoff nor an HTTP timeout broke that, because both threads were stuck inside the lock itself.
Sources: #3091, issue #3086 · review, section 4.
The line that logs a long running query is now built on the request’s
own thread, the crash handler skips its dump of queries in flight when
the crashing thread holds the lock it needs, and an alarm ends a crash
handler that hangs anyway. The background task used to read request
state the search threads were free to change, so under enough load it
crashed, and the crash handler then waited on a lock the dead task still
held. The process stopped there: every search blocked, the replication
loop stalled, and /health went on answering ok.
Sources: direct commit 86a3337 · review, section 5.
Gzip inflation now runs through a fixed buffer and appends, so the output size no longer depends on the compressed size, and a stream left incomplete is rejected rather than passed on truncated. The buffer used to be sized at ten times the compressed chunk, so any import body compressing better than about ten to one, which a repetitive JSONL import reaches easily, could corrupt the heap or drop documents without saying so. The code dates from 24 September and had no pull request at that cutoff, so it is not in the September report. It was opened as #3117 on 14 October and merged on 28 October.
Sources: #3117 · review, section 6.
A node that cannot resolve every peer no longer applies a partial peer list. If it already has a replication log or a snapshot it starts from the membership recorded there, and if it has no state it waits. An unresolvable hostname used to be passed on as written and a failed peer dropped from the list, so a node could reconfigure the cluster from what it had and remove valid members. The same change closes a gap in the proxy endpoint, where an empty peer allowlist used to admit everyone.
Sources: #3103 · review, section 7.
The C++ suite now runs in eight shards, where the slowest takes 52 seconds against 316 for the whole suite in one process on 32 cores, and a cold build of the server went from 1,062 seconds to 336 on the same machine once a job cap on a dependency was lifted. Before this the suite ran in one process and its tests shared fixed paths, so two test processes at once overwrote each other’s data. These figures are from the commit messages, measured by their author.
Two of these changes concern exposure rather than cost. Workflow permissions were scoped and every action pinned to a commit, and the server logs uploaded when an API test fails are scrubbed of provider API keys first, because those logs carry request payloads and anyone who can read the repository can download the artifacts.
Sources: #3097 and 55 direct commits of 23 to 26 October · review, section 8.
Access control on write paths. The key policy covers search, document get and export (#3119). An open branch reports a separate gap in authorization on single document upsert (#3128), and another resolves a preset referenced by a scoped key before authorization and adds the authorized collections to the result cache key (#3142). Neither had merged at the end of the month.
The write turnstile outside tests. The hold and the cooldown are asserted by timed waits inside one process. Nothing in the sources checked measures search latency or write throughput on a loaded server, or explains how the default of 25 was chosen. The durability side of the same path is still open, as it was in September: the branch where a document becomes searchable before it is stored (#3050, open since 15 September) and the one on import responses that stall indexing (#3121).
Work that went in without a pull request. Sixty-seven of the month’s eighty-seven commits were pushed to the branch directly, including the test and build rebuild and the write turnstile. Public development shows no review for them, and whether they were reviewed elsewhere cannot be seen from this data. Two pull requests on subjects that landed directly were closed without merging in the same period, #3100 on 8 October and #3101 on 30 October, and neither records a reason.
Natural language search and embedders. Two September branches merged, the parameter newer OpenAI models require (#3073) and loading stored models without a live call (#3153). The typed judgment provider took one October commit against fourteen in September (#3072), so the shape of that generation may still change, and the regional embedder key that merged (#3096) came off a branch that also holds and evicts embedders per field and stayed open (#3104).
September branches that did not move. Fourteen pull requests open at the end of September were still open at the end of October with no commits in between, among them four the September report raised as open: the bundled OpenSSL bump (#3064, open since 23 September), the facet identifier collision (#3075) and the work on async reference registrations (#3082, #3066). An absence of commits is not evidence that any of them was abandoned.
Three branches open at the end of September reached v31.
A union search reports a timeout from whichever sub-search ran out of
budget, and a union cut off with nothing to return answers 408 rather
than 200 with an empty body (#3052, section
9). The memory guard asks the allocator to return unused pages
before rejecting a write, so writes recover after a bulk delete instead
of failing while the documents are already gone (#3080, section
11). Natural language models load at startup without calling their
provider, so an outage during a restart no longer drops a configured
model (#3073, #3153, section
10).
Four changes alter what a search returns. Pinned hits are no longer
dropped when a filter matches fewer documents than there are pins (#3124, section
12). Replacing a nested object array no longer leaves its old values
in the index, where a filter could still match a document whose stored
array was empty (#2920, section
13). A curation rule keeps its filter_by when the query
matched through a stopword, through stemming or after the rule rewrote
the query (#2999, section
14). And query_by and group_by honour
validate_field_names=false for unresolved reference style
names (#3141, section
19).
The rest of the integrated work, each with its own section of the
review: a server side --max-query-len (#3108, 15),
a negated join computed from the parent collection (#3133, 16),
collection metadata written under an exclusive lock after a crash under
concurrent load (#3112, 17),
embedders keyed by their GCP region (#3096, 18),
a startup crash under WSL (#3093, 20),
an empty object filter rejected with its own message (21),
facet parsing kept inside the facet string (22)
and the vector index pinned to a newer build of hnswlib, the nearest
neighbour library underneath it (23).
Eighty-seven commits entered the v31 branch between 1
October and 1 November UTC, twenty of them integrating a pull request
and sixty-seven pushed directly. The window is taken from the date a
commit entered the branch, not from when its code was written. The
technical review accounts for every one of them, the month’s themes in
depth and the rest in a line each, and lists work still on a branch
separately, by initiative, counting towards nothing.
Tests were read in the diffs and not run, and every number quoted above is reported by the author of the change. The newest published release is v30.2 from 19 April 2026, so none of this month’s work is in a release, as was true in September. Ten pull requests were closed without merging during October and their branches are not in the data collected, so why each was closed could not be checked. Public development does not show revenue, adoption or private work.
Typesense is a trademark of Typesense, Inc.