Verified against Microsoft Learn on September 29, 2026. Every rule and every supported or unsupported example on this sheet comes from the indexing policy documentation.
Indexing policies in Azure Cosmos DB · Integrated vector store · Full text search
Paths and precedence#
| Path | Matches |
|---|---|
/headquarters/employees/? | One scalar value (a string or number). Scalar paths end in /? |
/locations/[]/country/? | The country of every element in the locations array. Arrays use /[] |
/headquarters/* | Everything below headquarters. /* is the wildcard |
/* | The root. Every policy includes or excludes it |
- Include the root and exclude what you skip: the recommended strategy, because new properties are indexed automatically.
- Exclude the root and include what you query: fewer indexed paths, so lower write RU and latency. Include the partition key path explicitly with this strategy.
- When included and excluded paths conflict, the more precise path wins. A deeper path beats a narrower one (
/a/b/?beats/a/?), and/?beats/*(/a/?beats/a/*). - Example: include
/food/ingredients/nutrition/*and exclude/food/ingredients/*, and only the nutrition data under ingredients is indexed.
Indexed automatically, and indexed on request#
| Property | Default |
|---|---|
id and _ts | Always indexed when the indexing mode is consistent |
_etag | Excluded by default; add it to the included paths to index it |
The partition key (unless it is /id) | Include it in the index so queries that filter on it stay efficient. With hierarchical keys, include each level |
| Spatial paths | Add a spatial index (Point, Polygon, MultiPolygon, LineString) to use spatial functions |
| Composite indexes | Add them as your ORDER BY and filter queries need them |
Indexing modes#
| Mode | Behavior | Use it for |
|---|---|---|
| Consistent | The index updates synchronously with every write | Any container you query |
| None | Indexing is off | Pure key-value access, or during a bulk load; switch back to consistent and watch IndexTransformationProgress |
New containers use consistent or none. Time to live requires indexing, so for TTL with no indexed paths, set the mode to consistent, include no paths, and exclude /*.
Composite indexes#
- A query with ORDER BY on two or more properties requires a composite index. For filters and aggregates, composite indexes are optional and reduce RU.
- Paths are scalar with an implicit
/?, and the/*wildcard is unavailable. The sequence of paths matters. - One composite index optimizes one range filter at most. Range filters are
>,<,<=,>=, and!=.
ORDER BY on several properties#
The index paths must match the ORDER BY sequence and directions, or reverse every direction.
| Composite index | Query | Supported |
|---|---|---|
| (name ASC, age ASC) | ORDER BY c.name ASC, c.age ASC | ✅ Yes |
| (name ASC, age ASC) | ORDER BY c.name DESC, c.age DESC | ✅ Yes, every direction reversed |
| (name ASC, age ASC) | ORDER BY c.age ASC, c.name ASC | ❌ No, wrong sequence |
| (name ASC, age ASC) | ORDER BY c.name ASC, c.age DESC | ❌ No, only one direction reversed |
| (name ASC, age ASC, timestamp ASC) | ORDER BY c.name ASC, c.age ASC | ❌ No, the index has an extra path |
Filters on several properties#
Equality filters go first and the range filter goes last. ASC or DESC has no effect for filters.
| Composite index | Query | Supported |
|---|---|---|
| (name ASC, age ASC) | WHERE c.name = "John" AND c.age > 18 | ✅ Yes |
| (name DESC, age ASC) | WHERE c.name = "John" AND c.age > 18 | ✅ Yes, direction is irrelevant |
| (name ASC, age ASC) | WHERE c.name != "John" AND c.age > 18 | ❌ No, != is a second range filter |
| (name ASC, age ASC, timestamp ASC) | WHERE c.name = "John" AND c.age = 18 AND c.timestamp > 123049923 | ✅ Yes |
| (name ASC, age ASC, timestamp ASC) | WHERE c.name = "John" AND c.age < 18 AND c.timestamp = 123049923 | ❌ No, the range filter is not last |
| (name ASC, age ASC) and (name ASC, timestamp ASC) | WHERE c.name = "John" AND c.age < 18 AND c.timestamp > 123049923 | ✅ Yes, one index per range filter |
Two range filters need two composite indexes, each ending in one of the range properties, and a filter can use several composite indexes at once.
A filter plus ORDER BY#
Add the filtered properties to the front of the ORDER BY so one composite index serves both.
| Composite index | Query | Supported |
|---|---|---|
| (name ASC, timestamp ASC) | WHERE c.name = "John" ORDER BY c.name ASC, c.timestamp ASC | ✅ Yes |
| (name ASC, timestamp ASC) | WHERE c.name = "John" AND c.timestamp > 1589840355 ORDER BY c.name ASC, c.timestamp ASC | ✅ Yes |
| (name ASC, timestamp ASC) | WHERE c.name = "John" ORDER BY c.timestamp ASC | ❌ No, name is missing from ORDER BY |
| (name ASC, timestamp ASC) | WHERE c.name = "John" ORDER BY c.timestamp ASC, c.name ASC | ❌ No, wrong sequence |
| (timestamp ASC, name ASC) | WHERE c.timestamp > 1589840355 AND c.name = "John" ORDER BY c.timestamp ASC, c.name ASC | ❌ No, the range property is first |
A filter plus an aggregate (SUM and AVG)#
The equality filters come first and the aggregated property comes last. The only range filter allowed is on the aggregated property.
| Composite index | Query | Supported |
|---|---|---|
| (name ASC, timestamp ASC) | SELECT AVG(c.timestamp) FROM c WHERE c.name = "John" | ✅ Yes |
| (name ASC, age ASC, timestamp ASC) | SELECT AVG(c.timestamp) FROM c WHERE c.name = "John" AND c.age = 25 | ✅ Yes |
| (timestamp ASC, name ASC) | SELECT AVG(c.timestamp) FROM c WHERE c.name = "John" | ❌ No, the aggregate is not last |
| (name ASC, timestamp ASC) | SELECT AVG(c.timestamp) FROM c WHERE c.name > "John" | ❌ No, the range filter is not on the aggregate |
Vector and full text indexes#
| Vector index type | Search | Max dimensions | Choose it when |
|---|---|---|---|
| flat | Brute force, 100% recall | 505 | Small vectors and exact results |
| quantizedFlat | Brute force on compressed vectors, near 100% recall | 4,096 | Filters narrow the search to a small set and accuracy matters |
| diskANN | Approximate nearest neighbor | 4,096 | Large vector sets that need the lowest latency and RU cost |
- Vector policies and vector indexes are immutable after creation. To change one, create a new container.
- The vector index path must be a path in the container’s vector policy, and a full text index path must be in the container’s full text policy.
- Tuning:
quantizationByteSize(quantizedFlat and diskANN, 1 to 512) trades RU and latency for accuracy;indexingSearchListSize(diskANN only, 10 to 500, default 100) trades build time for accuracy. - Enable the vector search and full text and hybrid search features on the account before you define these indexes.
Changing an indexing policy#
- A policy change runs as an online, in-place index transformation that consumes RU at a lower priority than your reads and writes. Reads and writes stay available throughout.
- Adding an index takes effect when the transformation completes; queries use the old indexes until then.
- Removing an index takes effect immediately.
Add the new index before you remove the old one
When you replace an index, for example a single property index with a composite index, add the new index first and wait for the transformation to finish. Then remove the old index in a separate change. Group several removals into one policy change so results stay consistent.

