Enterprise DNA

Omni by Enterprise DNA

Enterprise DNA Resources

Step-by-step how-tos. Practical AI operating-system thinking for owners, operators, and teams doing real work.

220k+

Data professionals

Omni

AI agents and apps

Audit

Map the manual work

Guide Intermediate General

Weaviate Tutorial: Vector Search for Beginners

A hands-on Weaviate walkthrough covering local setup, authentication, your first vector search, and the configuration dials that matter in production.

Sam McKay |
Weaviate Tutorial: Vector Search for Beginners

What Weaviate actually is

Strip away the marketing and Weaviate is an open-source vector database written in Go. It stores both data objects and their vector representations, then lets you query those vectors using similarity search. That is the core job. Everything else is configuration on top.

The technical shape is straightforward. You create a collection, which is roughly equivalent to a table in a relational database. Each collection has a defined schema that includes properties (the fields you want to filter on) and a vectorizer module that decides how text or images get turned into vectors. When you add an object, Weaviate runs it through the configured vectorizer and stores the resulting vector alongside the original data. When you query, you send a search term, Weaviate embeds it the same way, and returns the nearest neighbors ranked by distance.

What separates Weaviate from a basic vector store like a flat FAISS index is the production-grade plumbing around that core. You get a GraphQL API, REST API, native client libraries in Python, TypeScript, Go and Java, horizontal scaling through sharding, replication for availability, and built-in hybrid search that combines vector similarity with traditional BM25 keyword scoring. The current version runs as a single Docker container for development or as a clustered deployment behind a load balancer for production.

The mental model worth holding is this. Weaviate is not a replacement for Postgres. It is a specialized store optimized for similarity queries over high-dimensional vectors, with optional structured filtering on the side. If your workload is dominated by exact match lookups, you are paying for features you do not use. If your workload is dominated by finding the items semantically closest to a query, you have come to the right place.

Setup and authentication

The fastest path from zero to a running instance is Docker. Pull the official image, expose two ports, and you have a local server in under a minute. The minimum command looks like this.

docker run -d —name weaviate -p 8080:8080 -p 50051:50051 -e AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED=true -e PERSISTENCE_DATA_PATH=/var/lib/weaviate semitechnologies/weaviate:latest

That sets up Weaviate with anonymous access enabled, which is fine for local experimentation. Port 8080 serves REST and GraphQL, port 50051 serves gRPC. The data path flag tells the container where to persist objects between restarts.

For anything beyond local tinkering you want authentication. Weaviate supports API key auth and OIDC. The relevant environment variables are AUTHENTICATION_APIKEY_ENABLED, AUTHENTICATION_APIKEY_ALLOWED_KEYS, AUTHENTICATION_APIKEY_USERS, and AUTHORIZATION_ADMINLIST_ENABLED. A production-flavored startup might set AUTHENTICATION_APIKEY_ENABLED=true and pass a list of allowed keys through AUTHENTICATION_APIKEY_ALLOWED_KEYS with comma-separated values.

If you do not want to run infrastructure yourself, Weaviate Cloud Services (WCS) hosts managed clusters. You sign up, create a sandbox cluster for free, and get an API key plus a cluster URL. The Python client takes both as arguments at initialization and handles auth headers for you.

Authentication in client code looks like this conceptually. You instantiate the client with a URL and either an API key or a bearer token. Every subsequent request carries the credential automatically. The Python client uses weaviate.Client(url, auth_client_secret=weaviate.AuthApiKey(api_key=”…”)). The TypeScript client uses weaviate.client({ scheme: “https”, host: ”…”, apiKey: new ApiKey(”…”) }). Pick whichever stack you already use and the pattern is the same.

First working example

Assume you have Weaviate running locally and the Python client installed (pip install weaviate-client). The goal is to ingest a small dataset, run a semantic query, and inspect the results.

Step one, define a collection. Weaviate can infer a schema from data, but for a clean first example you set it up explicitly. You give the collection a name, list the properties you want to filter on, and pick a vectorizer module.

client.schema.create_class({ “class”: “Article”, “vectorizer”: “text2vec-transformers”, “properties”: [ {“name”: “title”, “dataType”: [“text”]}, {“name”: “body”, “dataType”: [“text”]}, {“name”: “category”, “dataType”: [“text”]}, ], })

The text2vec-transformers module ships with the default Docker image and runs an embedding model locally, so no external API call is required. Other modules like text2vec-openai, text2vec-cohere, and text2vec-huggingface route to external services and need credentials.

Step two, add objects. You send a batch with one record per item. Each record contains the property values, and the vectorizer generates embeddings automatically when you save.

client.batch.add_data_object( data_object={“title”: ”…”, “body”: ”…”, “category”: “ml”}, class_name=“Article”, )

Run client.batch.flush() when you are done adding, which forces pending writes to commit.

Step three, query. A semantic search asks for the objects whose vectors are nearest to the query vector. The nearText filter takes the raw query string and handles embedding on the server.

result = client.query.get(“Article”, [“title”, “body”, “category”]).with_near_text({“concepts”: [“how do transformers work”]}).with_limit(3).do()

The response is a GraphQL-shaped dictionary. Pull the data[“Get”][“Article”] list and you have your top three matches ranked by semantic similarity. From end to end this is roughly thirty lines of Python and takes a few minutes the first time.

Key settings that matter

The defaults work for demos and break under real load. The settings most people ignore, ranked by how much pain they cause, are these.

Distance metric. Weaviate supports cosine, dot, l2-squared, and hamming. Cosine is the typical default and matches what most embedding models produce. If your model was trained for inner product similarity (some retrieval models are), switch to dot. Picking the wrong metric silently degrades every query you run.

HNSW parameters. Weaviate uses Hierarchical Navigable Small World graphs for approximate nearest neighbor search. The two knobs that matter are efConstruction, which controls index build quality, and maxConnections, which controls graph connectivity. Higher values give better recall at the cost of memory and build time. For a working prototype the defaults are fine. For a production corpus over a few million vectors, raising efConstruction to 128 and maxConnections to 32 is a reasonable starting point.

Vectorizer module choice. This determines both cost and quality. Local transformers are free but slow per request. OpenAI and Cohere are fast and high quality but charge per token and add an external dependency. If you have compliance constraints that forbid sending data to third parties, you need a self-hosted option and that constrains the rest of your architecture.

Hybrid search alpha. When you combine BM25 keyword scoring with vector similarity, alpha controls the blend. Alpha of 0 is pure keyword, alpha of 1 is pure vector, alpha of 0.5 is an even mix. Most workloads land between 0.3 and 0.7. There is no universal right answer and the right number depends on whether your queries are dominated by precise terms or fuzzy concepts.

Replication factor. Set REPLICATION_FACTOR in the cluster configuration to the number of copies you want per shard. Factor of 1 means no redundancy, factor of 3 means you can lose two nodes and stay available. Replication also helps read throughput because queries fan out across replicas.

Shard count. Weaviate shards collections automatically based on LOAD_CONFIG_SHARD_CAPACITY, with a default that puts a few million objects per shard. You can override per class with the shardingConfig field. The right number depends on your write throughput and node count. Under-sharding creates hot shards, over-sharding creates coordination overhead.

Backup and persistence. In Docker, PERSISTENCE_DATA_PATH controls where data lives on disk. In Kubernetes, persistent volume claims handle this. WCS does automated backups. Either way, test restore before you trust the system.

Where it shines

Semantic search at scale is the headline use case and Weaviate handles it well. Once you cross the threshold where naive cosine similarity over a few million vectors becomes slow, you need an approximate nearest neighbor index and the production plumbing around it. Weaviate gives you both without requiring you to assemble FAISS, an embedding service, a metadata store, and a query API yourself.

Hybrid search is the second standout. Most vector databases force you to choose between keyword and semantic. Weaviate blends them in a single query, which matters for retrieval augmented generation pipelines where users type queries that mix precise terms (product names, acronyms) with fuzzy concepts. You can tune the blend per query if you want, and you can add filters on structured properties alongside the similarity search.

Multi-tenancy is built in. If you are building a SaaS product where each customer has their own isolated document collection, you set