Skip to content

Add article: How to Handle Bulk Uploads in Qdrant#2489

Open
jkupchanko wants to merge 7 commits into
masterfrom
article/bulk-uploads-in-qdrant
Open

Add article: How to Handle Bulk Uploads in Qdrant#2489
jkupchanko wants to merge 7 commits into
masterfrom
article/bulk-uploads-in-qdrant

Conversation

@jkupchanko

@jkupchanko jkupchanko commented Jul 9, 2026

Copy link
Copy Markdown

🔗 Preview this change

View the article on the deploy preview →

https://deploy-preview-2489--condescending-goldwasser-91acf0.netlify.app/articles/bulk-uploads-in-qdrant/


PREVIEW

Summary

New production-ops article: How to Handle Bulk Uploads in Qdrant.

It walks through best practices for ingesting large datasets into Qdrant — on-disk vector storage, payload indexes, quantization, on-disk sparse indexes, batching, parallelization, and sharding — for both dense and sparse vectors, with a "Choosing the Right Mix" comparison table at the end.

What's included

  • content/articles/bulk-uploads-in-qdrant.md
  • Cover / preview / social images (static/articles_data/bulk-uploads-in-qdrant/preview/)
  • Seven flow diagrams (one per strategy) showing the recommended vs. default path, in the house diagram style
  • Color-coded vector-type badges, best-fit / watch-for callouts, and two benchmark callouts

Review

👋 @kanungle — this is ready for your review. The Netlify Deploy Preview on this PR will render the full article on the site so you can read it in context (cover, diagrams, code, and table).

Notes

  • All Python snippets use current qdrant-client APIs.
  • Preview images are included; the article follows the standard front-matter + preview_dir convention.
  • Scope is intentionally just this article — no theme or shared-file changes.

🤖 Generated with Claude Code

New production-ops article covering bulk upload best practices in Qdrant:
on-disk vector storage, payload indexes, quantization, sparse-index
on-disk storage, batching, parallelization, and sharding — for both
dense and sparse vectors.

Includes:
- content/articles/bulk-uploads-in-qdrant.md
- Cover / preview / social images (preview/)
- Seven flow diagrams (one per option) illustrating the recommended vs
  default path for each strategy

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@netlify

netlify Bot commented Jul 9, 2026

Copy link
Copy Markdown

Deploy Preview for condescending-goldwasser-91acf0 ready!

Name Link
🔨 Latest commit 83527f8
🔍 Latest deploy log https://app.netlify.com/projects/condescending-goldwasser-91acf0/deploys/6a56986184a23d0007cfcace
😎 Deploy Preview https://deploy-preview-2489--condescending-goldwasser-91acf0.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@jkupchanko jkupchanko requested a review from kanungle July 9, 2026 23:34
@kanungle

Copy link
Copy Markdown
Contributor

@jkupchanko thanks for creating the article preview images, however, let me do these in the future so I can ensure they're on-brand with the others. I've updated those images and will start reviewing the article content now.

@kanungle kanungle left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work @jkupchanko. Good first draft.

I've left some requested changes. Images should not be embedded as html, and code snippets can be more concise. Some other small tweaks as well.

@generall is this aligned with your expectations of our revised advice?

Comment on lines +22 to +24
Before we get into the best practices, it's important to remember that not all vectors behave the same way during ingestion. Dense and sparse vectors use different indexing approaches, which means they can create different performance considerations during bulk uploads.

Let's quickly break down the difference before moving into the recommended upload strategies.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move this to the beginning of next section


Sparse vectors use a separate indexing approach, and the sparse index is updated as points are written. This means sparse vector ingestion should not be treated the same way as dense HNSW indexing.

This difference matters because the right bulk upload strategy depends on the type of vectors being uploaded and the indexing work Qdrant has to handle during ingestion.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove; not needed


## Choosing the Right Bulk Upload Strategy

Before we go through the best practices, understand there is no single configuration that works best for every bulk upload. The right approach depends on what you are trying to improve: upload speed, memory usage, search availability, or a balance of all three.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is no single configuration that works best fore every bulk upload

make bold

Comment on lines +162 to +166
from qdrant_client import QdrantClient, models

collection_name = "my_collection"

client = QdrantClient(url="http://localhost:6333")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this part of code not needed

Comment on lines +125 to +130
from qdrant_client import QdrantClient, models

collection_name = "my_collection"

client = QdrantClient(url="http://localhost:6333")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This part of code not needed

Comment on lines +200 to +222
from qdrant_client import QdrantClient, models

collection_name = "my_collection"

client = QdrantClient(url="http://localhost:6333")

client.create_collection(
collection_name=collection_name,
vectors_config=models.VectorParams(
size=768,
distance=models.Distance.COSINE,
on_disk=True,
),
)

points = [
models.PointStruct(
id=i,
vector=[0.1] * 768,
payload={"category": "example"},
)
for i in range(1000)
]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This part of code not needed

Comment on lines +252 to +257
from qdrant_client import QdrantClient, models

collection_name = "my_collection"

client = QdrantClient(url="http://localhost:6333")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This part of code not needed

Comment on lines +281 to +286
from qdrant_client import QdrantClient, models

collection_name = "my_collection"

client = QdrantClient(url="http://localhost:6333")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This part of code not needed


The safest approach is to choose the right strategy for the workload instead of relying on one universal configuration. Dense vectors, sparse vectors, and hybrid setups can all create different performance considerations during ingestion.

By designing the collection and upload process before ingestion starts, you can make bulk uploads more efficient, more stable, and easier to scale as your dataset grows. For help sizing your deployment, see the [Capacity Planning guide](/documentation/capacity-planning/).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For help sizing your deployment, see the Capacity Planning guide.

Don't reference this. It kind of sucks. Instead point to https://sizing.qdrant.tech


<strong style="color:#ff9800;">⚠ Watch for:</strong> More shards are not always better. Each shard adds overhead, so the shard count should match the size of the deployment and the amount of write parallelism you actually need.

## Choosing the Right Mix

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good start for offering clear guidance and takeaways, but I feel it's still not solving my needs in figuring out what exactly to do. Maybe we point to Qdrant Skills here?

- Convert all diagram embeds from HTML <img> to markdown image syntax
- Trim code snippets to the focal call (drop client/collection boilerplate;
  drop the points-generation block in the batching example)
- Move the "break down the difference" line to open the Vector Type section
- Remove the redundant closing sentence in Why Vector Type Matters
- Bold "there is no single configuration that works best for every bulk upload"
- Replace the Capacity Planning link with the Qdrant sizing calculator
  (sizing.qdrant.tech)
- Add a pointer to Qdrant Skills for scenario-specific guidance

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@jkupchanko

Copy link
Copy Markdown
Author

Thanks for the review @kanungle! Addressed everything in 0922daf:

  • Images → converted all 7 diagrams from HTML <img> to markdown ![alt](url)
  • Code snippets → trimmed each to just the focal call (dropped the import / collection_name / client = QdrantClient(...) boilerplate; also removed the points = [...] construction in the batching example)
  • Moved the "break down the difference" line to open the Why Vector Type Matters section
  • Removed the redundant closing sentence in that section
  • Bolded "there is no single configuration that works best for every bulk upload"
  • Replaced the Capacity Planning link with the sizing calculator (sizing.qdrant.tech)

On the guidance point (comparison-table section): I added a pointer to Qdrant Skills. Happy to go further if it's still not concrete enough — e.g. an explicit "if you're unsure, start here" default recommendation. Let me know what you'd prefer.

Ready for another look when you have a chance.

@jkupchanko jkupchanko requested a review from kanungle July 10, 2026 15:30

@kanungle kanungle left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple very minor changes. I would also give @abdonpijpelink and @generall a chance to take a look. Let's plan on merging monday/tuesday


## Why Vector Type Matters

Let's quickly break down the difference before moving into the recommended upload strategies.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, go ahead and move this line back to where you had it. Or you move "Before we get into..." sentence into this section too (which was my original intended feedback)

| One upload worker is not enough | Option 6: Parallelize Uploads | Option 7: Multiple Shards | Too much parallelism can create pressure on CPU, memory, disk I/O, and network resources. |
| Very large dataset with high write volume | Option 7: Multiple Shards | Option 5: Batch Uploads, Option 6: Parallelize Uploads | More shards add overhead, so shard count should match the deployment size and write parallelism needed. |

Still deciding exactly what to configure for your workload? [Qdrant Skills](https://skills.qdrant.tech) provides hands-on, scenario-based guidance that walks you through the specific settings for your situation.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Point to "Qdrant's Agent Skills" and this link: https://qdrant.tech/documentation/skills/


![Diagram: uploading one point per request creates high overhead, while grouping points into batches of 64-256 is about 5x faster.](/articles_data/bulk-uploads-in-qdrant/option5-batching.png)

<div style="margin:1.5rem 0; padding:16px 18px; border:1px solid rgba(38,166,154,0.35); border-left:3px solid #26a69a; border-radius:8px; background:rgba(38,166,154,0.08);"><div style="font-size:11px; font-weight:700; letter-spacing:0.08em; text-transform:uppercase; color:#4db6ac; margin-bottom:6px;">📊 Benchmark</div>In testing with 10,000 768-dim vectors, batching at <strong>64 points per request</strong> was <strong style="color:#4db6ac;">~5× faster</strong> than uploading one point at a time.</div>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure we can use this styling. @abdonpijpelink can you opine?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the end it's up to DevRel how you style the articles, but it seems inconsistent with the other articles (and docs). Also, I'm not sure these colors are on-brand?

@kanungle

Copy link
Copy Markdown
Contributor

@abdonpijpelink @generall if you have time or preference for reviewing, I've added you to the PR. It looks good to me though and will plan on merging on monday/tuesday

@abdonpijpelink abdonpijpelink left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left a couple of comments.

A couple of more general remarks:

  • The diagrams do not follow the diagram best practices (see Figma). Most importantly, elements in diagrams should use colors of the same shade, e.g. if box background is blue - text should be dark blue. Here, the diagrams use black text on a colored background. I'm also not sure they're using the Qdrant color palette?
  • I feel the options are presented in a somewhat random order? While quantization is a useful tool to reduce memory pressure, should it come before parallelization and batching in an article about bulk uploading?


![Diagram: uploading one point per request creates high overhead, while grouping points into batches of 64-256 is about 5x faster.](/articles_data/bulk-uploads-in-qdrant/option5-batching.png)

<div style="margin:1.5rem 0; padding:16px 18px; border:1px solid rgba(38,166,154,0.35); border-left:3px solid #26a69a; border-radius:8px; background:rgba(38,166,154,0.08);"><div style="font-size:11px; font-weight:700; letter-spacing:0.08em; text-transform:uppercase; color:#4db6ac; margin-bottom:6px;">📊 Benchmark</div>In testing with 10,000 768-dim vectors, batching at <strong>64 points per request</strong> was <strong style="color:#4db6ac;">~5× faster</strong> than uploading one point at a time.</div>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the end it's up to DevRel how you style the articles, but it seems inconsistent with the other articles (and docs). Also, I'm not sure these colors are on-brand?


![Diagram: original full-size vectors stay on disk while a compressed INT8 copy is kept in RAM, so search stays fast with lower memory use.](/articles_data/bulk-uploads-in-qdrant/option3-quantization.png)

In Python, scalar quantization can be configured when creating the collection:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe use TurboQuant instead of scalar?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, thanks

- Move the "Before we get into..." sentence into the Why Vector Type
  Matters section (per Neil's clarified intent)
- Replace all custom-styled inline HTML (vector-type badges, best-fit/
  watch-for callouts, benchmark boxes) with standard markdown for
  consistency with other articles and docs
- Point to "Qdrant's Agent Skills" at qdrant.tech/documentation/skills/
- Switch Option 3 example from scalar quantization to TurboQuant

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@kanungle

Copy link
Copy Markdown
Contributor

@abdonpijpelink

In the end it's up to DevRel how you style the articles, but it seems inconsistent with the other articles (and docs). Also, I'm not sure these colors are on-brand?

I believe Thierry previously used this formatting which was approved, so I think it's okay. That being said, @jkupchanko you can do a quick update on colors with this reference

The diagrams do not follow the diagram best practices (see Figma). Most importantly, elements in diagrams should use colors of the same shade, e.g. if box background is blue - text should be dark blue.

I did not intend to be that detailed on the diagrams for font colors. Thought black should be okay enough. That being said, @jkupchanko please feed these diagrams to ChatGPT then use it to restyle your current images. Should take 5-10 mins. If those new diagrams still come out wrong, try feeding this as a source style.

I feel the options are presented in a somewhat random order? While quantization is a useful tool to reduce memory pressure, should it come before parallelization and batching in an article about bulk uploading?

Yes, absolutely. This is the feedback I was looking for. I feel overall this article has a lot of methods but no strong prescription on when and how to use them. I think we need more guidance here from the solutions architect team, but in the absence of that, we can do our own tests (@jkupchanko to run).

My other thought was to use skills to advise on different scenarios and how to configure bulk uploads, but in order to do that, we first need to understand the right content to go into skills, which, again, likely require our own tests.

Ideally, if this knowledge exists within qdrant, we would love to get a download of that information into our brains before running the tests.

@kanungle

kanungle commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Overall, we're trying to get as close as we can to providing some kind of guidance, even if we're not 100% prescriptive. I'm not sure if tests alone can solve for this or if we just need to think about logically orienting the structure of this article better. In particular, this section leaves a lot to be desired for me. @jkupchanko let's discuss

jkupchanko and others added 2 commits July 14, 2026 12:31
Swap the "Choosing the Right Mix" comparison table for a top-down
decision-tree image that walks readers from vector type to a concrete
storage/quantization/sharding configuration.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… practices

Replace all seven strategy diagrams with updated versions, and group
batching, parallelization, and sharding under "Best Practices for Every
Upload" since they apply to any bulk upload rather than being
situational options.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@jkupchanko jkupchanko requested a review from kanungle July 14, 2026 20:16
@jkupchanko

Copy link
Copy Markdown
Author

@kanungle updated since your last review:

  • Replaced the "Choosing the Right Mix" comparison table with a top-down decision-tree diagram that walks readers from vector type to a concrete storage / quantization / sharding configuration.
  • Refreshed all seven strategy diagrams with updated visuals.
  • Reframed batching, parallelization, and sharding as "Best Practices for Every Upload" (grouped subsections, no longer numbered "options"), since they apply to any bulk upload rather than being situational choices.

Ready for another look when you get a chance — thanks!

@kanungle kanungle left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good round of fixes on the images, code trimming, and the sizing calculator link — thanks. A few things before this ships:

  1. Unpublishing indexing-optimization.md needs a redirect. Setting it to draft: true will 404 /articles/indexing-optimization/ and drop its backlinks. Have Claude Code update the redirect file links.

  2. Frontmatter fixes to match other articles: date should be a full timestamp (2026-07-14T00:00:00.000Z, see indexing-optimization.md), and you're missing author_link and keywords. Description is 159 chars; keep it under 140. Try: "Plan bulk uploads in Qdrant: batching, parallelization, sharding, payload indexes, quantization, and on-disk storage."

  3. Decision-tree diagram (choosing-the-right-mix.png): the logic is right, but every box is rendering empty — each label floats outside its blank box. Moving the existing text inside the boxes fixes it:

    • Root box: "Uploading Bulk Data"
    • Branch heads: "Dense Vectors" / "Sparse Vectors" / "Both (Sparse + Dense)" inside the three top boxes
    • Decision boxes get their questions: "Memory issues?", "Keep full precision?", "How aggressive?", "Still too large?", "Heavy writes?", "Multi-node?"
    • Outcome boxes get their results: "In RAM (on_disk=False)", "On disk (on_disk=True)", "TurboQuant 4-bit (~8x smaller)", "TurboQuant 1-bit (up to 32x smaller)", "Index in RAM", "Index on disk", "On disk + fp16 (datatype=float16)", "One shard (shard_number=1)", "Pre-shard (shard_number >= 2)", "Shard on cluster + replication"

    While you're in there: keep one Yes/No legend (there's a chip version top-right and a "Legend:" row at the bottom), and crop out the "…" button baked into the top-right corner.

  4. Three images need compression: option5-batching.png (1.1MB), option1-memory.png (1.0MB), and choosing-the-right-mix.png (940KB). Run them through compressor.io — target under 250KB each. The other five are fine.

  5. Benchmark callouts need context. Add environment and Qdrant version to both. 10k vectors is small for an article about bulk scale; if re-running at 1M isn't practical, qualify that gains grow with scale instead.

  6. TurboQuant snippet: show bits= since the decision tree recommends 4-bit vs 1-bit; right now the code doesn't match the diagram.

  7. Two additions would round it out: a short note on prefer_grpc=True (gRPC is meaningfully faster for bulk upload) and a line on checking collection status is green before serving traffic. Also drop the repeated "In Python, this can look like:" lead-in; it's verbatim five times.

After the redirect + frontmatter fixes this is good to merge.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants