

# Creating and searching vector indexes
<a name="VectorSearchWorkingWith"></a>

This section describes how to create and manage vector indexes, write items with vector data, and perform similarity searches using the `SearchVectors` API.

**Topics**
+ [Before you begin](#VectorSearchWorkingWith.Prerequisites)
+ [SearchVectors endpoints](#VectorSearchWorkingWith.Endpoints)
+ [Generating vector embeddings](#VectorSearchWorkingWith.Embeddings)
+ [Creating a vector index](#VectorSearchWorkingWith.Create)
+ [Writing items with vector data](#VectorSearchWorkingWith.Write)
+ [Searching with SearchVectors](#VectorSearchWorkingWith.Search)
+ [Deleting a vector index](#VectorSearchWorkingWith.Delete)

## Before you begin
<a name="VectorSearchWorkingWith.Prerequisites"></a>

Before you work with vector indexes, verify the following:
+ Your table uses on-demand capacity mode (`PAY_PER_REQUEST`). Vector indexes are not supported on provisioned capacity tables.
+ Your AWS Identity and Access Management (IAM) identity has `dynamodb:CreateTable` or `dynamodb:UpdateTable` permissions to create vector indexes.
+ Your IAM identity has `dynamodb:SearchVectors` permission on the vector index resource to perform searches. The resource ARN format is `arn:aws:dynamodb:{{region}}:{{account-id}}:table/{{table-name}}/index/{{index-name}}`.

## SearchVectors endpoints
<a name="VectorSearchWorkingWith.Endpoints"></a>

`SearchVectors` requests use dedicated vector-search endpoints, which are distinct from the standard DynamoDB endpoints that you use to create and manage vector indexes (for example, with `CreateTable`, `UpdateTable`, and `DescribeTable`). The AWS SDKs and AWS CLI route `SearchVectors` requests to the correct endpoint automatically. You do not need to configure or override the endpoint in your application code.

If you are building a custom HTTP client that calls the DynamoDB API directly without an AWS SDK, use one of the following vector-search endpoints, replacing {{account-id}} and {{region}} as appropriate:
+ `{{account-id}}.search-ddb.{{region}}.amazonaws.com` — Account-based endpoint.
+ `search-dynamodb.{{region}}.api.aws` — Dual-stack endpoint, compatible with both IPv4 and IPv6.

## Generating vector embeddings
<a name="VectorSearchWorkingWith.Embeddings"></a>

DynamoDB stores and searches vector embeddings, but it does not generate them. You produce embeddings with an embedding model, such as the Amazon Bedrock Titan Text Embeddings or Cohere Embed models, or any embedding model you operate. You then store the resulting vector in a DynamoDB item and pass a query vector to `SearchVectors`.

**Query vector and stored vectors must use the same model**  
The query vector you pass to `SearchVectors` and the vectors stored in your items must be produced by the same embedding model and must have the same number of dimensions as the vector index. Mixing models, or querying with a different number of dimensions than the index was created with, produces meaningless results or a validation error.

The typical flow is:

1. Send your source content (for example, a product description) to an embedding model and receive a vector.

1. Store that vector in a DynamoDB item, in the attribute named by the vector index (`VectorAttribute`), as a list (`L`) of numbers (`N`).

1. At query time, generate a vector from the search text using the same model, and pass it as the `SearchVector`.

**Choose your embedding model before creating the index**  
Choose your embedding model before you create the vector index, because the model determines the number of dimensions. Common embedding models produce 384, 768, 1024, 1536, or 3072 dimensions. DynamoDB supports up to 4,096 dimensions. See [Requirements and limitations](VectorSearch.Requirements.md).

The distance function you choose interacts with how your model produces embeddings. `COSINE` compares direction and ignores magnitude, so it works with embeddings whether or not they are normalized. `DOT_PRODUCT` is sensitive to magnitude: if your embeddings are not normalized to unit length, larger vectors receive higher scores regardless of direction. If you use `DOT_PRODUCT` and want direction-based similarity, normalize your embeddings to unit length before you store them. See [How distance functions rank results](VectorSearch.md#VectorSearchWorkingWith.Ranking).

## Creating a vector index
<a name="VectorSearchWorkingWith.Create"></a>

You can create a vector index when you create a new table or add one to an existing table.

### Creating a table with a vector index
<a name="VectorSearchWorkingWith.Create.NewTable"></a>

Use the `CreateTable` API with the `VectorIndexes` parameter to create a table with a vector index. The following AWS CLI example creates a `Products` table with a vector index named `ProductEmbeddingIndex`.

```
aws dynamodb create-table \
    --table-name Products \
    --attribute-definitions AttributeName=ProductId,AttributeType=S \
                            AttributeName=Category,AttributeType=S \
                            AttributeName=Brand,AttributeType=S \
    --key-schema AttributeName=ProductId,KeyType=HASH \
    --billing-mode PAY_PER_REQUEST \
    --vector-indexes \
        "[
            {
                \"IndexName\": \"ProductEmbeddingIndex\",
                \"VectorAttribute\": {\"AttributeName\": \"Embedding\"},
                \"SearchSchema\": [{\"AttributeName\":\"Category\",\"SearchSchemaElementType\":\"HASH\"},
                                  {\"AttributeName\":\"Brand\",\"SearchSchemaElementType\":\"INLINE_FILTER\"}],
                \"Projection\": {\"ProjectionType\": \"ALL\"},
                \"Dimensions\": 1536,
                \"DistanceFunction\": \"COSINE\"
            }
        ]"
```

In this example:
+ `VectorAttribute` specifies `Embedding` as the attribute that contains vector data.
+ `SearchSchema` defines `Category` as a vector index partition key (`HASH`), which partitions the index by category for scaling. It also defines `Brand` as an `INLINE_FILTER`, which lets you filter search results by brand at the storage layer. Because both `Category` and `Brand` are referenced in the SearchSchema, they must also be declared in `AttributeDefinitions`, the same way key attributes are declared for a global secondary index.
+ `Dimensions` is set to 1536, matching the output of common embedding models.
+ `DistanceFunction` is set to `COSINE`, where lower scores indicate greater similarity.

### Adding a vector index to an existing table
<a name="VectorSearchWorkingWith.Create.ExistingTable"></a>

Use the `UpdateTable` API with the `VectorIndexUpdates` parameter to add a vector index to an existing table. This example adds a second, independent index named `ProductEmbeddingIndexV2` to the same `Products` table.

```
aws dynamodb update-table \
    --table-name Products \
    --vector-index-updates \
        "[
            {
                \"Create\": {
                    \"IndexName\": \"ProductEmbeddingIndexV2\",
                    \"VectorAttribute\": {\"AttributeName\": \"Embedding\"},
                    \"Projection\": {\"ProjectionType\": \"ALL\"},
                    \"Dimensions\": 1536,
                    \"DistanceFunction\": \"EUCLIDEAN\"
                }
            }
        ]"
```

When you add a vector index to an existing table, DynamoDB reports index progress through two fields in the `DescribeTable` response: an `IndexStatus` value and a separate `Backfilling` boolean.

1. `IndexStatus` is `CREATING` — DynamoDB is setting up the index infrastructure.

1. `IndexStatus` is `ACTIVE` with `Backfilling` set to `true` — DynamoDB is populating the index with existing data from the base table. New writes to the base table are also replicated to the index during this phase. While a vector index is backfilling, `SearchVectors` returns an error. Wait until `Backfilling` is `false` before you search.

1. `IndexStatus` is `ACTIVE` with `Backfilling` set to `false` (or absent) — The index is fully populated and ready for search operations.

**You can't search while the index is backfilling**  
`SearchVectors` returns an error while a vector index is backfilling. Use `DescribeTable` to check both the `IndexStatus` and the `Backfilling` flag, and wait until `IndexStatus` is `ACTIVE` and `Backfilling` is `false` before you search. There is no `BACKFILLING` index status value.

## Writing items with vector data
<a name="VectorSearchWorkingWith.Write"></a>

You write items with vector data using the standard DynamoDB write APIs (`PutItem`, `UpdateItem`, `BatchWriteItem`, `TransactWriteItems`). Store the vector embedding as a list of numbers (`L` type containing `N` elements).

Because a vector contains many values, save the item to a file such as `item.json`, then pass the file to the AWS CLI.

```
{
    "ProductId": { "S": "prod-123" },
    "Category": { "S": "Electronics" },
    "Title": { "S": "Wireless Headphones" },
    "Embedding": {
        "L": [
            { "N": "0.1234" },
            { "N": "-0.5678" },
            { "N": "0.9012" },
            ...
        ]
    }
}
```

```
aws dynamodb put-item \
    --table-name Products \
    --item file://item.json
```

**Vector length must match the index dimensions**  
The `Embedding` vector shown here is abbreviated. In `item.json`, it must contain 1,536 values to match the `Dimensions` you set on `ProductEmbeddingIndex`. Writing a vector with the wrong number of dimensions is rejected.

DynamoDB validates vector data when you write items to a table that has a vector index. The following table describes the validation behavior.


| Condition | Behavior | 
| --- | --- | 
| Vector attribute has wrong number of dimensions | Write is rejected. | 
| Vector index partition key attribute is missing | Write succeeds on the base table, but the item is not replicated to the vector index. | 
| Vector index partition key attribute type doesn't match index schema | Write is rejected. | 
| Inline filter attribute is missing | Write succeeds and the item is replicated to the vector index. | 
| Vector values have higher precision than 32-bit floating point (f32) | Write succeeds. Values are stored as-is in the base table but lose precision when replicated to the vector index. | 
| Vector attribute is deleted from an item | The corresponding entry in the vector index is deleted. | 

**Missing partition key causes silent de-indexing**  
If your vector index defines a partition key in the SearchSchema and you write an item without that attribute (or remove it with `UpdateItem`), the write succeeds on the base table but the item is silently excluded from the vector index. It will not appear in `SearchVectors` results even though the base table item and its vector embedding still exist. Ensure that every item you want to be searchable contains the vector index partition key attribute.

**Stale embeddings produce incorrect results**  
DynamoDB does not recompute embeddings for you. If you change the source content that produced an embedding (for example, you edit a product description), the stored vector does not update automatically. You must regenerate the embedding with your embedding model and write the new vector back to the item. Otherwise the vector index continues to return results based on the old, stale vector, which can silently produce incorrect matches.

## Searching with SearchVectors
<a name="VectorSearchWorkingWith.Search"></a>

Use the `SearchVectors` API to find items in a vector index that are most similar to a query vector. Results are sorted by relevance, with the most similar item first. Search results are eventually consistent: there might be a brief delay between writing or updating a vector and it appearing in search results. For more information, see [Ongoing write synchronization](VectorSearchDataSync.md#VectorSearchDataSync.OngoingWrites).

### Basic search
<a name="VectorSearchWorkingWith.Search.Basic"></a>

The following example searches for the 10 most similar items in the `ProductEmbeddingIndex` index. Because this index has a vector index partition key (`Category`) defined in its SearchSchema, the `SearchConditionExpression` must include the vector index partition key value.

Save the query vector to a file such as `query-vector.json`, as a plain JSON array of number values.

```
[
    { "N": "0.1234" },
    { "N": "-0.5678" },
    { "N": "0.9012" },
    ...
]
```

```
aws dynamodb search-vectors \
    --table-name Products \
    --index-name ProductEmbeddingIndex \
    --search-vector file://query-vector.json \
    --top-k 10 \
    --search-condition-expression "Category = :cat" \
    --expression-attribute-values "{\":cat\": {\"S\": \"Electronics\"}}"
```

The response includes a `SearchResults` array. Each element contains the matching `Item` and a `Score` that indicates how similar the item is to the query vector.

```
{
    "SearchResults": [
        {
            "Item": {
                "ProductId": { "S": "prod-456" },
                "Category": { "S": "Electronics" },
                "Title": { "S": "Bluetooth Speaker" }
            },
            "Score": 0.0023
        },
        {
            "Item": {
                "ProductId": { "S": "prod-789" },
                "Category": { "S": "Electronics" },
                "Title": { "S": "Noise Cancelling Earbuds" }
            },
            "Score": 0.0145
        }
    ]
}
```

**Vector attributes are excluded from results by default**  
By default, the results from `SearchVectors` don't include the vector attribute (the embedding). Vector data is large, and you typically don't need it in the response. The results include the other projected attributes and the `Score` value. To include the vector attribute, request it with a `ProjectionExpression`. For more information, see [Using ProjectionExpression](#VectorSearchWorkingWith.Search.Projection).

**SearchVector is a plain list, not a DynamoDB L type**  
The `SearchVector` request parameter is a plain JSON array of number objects (`[{"N": "0.1234"}, ...]`). Do not wrap it in a DynamoDB `L` type as you would when storing a vector in an item attribute. The `L` wrapper is only used when writing or reading vector data in item attributes.

The meaning of the `Score` depends on the distance function you chose when you created the index. For `COSINE` and `EUCLIDEAN`, lower scores indicate greater similarity. For `DOT_PRODUCT`, higher scores indicate greater similarity.

### Filtering with SearchConditionExpression
<a name="VectorSearchWorkingWith.Search.Filtering"></a>

Use `SearchConditionExpression` to filter search results based on vector index partition key and inline filter attributes defined in the SearchSchema. This expression uses the same syntax as other DynamoDB expression parameters.

The following example searches for items in the `Electronics` category (vector index partition key) with a `Brand` inline filter.

```
aws dynamodb search-vectors \
    --table-name Products \
    --index-name ProductEmbeddingIndex \
    --search-vector file://query-vector.json \
    --top-k 10 \
    --search-condition-expression "Category = :cat AND Brand = :brand" \
    --expression-attribute-values "{\":cat\": {\"S\": \"Electronics\"}, \":brand\": {\"S\": \"Acme\"}}"
```

If your vector index has a partition key defined in the SearchSchema, you must include it in the `SearchConditionExpression`. Inline filter attributes are optional.

The equality operator (`=`) is supported in `SearchConditionExpression` for both vector index partition key and inline filter attributes. Comparison, range, and set-membership operators (`<>`, `<`, `<=`, `>`, `>=`, `IN`) are not yet available.

This filtering is how you scope a similarity search to a subset of your data, a common requirement in multi-tenant and Retrieval Augmented Generation (RAG) applications. For example, to find documents similar to a query but only within one tenant, define the tenant attribute as a vector index partition key (`HASH`) in the SearchSchema and pass its value in every search. This isolates results to that tenant. It also improves performance, because the search examines only the relevant data. Use inline filter attributes for additional equality constraints, such as a document type or status, that you want to apply within the routed partition.

**Partition key scoping is not a security boundary**  
Using a partition key to scope searches to a single tenant is a data-locality and performance optimization, not an access-control mechanism. Any principal that holds `dynamodb:SearchVectors` permission on the index can search any partition key value. Because fine-grained access control (FGAC) condition keys such as `dynamodb:LeadingKeys` do not apply to `SearchVectors`, you cannot restrict access to individual partition key values at the IAM policy level. If your workload requires strict tenant isolation at the data layer, use separate tables or indexes with distinct IAM grants for each tenant.

### Using ProjectionExpression
<a name="VectorSearchWorkingWith.Search.Projection"></a>

Use `ProjectionExpression` to return only specific attributes in the search results. This can reduce the response size when you don't need all projected attributes. Because `ProductEmbeddingIndex` defines a vector index partition key (`Category`) in its SearchSchema, this example still includes the vector index partition key value in `SearchConditionExpression`.

```
aws dynamodb search-vectors \
    --table-name Products \
    --index-name ProductEmbeddingIndex \
    --search-vector file://query-vector.json \
    --top-k 5 \
    --search-condition-expression "Category = :cat" \
    --expression-attribute-values "{\":cat\": {\"S\": \"Electronics\"}}" \
    --projection-expression "ProductId, Title"
```

**Only projected attributes can be returned**  
You can only return attributes that are projected into the vector index. Attributes that are not in the index projection cannot be returned by `SearchVectors`.

## Deleting a vector index
<a name="VectorSearchWorkingWith.Delete"></a>

Use the `UpdateTable` API with the `VectorIndexUpdates` parameter to delete a vector index.

```
aws dynamodb update-table \
    --table-name Products \
    --vector-index-updates \
        "[
            {\"Delete\": {\"IndexName\": \"ProductEmbeddingIndex\"}}
        ]"
```

When you delete a vector index, DynamoDB removes the index and all of its data. This operation does not affect the base table or its items.