CockroachDB 26.1 separates read replica cost from survival goals
Non-voting replicas can now be removed without reducing the voters required by a multi-region survival goal. The release also changes access to internal metadata and adds visibility inside stored routines.
CockroachDB 26.1 lets a multi-region database remove non-voting read replicas while retaining the voting replicas required by its survival goal. The February 18 release describes this as a way to reduce storage costs without compromising the configured availability guarantee. The implementation history is more specific. Zone Config Extensions previously rejected a configuration that made the total replica count equal to the voting replica count, even when the required voters remained.
That distinction matters because an additional copy of data does not necessarily have the same role as another voter. CockroachDB already distinguishes copies that participate in consensus from copies intended for reads. Version 26.1 makes that distinction usable in a configuration that the previous validation incorrectly prevented. It creates a narrower cost decision than simply reducing replication and accepting more risk.
I have three years with CockroachDB and value its explicit consistency model. Consensus round trips have a real latency cost, which I accept when the required guarantees justify it. This change fits that preference. It makes the role of each replica clearer and allows the cost of read placement to be considered separately from the voters needed for the chosen failure tolerance.
Voting replicas determine the quorum
The replication architecture documentation explains that changes to a range require agreement from a quorum of replicas. Raft coordinates that agreement. Voting replicas participate in the consensus process, including elections. A non-voting replica follows the Raft log but does not participate in quorum, so its presence does not add a vote to the agreement needed for a write.
CockroachDB introduced non-voting replicas because adding voting replicas to place more readable copies also increased participation in consensus. The documentation dates the earlier all-voting arrangement to versions before 21.1. Non-voting replicas allow additional read placement with almost no effect on write latency, according to the architecture description. They still contain data and follow the replicated log, even though their purpose differs from a voter.
The relevant configuration relationship is simple. num_replicas counts the total copies, and num_voters identifies the voting copies. When the latter is smaller, the difference is the number of non-voting replicas. Making the two values equal removes that difference. It does not, by itself, reduce the number of voters.
Version 26.1's development notes describe correcting Zone Config Extensions so this equality is accepted while maintaining the voters required by the database's survival goal. That is the basis for the release's availability claim. It is not permission to choose an arbitrary smaller voting set and assume the same guarantee. The required voter count and placement remain constraints of the selected survival objective.
Storage savings can change where reads are available
Removing copies reduces the storage needed for those copies, which is the benefit highlighted in the release. The tradeoff follows from their role. A non-voting replica exists to provide another place from which eligible reads can be served. Removing it can therefore change the location of readable data even though the voting arrangement continues to meet the same failure-survival requirement.
Availability and read latency are different properties here. The release establishes that the survival guarantee can be retained. It does not establish that every application's read latency will remain unchanged after removing its local read copy. A design that relies on nearby replicas has a different requirement from one that needs only the configured failure tolerance and can accept another read location.
This makes workload placement relevant to the cost decision. A region added primarily for local reads may justify its non-voting copies. Another deployment may find those copies unnecessary for its access pattern. The new capability allows that decision to reflect the application's needs without conflating it with a reduction in voters. No universal percentage saving follows from the release notes, because the result depends on the database's actual replica arrangement.
The architecture documentation recommends that most users manage placement through high-level multi-region controls. The replication-zone documentation also distinguishes voter_constraints, which govern voters, from general constraints, which govern all replicas. Those separate controls explain why matching counts is only part of a valid placement definition. A survival goal is about where the required votes remain available after the specified failure.
My interest in this feature is the precision of the tradeoff. It exposes a storage choice while retaining the declared availability requirement. The operational question becomes whether the extra read location is worth its copies for this workload. That is a more useful question than treating every replica as interchangeable or assuming that every reduction has the same consistency consequence.
Internal metadata becomes a restricted dependency
The release also changes how operators inspect the system. Access to the system database and most of the crdb_internal schema is restricted by default. Queries to those objects fail unless explicitly overridden through allow_unsafe_internals. The notes explain that these internal objects were not designed as stable external interfaces and that accidental misuse can create difficult recovery situations.
Several commonly used introspection capabilities move to stable information_schema interfaces. The notes name information_schema.crdb_datums_to_bytes and information_schema.crdb_index_usage_stats. They also identify information_schema.crdb_rewrite_inline_hints as the replacement for a function introduced during development under an internal name. Those are concrete migration targets for tools using the corresponding capabilities.
The change makes previously implicit coupling visible. An administration query can be operationally important while depending on an implementation detail that the database does not promise to preserve. A default restriction will expose that dependency during an upgrade. Where a stable replacement exists, moving to it gives the tool an interface intended for external use.
An override remains available, but its existence does not give an internal object a stability commitment. The release's stated purpose is to prevent accidental use of objects whose behavior was not designed for that role. Treating the override as a permanent blanket setting would retain the original dependency and remove the signal that the new default supplies. A tool migration needs to identify which capability it actually requires.
Routine statistics reveal work inside a CALL
Version 26.1 records execution statistics and logical plans for statements inside user-defined functions and stored procedures. The release highlights per-statement timings and resource consumption, with correlation to the parent call. This addresses an observability problem that occurs when a top-level routine invocation represents several different database operations.
The development notes say these inner statements appear in the DB Console's SQL Activity and Insights pages. They also state a limitation. Statements inside routines are not collected for active statement diagnostics requests, while diagnostics remain available for top-level executions. Recorded statistics and a diagnostic capture are therefore different capabilities in this release.
That boundary matters when moving from an aggregate symptom to a particular statement. A slow routine can now expose which inner operation accounts for time or resources. It does not follow that requesting diagnostics for the routine will capture every nested statement through the same mechanism. The available statistics still provide a more specific basis for investigating the routine than the total duration of the call alone.
Other resource-accounting improvements report admission-control waiting time. The development notes add cumulative wait time to EXPLAIN ANALYZE when it is nonzero. That gives an explanation for time spent waiting to be admitted to work, which should not be attributed automatically to the execution plan's data access. The release's broader attribution work makes these distinctions more visible to operators.
The release changes both policy and evidence
The security additions have their own availability qualifications. Disabling the root user and collecting debugging data without root are previews in 26.1. Its new FIPS architecture, based on Go's native module, is also a preview for nonproduction evaluation. Those labels matter independently of whether the general database release is suitable for a deployment.
Replica removal is the change that most directly affects my view of this release. It allows an unnecessary read copy to be removed while retaining the declared survival objective. The decision still needs an accurate account of where the application's reads should run, since the guarantee concerns availability under failure and does not promise identical read placement.
Introspection performance has a separate upgrade qualification. Queries against pg_catalog and information_schema can use cached descriptors to improve performance when a cluster has many tables. The notes say this improvement requires upgrade finalization, and identify sql.catalog.allow_leased_descriptors.enabled as its control. That means a comparison made during the mixed-version phase does not establish the final introspection behavior. Tools moving to the supported metadata interfaces can assess their results again after the documented finalization step.