Skip to main content
Payloads are JSON objects attached to points that store metadata alongside vectors. They enable filtering, sorting, and enriching search results with structured data.

What are Payloads?

Each point in Qdrant can have an optional payload containing arbitrary JSON data:
from qdrant_client import QdrantClient, models

client = QdrantClient("localhost", port=6333)

client.upsert(
    collection_name="products",
    points=[
        models.PointStruct(
            id=1,
            vector=[0.1, 0.2, 0.3, 0.4],
            payload={
                "name": "Laptop",
                "price": 1299.99,
                "category": "electronics",
                "in_stock": True,
                "tags": ["computer", "portable", "work"],
                "specs": {
                    "ram": "16GB",
                    "storage": "512GB SSD"
                },
                "release_date": "2024-01-15T00:00:00Z"
            }
        )
    ]
)
// From lib/segment/src/types.rs:1888-1890
pub struct Payload(pub Map<String, Value>);
Payloads are stored separately from vectors, making them efficient for filtering without loading vector data.

Supported Data Types

Qdrant payloads support rich JSON data types:

Primitive Types

payload = {
    # String
    "title": "Vector Database Guide",
    "author": "Jane Smith",
    
    # Integer (i64)
    "views": 1500,
    "year": 2024,
    
    # Float (f64)
    "rating": 4.7,
    "price": 29.99,
    
    # Boolean
    "published": True,
    "featured": False
}
// From lib/segment/src/types.rs:2029-2042
pub enum PayloadSchemaType {
    Keyword,   // String values
    Integer,   // i64 integers
    Float,     // f64 floats
    Geo,       // Geographic points
    Text,      // Full-text searchable strings
    Bool,      // Boolean values
    Datetime,  // RFC3339 datetime strings
    Uuid,      // UUID identifiers
}

Arrays

Store multiple values of the same type:
payload = {
    "tags": ["machine-learning", "nlp", "vectors"],
    "scores": [0.8, 0.9, 0.75, 0.85],
    "ids": [101, 102, 103]
}

Nested Objects

Hierarchical data structures:
payload = {
    "product": {
        "name": "Smartphone",
        "manufacturer": {
            "name": "TechCorp",
            "country": "USA"
        },
        "specs": {
            "screen_size": 6.1,
            "battery": "4000mAh"
        }
    }
}

# Access nested fields with dot notation
client.scroll(
    collection_name="products",
    scroll_filter=models.Filter(
        must=[
            models.FieldCondition(
                key="product.manufacturer.country",
                match=models.MatchValue(value="USA")
            )
        ]
    )
)

Geographic Points

Latitude and longitude coordinates:
payload = {
    "location": {
        "lon": -0.1276,
        "lat": 51.5074
    },
    "city": "London"
}
// From lib/segment/src/types.rs:1762-1766
pub struct GeoPoint {
    pub lon: OrderedFloat<f64>,  // -180 to 180
    pub lat: OrderedFloat<f64>,  // -90 to 90
}
Geo points enable radius and bounding box searches for location-based applications.

Datetime Values

RFC3339 formatted datetime strings:
payload = {
    "created_at": "2024-01-15T10:30:00Z",
    "updated_at": "2024-03-20T15:45:30Z",
    "published_date": "2024-02-01T00:00:00Z"
}

# Filter by date range
client.scroll(
    collection_name="articles",
    scroll_filter=models.Filter(
        must=[
            models.FieldCondition(
                key="created_at",
                range=models.DatetimeRange(
                    gte="2024-01-01T00:00:00Z",
                    lt="2024-04-01T00:00:00Z"
                )
            )
        ]
    )
)
Qdrant stores datetimes as microsecond timestamps internally for efficient range queries.

UUID Values

Universally unique identifiers:
import uuid

payload = {
    "document_id": str(uuid.uuid4()),
    "user_id": "550e8400-e29b-41d4-a716-446655440000"
}

Payload Indexing

Indexing payload fields dramatically improves filter performance:

Creating Payload Indexes

# Index a keyword field
client.create_payload_index(
    collection_name="products",
    field_name="category",
    field_schema=models.PayloadSchemaType.KEYWORD
)

# Index an integer field
client.create_payload_index(
    collection_name="products",
    field_name="price",
    field_schema=models.PayloadSchemaType.INTEGER
)

# Index a text field for full-text search
client.create_payload_index(
    collection_name="products",
    field_name="description",
    field_schema=models.PayloadSchemaType.TEXT
)

# Index a geo field for location queries
client.create_payload_index(
    collection_name="products",
    field_name="location",
    field_schema=models.PayloadSchemaType.GEO
)
// From lib/segment/src/types.rs:429-437
pub struct PayloadIndexInfo {
    pub data_type: PayloadSchemaType,
    pub params: Option<PayloadSchemaParams>,
    pub points: usize,  // Number of indexed points
}
Always index fields you frequently filter on. Without indexes, filters require scanning all points.

Advanced Index Configuration

Keyword Indexes

client.create_payload_index(
    collection_name="products",
    field_name="category",
    field_schema=models.KeywordIndexParams(
        type="keyword",
        on_disk=False  # Store in RAM for fastest filtering
    )
)

Integer Indexes with Range Support

client.create_payload_index(
    collection_name="products",
    field_name="year",
    field_schema=models.IntegerIndexParams(
        type="integer",
        range=True,   # Enable range queries
        lookup=True   # Enable exact match queries
    )
)

Text Indexes with Tokenization

client.create_payload_index(
    collection_name="articles",
    field_name="content",
    field_schema=models.TextIndexParams(
        type="text",
        tokenizer="word",           # word, whitespace, multilingual
        min_token_len=2,
        max_token_len=20,
        lowercase=True
    )
)
Text indexes enable full-text search within payloads using match queries.

Querying Payloads

# Search with payload filters
results = client.search(
    collection_name="products",
    query_vector=[0.1, 0.2, 0.3, 0.4],
    query_filter=models.Filter(
        must=[
            models.FieldCondition(
                key="category",
                match=models.MatchValue(value="electronics")
            ),
            models.FieldCondition(
                key="price",
                range=models.Range(lte=1000.0)
            ),
            models.FieldCondition(
                key="in_stock",
                match=models.MatchValue(value=True)
            )
        ]
    ),
    limit=10
)

Match Conditions

# Exact match
models.FieldCondition(
    key="category",
    match=models.MatchValue(value="electronics")
)

# Match any of multiple values
models.FieldCondition(
    key="category",
    match=models.MatchAny(any=["electronics", "computers", "phones"])
)

# Full-text match
models.FieldCondition(
    key="description",
    match=models.MatchText(text="laptop portable")
)

Range Conditions

# Numeric ranges
models.FieldCondition(
    key="price",
    range=models.Range(
        gte=100.0,  # Greater than or equal
        lt=500.0    # Less than
    )
)

# Date ranges
models.FieldCondition(
    key="created_at",
    range=models.DatetimeRange(
        gte="2024-01-01T00:00:00Z",
        lt="2024-12-31T23:59:59Z"
    )
)

Geographic Queries

# Radius search
models.FieldCondition(
    key="location",
    geo_radius=models.GeoRadius(
        center=models.GeoPoint(
            lon=-0.1276,
            lat=51.5074
        ),
        radius=5000.0  # meters
    )
)

# Bounding box search
models.FieldCondition(
    key="location",
    geo_bounding_box=models.GeoBoundingBox(
        top_left=models.GeoPoint(lon=-0.15, lat=51.52),
        bottom_right=models.GeoPoint(lon=-0.10, lat=51.48)
    )
)

Nested Field Queries

# Query nested fields with dot notation
models.FieldCondition(
    key="product.specs.ram",
    match=models.MatchValue(value="16GB")
)

Array Queries

# Match any element in array
models.FieldCondition(
    key="tags",
    match=models.MatchAny(any=["nlp", "ml", "ai"])
)

Payload Operations

Setting Payload

Merge new fields into existing payload:
client.set_payload(
    collection_name="products",
    payload={
        "updated_at": "2024-03-20T10:30:00Z",
        "views": 1500
    },
    points=[1, 2, 3, 4, 5]
)

Overwriting Payload

Replace entire payload:
client.overwrite_payload(
    collection_name="products",
    payload={
        "name": "New Product",
        "category": "electronics"
    },
    points=[1, 2, 3]
)

Deleting Payload Fields

Remove specific keys:
client.delete_payload(
    collection_name="products",
    keys=["old_field", "temporary_data"],
    points=[1, 2, 3]
)

Clearing All Payload

Remove entire payload while keeping vector:
client.clear_payload(
    collection_name="products",
    points_selector=models.PointIdsList(points=[1, 2, 3])
)

Payload in Search Results

Control what payload data is returned:
# Return all payload
results = client.search(
    collection_name="products",
    query_vector=[0.1, 0.2, 0.3],
    with_payload=True,
    limit=10
)

# Return no payload
results = client.search(
    collection_name="products",
    query_vector=[0.1, 0.2, 0.3],
    with_payload=False,
    limit=10
)

# Return specific fields only
results = client.search(
    collection_name="products",
    query_vector=[0.1, 0.2, 0.3],
    with_payload=models.PayloadSelector(
        include=["name", "price", "category"]
    ),
    limit=10
)

# Exclude specific fields
results = client.search(
    collection_name="products",
    query_vector=[0.1, 0.2, 0.3],
    with_payload=models.PayloadSelector(
        exclude=["large_field", "temporary_data"]
    ),
    limit=10
)
For better performance, only request the payload fields you actually need.

Best Practices

Create indexes for any field you filter on regularly. Indexed filters are orders of magnitude faster than unindexed ones.
Aim for payloads under 1KB per point. Store large objects (images, documents) externally and reference them in the payload.
Use the correct PayloadSchemaType when creating indexes:
  • keyword for exact match filtering (categories, tags, IDs)
  • integer for numeric exact match and ranges
  • text for full-text search
  • geo for location queries
Keep payload structure consistent across points. This makes querying easier and reduces storage overhead.
Deep nesting can make queries complex. Consider flattening structures when possible.
Use PayloadSelector to fetch only the fields you need, reducing network transfer and deserialization time.

Performance Considerations

Memory Usage

# Store indexes on disk for large collections
client.create_payload_index(
    collection_name="large_collection",
    field_name="category",
    field_schema=models.KeywordIndexParams(
        type="keyword",
        on_disk=True  # Reduce RAM usage
    )
)

Filter Selectivity

Combine multiple filters for better performance. Qdrant optimizes filter execution order based on selectivity.
# Multiple filters are AND'ed together efficiently
models.Filter(
    must=[
        models.FieldCondition(
            key="category",
            match=models.MatchValue(value="electronics")  # High selectivity
        ),
        models.FieldCondition(
            key="price",
            range=models.Range(lte=1000.0)  # Further narrows results
        )
    ]
)

Points

Learn how payloads are attached to points

Indexing

Understand how payload indexes work

Collections

Learn about collection-level configurations

Vectors

Understand the vector component of points