Building AI-Powered Semantic Search with Django and pgvector: 2026 Guide

Learn how to build production-ready semantic search with Django, pgvector, and OpenAI embeddings. Step-by-step 2026 guide with code examples for vector search in Django applications.

Published: June 01, 2026

Category: AI

Why Semantic Search Matters in 2026

Keyword-based search has been the backbone of web applications for decades. But as users demand more intuitive, conversational experiences, traditional full-text search falls short. Enter semantic search — a technique that understands the meaning behind queries rather than just matching keywords.

Powered by vector embeddings and PostgreSQL's pgvector extension, semantic search enables your Django applications to deliver results that truly understand user intent. Whether you're building a documentation site, an e-commerce product catalog, or an internal knowledge base, semantic search dramatically improves the user experience.

What You'll Build

In this guide, we'll build a production-ready semantic search system using:

  • Django — Your trusted Python web framework
  • pgvector — PostgreSQL's vector similarity search extension
  • OpenAI Embeddings — State-of-the-art text embeddings (or any LLM provider)
  • React — A dynamic, real-time search interface

Step 1: Setting Up pgvector with Django

First, install the required dependencies:

pip install django pgvector psycopg2-binary openai

Enable the pgvector extension in your PostgreSQL database:

-- Run this in your PostgreSQL instance
CREATE EXTENSION IF NOT EXISTS vector;

Now, create a Django model that stores vector embeddings alongside your content:

from django.db import models
from pgvector.django import VectorField

class Document(models.Model):
    title = models.CharField(max_length=500)
    content = models.TextField()
    embedding = VectorField(dimensions=1536)  # OpenAI text-embedding-3-small
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        indexes = [
            models.Index(name='embedding_idx',
                         fields=['embedding'],
                         opclasses=['vector_cosine_ops']),
        ]

Step 2: Generating Embeddings with Django Signals

Use Django signals to automatically generate embeddings whenever a document is created or updated:

from django.db.models.signals import post_save
from django.dispatch import receiver
from openai import OpenAI

client = OpenAI()

@receiver(post_save, sender=Document)
def generate_embedding(sender, instance, created, **kwargs):
    text = f"{instance.title}\n\n{instance.content}"
    response = client.embeddings.create(
        model="text-embedding-3-small",
        input=text
    )
    instance.embedding = response.data[0].embedding
    Document.objects.filter(pk=instance.pk).update(
        embedding=instance.embedding
    )

Step 3: Building the Semantic Search API

Create a Django REST Framework view that accepts a query, generates its embedding, and returns the most semantically similar documents:

from rest_framework.decorators import api_view
from rest_framework.response import Response
from pgvector.django import CosineDistance
from openai import OpenAI

client = OpenAI()

@api_view(['POST'])
def semantic_search(request):
    query = request.data.get('query', '')
    if not query:
        return Response({'error': 'Query is required'}, status=400)
    response = client.embeddings.create(
        model="text-embedding-3-small",
        input=query
    )
    query_embedding = response.data[0].embedding
    results = (
        Document.objects
        .annotate(distance=CosineDistance('embedding', query_embedding))
        .order_by('distance')[:10]
    )
    return Response([
        {'title': doc.title, 'excerpt': doc.content[:200] + '...', 'score': 1 - doc.distance}
        for doc in results
    ])

Step 4: Building a React Search Component

Now, let's create a React component that provides real-time semantic search:

import { useState, useEffect } from 'react';
import debounce from 'lodash.debounce';

function SemanticSearch() {
  const [query, setQuery] = useState('');
  const [results, setResults] = useState([]);
  const [loading, setLoading] = useState(false);

  const search = debounce(async (searchQuery) => {
    if (!searchQuery.trim()) { setResults([]); return; }
    setLoading(true);
    const res = await fetch('/api/semantic-search/', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ query: searchQuery }),
    });
    const data = await res.json();
    setResults(data);
    setLoading(false);
  }, 300);

  useEffect(() => { search(query); }, [query]);

  return (
    <div className="semantic-search">
      <input type="text" value={query}
        onChange={(e) => setQuery(e.target.value)}
        placeholder="Search with AI-powered understanding..." />
      {results.map((r, i) => (
        <div key={i} className="result-card">
          <h3>{r.title}</h3><p>{r.excerpt}</p>
        </div>
      ))}
    </div>
  );
}

Why pgvector Over Dedicated Vector Databases?

  • No additional infrastructure — Your PostgreSQL handles vectors natively
  • Transactional consistency — ACID compliance for vector data
  • Simplified backups — One backup for all your data
  • Familiar tooling — Use Django ORM as you always have
  • Cost-effective — No extra services to provision and monitor

Performance Optimization Tips

  1. Use IVF indexes — pgvector supports IVFFlat for approximate nearest neighbor search
  2. Cache embeddings — Cache query embeddings in Redis for popular searches
  3. Batch processing — Generate embeddings in batches to stay within API rate limits
  4. Hybrid search — Combine semantic search with PostgreSQL full-text search (tsvector)

Going Further

This architecture can be extended with multi-modal search, personalized results, real-time indexing via Django Channels, and RAG pipelines that feed search results into an LLM for AI-powered answers.

Conclusion

Semantic search with Django and pgvector is no longer a futuristic luxury — it's an essential capability for modern web applications in 2026. By combining PostgreSQL's reliability with AI-powered embeddings, you can deliver search experiences that feel intelligent, intuitive, and responsive.

The best part? You don't need a dedicated vector database or a complex microservices architecture. With Django, pgvector, and a few lines of Python, you can add AI-powered semantic search to your application today.

Ready to build smarter search into your next Django project? Contact Gsoft Technologies to learn how our team can help you integrate AI-powered features into your web applications.

Back to Blog | Home | Services | Contact Us