Indexterity

Automatic index management for MongoDB, PostgreSQL and SQL Server — with a hand brake.

Indexterity watches index usage, proposes drops and creates with confidence scores, and applies them through a pipeline that hides, observes, then drops, and can always back out. Read-only until you say otherwise.

MongoDB 6.0 to 9.x, PostgreSQL 14+ and SQL Server 2016+. Hosted, or self-host the same image.

  1. PROPOSED
  2. APPROVED
  3. observed
  4. dropped
  5. undo anytime

What Indexterity does for your indexes

Read-only by default

Connect a cluster and Indexterity analyzes forever without touching it. Writes happen only after an owner flips the cluster live — and even then, indexes only, never your documents.

A safety pipeline, not a script

A drop is hidden first, observed, then put through a regression gate and a pre-flight before it happens. Anything that slows reads is un-hidden, remembered, and cooled down. Undo rebuilds a dropped index from its recorded spec.

Confidence scores

Every recommendation carries a 0–100 score from usage history, redundancy, size and scan frequency. Set an auto-approve threshold, or approve by hand — past regressions cut the score hard either way.

Workload-aware index creation

Recurring query shapes — from $queryStats or the profiler on MongoDB, pg_stat_statements on PostgreSQL, Query Store on SQL Server — become compound indexes in Equality, Sort, Range order with correct sort directions, partial indexes for constant filters, and TTL advisories for manual age-based cleanups. Queries that sort in memory count too, not just the ones that scan everything.

Proof, not promises

Freed bytes, index-count deltas, and per-collection read/write latency charts — before and after. Every index it builds is measured against the week before it: the reads on its collection, and the scanning it was built to stop. If writes regress, the build rolls back automatically.

Built for teams

Organizations with owner/member roles, email invites, an immutable audit trail of every executed operation, engine alerts by email and a weekly digest of what read-only clusters would have done.

How it works

  1. 1

    Connect read-only

    Paste a connection string. Indexterity first reports exactly which privileges it has, and offers to create its own least-privilege user. Credentials are envelope-encrypted at rest.

  2. 2

    Collect & score

    Index usage, sizes, latency and query shapes on a schedule — every recommendation arrives scored and explained in plain language.

  3. 3

    Approve — or set a threshold

    Click approve, or let a score threshold promote confident recommendations. The observe gates still stand between any recommendation and a drop.

  4. 4

    Watch the ROI

    Latency trends, freed storage and the scans removed accumulate on the dashboard, attributed per index, with undo one click away.

Get started

Clusters start read-only. Your documents are never read, and never touched.

Frequently asked questions

How do I get access?
Sign up on the sign-in page. Whether that is open to anyone is a per-deployment switch (SIGNUP_MODE: open, invite or closed) rather than something this page can promise: an install that takes invitations only says so at sign-up and points you at the invite mail. If you self-host, the first account you create bootstraps the install and can invite the rest of your team.
Does Indexterity read my data?
Analysis never reads your data on any engine: usage, sizes and latency come from the engine's own statistics views — $indexStats and $collStats on MongoDB, pg_stat_user_indexes and pg_stat_statements on PostgreSQL, sys.dm_db_index_usage_stats and sys.dm_db_partition_stats on SQL Server — and none of them expose stored values. On MongoDB and SQL Server the user Indexterity runs as has no read privilege at all, so the server itself refuses any attempt to read a document or a row, applying included. PostgreSQL cannot offer that, and we would rather say so than imply it: only a table's owner may alter its indexes there and an owner can always read the table, so the least-privilege user we provision is analysis-only and applying takes credentials you connect deliberately.
How does it decide an index is unused?
From the engine's own per-index operation counters, over at least three snapshots: $indexStats on MongoDB, summed across every replica-set member and shard; pg_stat_user_indexes on PostgreSQL, which from version 16 also records when each index was last used; and sys.dm_db_index_usage_stats on SQL Server, read per replica. An index with no operations in any snapshot is flat-zero; one that used to be busy and then went quiet is treated as periodic-dead. Indexes that are still used periodically are never proposed for removal. A counter that goes backwards — a restart, a rebuild, a statistics reset — is treated as a fact about the counter rather than about usage, and never as an index falling idle.
What happens if dropping an index hurts performance?
A drop is never the first action. The index is hidden first and the read latency of its collection or table is baselined. If average read latency rises past the baseline during the observe window, the index is un-hidden automatically, the recommendation is rejected, and the index enters a cooldown so it is not proposed again. What hiding costs depends on the engine, and Indexterity says which before it acts: on MongoDB it is instant and free both ways, on SQL Server the un-hide is an exact but not instant rebuild, and PostgreSQL has no reversible hide at all — there the index keeps serving every query while its usage is watched, and the drop is the first thing that changes anything. Even after a real drop, undo rebuilds the index from the spec recorded at drop time.
How long does an index stay hidden before it is dropped?
Thirty days by default, and the window adapts to the index itself — set by whichever question is still open. Will anything want this again? That runs at the cadence of the workload, so usage with long gaps (a monthly report, a weekly batch) extends the window to cover a full cycle. Did hiding it hurt? That runs at the rate the index is queried, so one still serving traffic when it is hidden answers within days and is watched for a week rather than a month. An index proven idle across a much longer history is shortened too: the history already was the observation. The window chosen for each drop, and why, is recorded in the audit trail.
Which deployments does it work with?
MongoDB 6.0 to 9.x — Atlas, self-hosted and sharded — PostgreSQL 14 and newer, and SQL Server 2016 and newer. Sharded clusters are handled explicitly: statistics are summed across shards, and shard-key backing indexes are protected from removal. Replicas are read one node at a time, because a replica-set member and an availability-group secondary each keep their own usage counters, and an index idle on the primary may be the one a reporting replica lives on. On Atlas, user management belongs to Atlas, so you create the scoped role there and connect with its string; self-hosted MongoDB and SQL Server can have Indexterity create the user for you.
Which PostgreSQL privileges does it need?
Membership in pg_monitor, CONNECT on each database and USAGE on each schema — that is the whole of the analysis side, and it is what the scoped role Indexterity offers to create is granted. pg_stat_statements is the optional one: without it the drop side works as normal and there are simply no create-side recommendations. Applying is different here and worth knowing before you start: PostgreSQL has no grantable index privilege, so only a table's owner can create or drop its indexes — GRANT ALL does not cover it and neither does the MAINTAIN privilege added in 17. A cluster stays analysis-only until you connect as the owner, and the preflight says exactly that rather than reporting it as a fault.
Which MongoDB privileges does it need?
listDatabases, listCollections, listIndexes, indexStats and collStats to analyze; createIndex, dropIndex and collMod to apply changes; optionally system.profile or $queryStats for workload analysis, serverStatus for the health probe, and enableProfiler so Indexterity can turn the profiler on while a hidden index is observed and see any query the hide makes fail. serverStatus is the one that reads beyond index metadata — it also exposes connection counts and storage-engine internals — so it is optional and a cluster without it works fine. Before storing anything, Indexterity checks the connection string and tells you exactly which of these are missing and what each one enables.
Which SQL Server permissions does it need?
VIEW SERVER STATE to read sys.dm_db_index_usage_stats, which is server-scoped; VIEW DATABASE STATE for sizes, row counts and Query Store in each database; and ALTER on the schemas whose indexes it may change. Query Store is the optional one — without it the drop side works as normal and there are simply no create-side recommendations. Letting Indexterity create its own login instead needs ALTER ANY LOGIN, ALTER ANY USER in each database, and CONTROL SERVER to grant VIEW SERVER STATE. Whichever route you take, the preflight names every permission it looked for and what each one enables.
Can it create missing indexes, not just drop unused ones?
Yes. Recurring scans of a whole collection or table become index recommendations in Equality, Sort, Range order with correct sort directions, folded together when one index can serve several shapes. So do queries that find their rows through an index and then sort them in memory — invisible to any scan test, and the failure mode that ends in an error rather than slowness. On SQL Server the server's own missing-index suggestions are folded in behind the same recurrence and cost gates as every other signal. A shape must recur before it counts, so a heavy query someone runs once by hand never leaves an index behind.