Weaviate: Vector Database with GraphQL API
What this article covers
- What Weaviate is and which features set it apart from other vector databases
- How to install and run Weaviate locally with Docker
- How to design schemas, store data, and perform search queries via GraphQL
- How hybrid search works and why it’s valuable for RAG
- How Weaviate compares to Chroma and Qdrant, and when to choose it
Introduction
You’re working with local RAG and may have already tried Chroma or Qdrant. Now you’re looking for a vector database that offers more than pure vector search. A database built from the ground up for semantic queries, equipped with a powerful query language.
That’s where Weaviate comes in. Weaviate is an open-source vector database distinguished by its GraphQL API, modular system, and built-in hybrid search. Rather than just storing vectors and finding similar ones, Weaviate provides a thoughtful architecture that combines vectorization, filtering, and hybrid search in a single system.
This article walks you through installation, schema design, data storage, and queries step by step. If you haven’t yet covered RAG fundamentals, read that first. Background on embedding models is also helpful.
Why do you need Weaviate?
Imagine running a knowledge base with thousands of documents. Some questions answer well through semantic similarity, that is, vector search. Others contain specific keywords or proper names that pure vector search struggles to find. So you’d need both: vector and keyword search in a single query.
With most vector databases, you must choose one approach or wire up external tools like BM25. Weaviate includes hybrid search out of the box. You weight vector and keyword search in a single query and get results that combine both worlds.
Then there’s the GraphQL API. Instead of learning a proprietary REST interface, you use a standardized query language many developers already know. You can express complex filters, sorting, and relationships between data objects in a single query. That’s especially valuable when your RAG application blends structured metadata with unstructured text.
The modular system is another strength. Weaviate can compute embeddings directly on the server if you enable a module like text2vec-transformers. You send raw text to Weaviate, and the database handles vectorization for you. For local setups, you can also supply your own vectors, which we’ll cover in this article.
Weaviate explained briefly
Weaviate stores data as objects with properties and vectors. Each object belongs to a class you define in the schema. The schema is like a table structure in a relational database: you specify which fields a class has, their data types, and whether they should be vectorized.
During a search query, Weaviate converts the query into a vector, compares it against stored vectors, and returns the most similar objects. That’s classic vector search. With hybrid search, Weaviate combines this vector search with keyword search and weights both according to a parameter you control.
The GraphQL API is the main interface for all queries. You write GraphQL queries to fetch, filter, and search objects. For writing and updating objects, you use the REST API or the Python client, which abstracts both for you.
Who this article is for
This article targets developers already familiar with RAG and vector databases. You should understand what local AI is and how RAG works. If you’ve already experimented with Chroma or Qdrant, this article is the logical next step. You need basic Python skills and should know how to use Docker, since we’ll run Weaviate in a Docker container.
Key terms
| Term | Explanation |
|---|---|
| Class | A category of data objects, similar to a table. Each class has defined properties. |
| Schema | The definition of all classes, properties, and vectorizers. Created before storing data. |
| Object | A single record within a class, consisting of properties and a vector. |
| Vector | A numerical array representing the semantic content of an object. |
| Module | A plugin that handles vectorization or other functions, such as text2vec-transformers. |
| Hybrid Search | A search method that combines and weights vector search and keyword search. |
| GraphQL | A query language for making structured queries against Weaviate. |
| BM25 | An algorithm for keyword search based on term frequency and document length. |
| Vectorizer | A module that automatically converts text to vectors without requiring external embedding computation. |
Installation: Starting Weaviate with Docker
Weaviate runs best in a Docker container. If you haven’t installed Docker yet, check out Docker fundamentals.
The simplest approach is a single Docker container without external modules. This configuration is ideal for getting started because you supply your own vectors and use Weaviate purely as storage and search engine.
docker run -d \
--name weaviate \
-p 8080:8080 \
-e AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED=true \
-e PERSISTENCE_DATA_PATH=/var/lib/weaviate \
-v weaviate_data:/var/lib/weaviate \
semitechnologies/weaviate:latest
Once running, you can reach Weaviate at http://localhost:8080. Check whether the server is running by calling the status endpoint:
curl http://localhost:8080/v1/.well-known/ready
If the response is READY, Weaviate is ready to use. The Docker volume weaviate_data ensures your data persists even after restarting the container.
For more complex setups with integrated vectorization modules, Docker Compose is recommended. Weaviate provides ready-made docker-compose.yml files that spin up additional containers for transformer models. For this article, the simple container is sufficient since we’re using our own vectors.
Installing the Python client
Weaviate provides an official Python client that abstracts the REST and GraphQL APIs. Install it with pip:
pip install weaviate-client
Then connect to your local Weaviate instance in Python:
import weaviate
client = weaviate.connect_to_local(
host="localhost",
port=8080
)
print(client.is_ready()) # True if the connection is established
The Python client uses the new v4 API, which offers a typed and more intuitive interface. If you find older tutorials using the v3 API, be aware that the syntax differs.
Designing the Schema
Before storing data, you create a schema that defines what classes exist and what properties they have. This is also where you decide whether Weaviate should vectorize automatically or if you’ll provide your own vectors.
In our example, we’re creating an Article class with title, content, and source properties. We’re skipping the internal vectorizer and bringing our own vectors instead.
from weaviate.classes.config import Configure
client.collections.create(
name="Article",
vectorizer_config=Configure.Vectorizer.none(),
properties=[
Configure.property(name="title", data_type=Configure.DataType.TEXT),
Configure.property(name="content", data_type=Configure.DataType.TEXT),
Configure.property(name="source", data_type=Configure.DataType.TEXT),
]
)
Setting Configure.Vectorizer.none() tells Weaviate to skip automatic vectorization. You supply the vectors yourself, computed with an external embedding model.
If you prefer to use a module like text2vec-transformers, you configure the vectorizer accordingly. However, this requires an additional container running the transformer model, which increases resource usage.
Storing Data
Now we add objects to the Article class. Since we disabled the internal vectorizer, we must provide vectors ourselves.
articles = client.collections.get("Article")
articles.data.insert_many([
{
"properties": {
"title": "Was ist lokale KI?",
"content": "Lokale KI läuft auf dem eigenen Rechner ohne Cloud-Dienste.",
"source": "blog"
},
"vector": [0.12, 0.34, 0.56, 0.78] # Dein Embedding-Vektor
},
{
"properties": {
"title": "RAG erklärt",
"content": "RAG verbindet Dokumentensuche mit Sprachmodellen für bessere Antworten.",
"source": "blog"
},
"vector": [0.23, 0.45, 0.67, 0.89] # Dein Embedding-Vektor
}
])
In practice, you generate vectors using an embedding model like intfloat/multilingual-e5-large or BAAI/bge-m3. The vector dimension must be consistent across all objects in a class. If you switch embedding models, you need to re-vectorize your data.
Performing Queries
Weaviate supports three search types: pure vector search, keyword search via BM25, and hybrid search. Let’s look at all three.
Vector Search
Vector search takes a query vector and returns the most similar objects:
articles = client.collections.get("Article")
results = articles.query.near_vector(
near_vector=[0.15, 0.40, 0.60, 0.80], # Dein Suchvektor
limit=3
)
for obj in results.objects:
print(obj.properties["title"], obj.properties["content"])
Keyword Search with BM25
BM25 search finds objects by keywords. It excels with proper nouns and specific terms:
results = articles.query.bm25(
query="lokale KI",
limit=3
)
for obj in results.objects:
print(obj.properties["title"], obj.properties["content"])
Hybrid Search
Hybrid search merges vector search and BM25. The alpha parameter controls the weighting: alpha=0 is pure BM25, alpha=1 is pure vector search. A value of 0.5 weights both equally.
results = articles.query.hybrid(
query="lokale KI",
vector=[0.15, 0.40, 0.60, 0.80], # Optional, can be generated automatically
alpha=0.5,
limit=3
)
for obj in results.objects:
print(obj.properties["title"], obj.properties["content"])
Hybrid search is particularly valuable for RAG because many queries have both semantic and keyword-based components. Learn more in the hybrid search article.
Filtering
Weaviate lets you filter search results by properties, useful when you only want to search specific sources or time ranges.
from weaviate.classes.query import Filter
results = articles.query.near_vector(
near_vector=[0.15, 0.40, 0.60, 0.80],
limit=3,
filters=Filter.by_property("source").equal("blog")
)
for obj in results.objects:
print(obj.properties["title"], obj.properties["source"])
Filters combine with and_ and or_ to express complex conditions. This is more powerful than simple metadata filters in other databases.
Comparison: Weaviate vs. Chroma vs. Qdrant
| Feature | Weaviate | Chroma | Qdrant |
|---|---|---|---|
| Query Language | GraphQL | Python API | REST and gRPC |
| Hybrid Search | Built-in | Limited | Via Sparse Vectors |
| Automatic Vectorization | Yes, via modules | Yes, via embedding functions | Yes, via FastEmbed |
| Schema | Explicit, class-based | Implicit, collection-based | Collection-based |
| Scaling | Good, distributed possible | Small to medium | Good, production-ready |
| Learning Curve | Medium | Very low | Low to medium |
| GraphQL | Yes | No | No |
| Filtering | Very powerful, composable | Simple | Very powerful |
| Resource Usage | Medium | Low | Low to medium |
Weaviate shines when you need hybrid search without external tools and prefer GraphQL as your query language. Chroma is simpler for quick starts, Qdrant is more robust for pure vector search on large datasets. Weaviate offers the most features out of the box but requires more upfront learning.
Common Pitfalls
-
Create the schema before the data: Weaviate requires a schema before you can store data. Attempting to insert objects into a non-existent class throws an error. Always define the schema first.
-
Vector dimensions must be consistent: All vectors in a class must have the same dimension. If you switch embedding models, you must recreate the class and reload the data.
-
Vectorizer misconfiguration: If you set
Configure.Vectorizer.none()but don’t provide vectors, Weaviate stores objects without vectors. Queries then fail. Ensure your vectorizer configuration matches how you’re providing data. -
Underestimating GraphQL syntax: GraphQL is powerful but error-prone. A wrong field name or typo in your query produces cryptic errors. Use the Python client, which generates correct syntax for you.
-
Forgetting persistence volumes: Without a Docker volume, all data vanishes after a restart. Always configure
PERSISTENCE_DATA_PATHwith a volume. -
Resource overhead with modules: Enabling vectorization modules like
text2vec-transformerssignificantly increases RAM and CPU demand. For local setups without GPU, computing vectors externally is often better. -
Leaving authentication disabled: Our example enables anonymous access, fine for local testing but never for publicly reachable instances.
-
Not understanding indexes: Weaviate uses HNSW for vector indexing by default. With very large datasets, familiarize yourself with index parameters to optimize search speed.
Hardware, Costs, and Security
Weaviate without vectorization modules runs lean. A machine with 4 GB RAM and a standard CPU handles a few thousand documents just fine. Once you enable modules like text2vec-transformers, RAM requirements climb to 8 GB or higher, and a GPU significantly speeds up vectorization.
Weaviate is open source and free. The Community Edition includes all the features you need for local RAG projects. A paid cloud version exists, but it’s irrelevant for local deployments.
Security follows the same principle as other local databases: as long as Weaviate stays within your own network, your data stays protected. If you expose Weaviate over the network, enable authentication and run it behind a reverse proxy with TLS. Since everything stays local, you gain a major advantage over cloud-based vector databases, as covered in the article on local AI versus cloud AI.
Further Reading
- Vector Database Overview - All vector database articles
- Local RAG - Complete RAG guide
- RAG Fundamentals - How RAG works
- Embedding Models - Turning text into vectors
- Hybrid Search - Combining vector and keyword search
- Chroma - Lightweight vector database
- Qdrant - Scalable vector database
- Docker Basics - Understanding containers
FAQ
Do I need to learn GraphQL to use Weaviate?
Not necessarily. The Python client abstracts away the GraphQL queries for you. That said, if you need complex queries with filters and relationships, understanding GraphQL basics helps.
Can Weaviate calculate its own vectors?
Yes, using modules like text2vec-transformers or text2vec-cohere. For local setups without a GPU, it’s often more efficient to compute vectors externally and pass them to Weaviate.
Is Weaviate free?
Yes, the open source version is free and covers everything you need for local projects. A paid cloud version exists, but it’s unnecessary for local deployments.
How many documents can Weaviate handle locally?
It depends on RAM and disk space. Weaviate handles hundreds of thousands to millions of objects. For very large datasets, tune your index parameters.
Can I connect Weaviate with Ollama?
Yes. Ollama provides the language model, Weaviate provides the vector database. Your Python script bridges both: Weaviate finds relevant documents, Ollama generates the response.
What’s the difference between Weaviate and Chroma?
Chroma is simpler and faster to set up, ideal for prototypes. Weaviate offers more features like GraphQL, Hybrid Search, and a module system, but requires more setup complexity.
Do I need Docker for Weaviate?
Docker is the recommended approach, though binaries are available. For local testing and production systems, Docker is simplest and best documented.
Does Weaviate support hybrid search?
Yes, Hybrid Search is one of Weaviate’s strengths. You weight vector and keyword search using the alpha parameter and get combined results.
Can I run Weaviate on a NAS?
Yes, with Docker. Make sure you have sufficient RAM and fast storage. Weaviate benefits from SSD storage, especially with large datasets.
How do I secure Weaviate?
Local instances without network exposure are usually safe in secure networks. To access over the network, enable authentication and use a reverse proxy with TLS encryption.
What’s the difference between Weaviate and Qdrant?
Qdrant is leaner and focused on pure vector search. Weaviate offers more features like GraphQL, a module system, and built-in Hybrid Search, but uses slightly more resources.
Sources
- Weaviate official website: weaviate.io
- Weaviate documentation: weaviate.io/developers/weaviate
- Weaviate Python Client: github.com/weaviate/weaviate-python-client
- Weaviate GitHub repository: github.com/weaviate/weaviate
- Article on Vector Databases in this series
- Article on Hybrid Search in this series


