BERTopic: Interpretable Topic Modeling on Top of Transformer Embeddings
Leveraging BERT and c-TF-IDF to create easily interpretable topics.
At a glance
- What is it?
- BERTopic clusters document embeddings and then labels each cluster with c-TF-IDF, replacing the term-frequency math of LDA with a pipeline you can swap component by component. The flexibility is the point, and also the cost.
- Who is it for?
- Adopt BERTopic if you need topic labels a human can read, you already have a sentence-transformers pipeline, and you can accept that UMAP and HDBSCAN will need per-corpus tuning. Do not adopt it if you need stable topic IDs across re-runs on shifting data, or if a bag-of-words model already answers your question.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 7 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The problem BERTopic addresses: topic labels that survive contact with a reader
Classical topic models such as LDA produce topics as probability distributions over a fixed vocabulary. The output is a list of weighted words, and turning that list into a label a stakeholder will accept is a separate, manual job. BERTopic attacks the labelling step directly. Its README describes the goal as creating dense clusters that allow for easily interpretable topics while keeping important words in the topic descriptions. The audience is anyone who has to hand a topic list to a person who did not build the model: analysts summarizing support tickets, researchers mapping a document archive, engineers building a browse-by-theme interface. The project is a Python library, MIT licensed, and the README states Python 3.10 or newer. It is not a service and not a pretrained topic index. You supply the corpus.
The pipeline: embeddings, UMAP, HDBSCAN, then c-TF-IDF for the labels
BERTopic is a composition of stages rather than a single algorithm. Documents are first converted to embeddings, by default through sentence-transformers, which is why the base install pulls in transformers. Those vectors are reduced in dimensionality, typically with UMAP, and then clustered, typically with HDBSCAN. Each cluster becomes a candidate topic. The labelling step is where the project's name comes from: c-TF-IDF treats all documents in one cluster as a single concatenated document and computes a TF-IDF-like weight for each term against the rest of the corpus. Terms that are frequent inside a cluster but rare elsewhere rise to the top and become the topic representation. That is the mechanism that keeps topic words specific instead of letting generic high-frequency vocabulary dominate every topic. The README also notes that a lightweight installation without transformers, UMAP or HDBSCAN is possible for training with Model2Vec or for inference, which tells you the stages are genuinely separable and not just nominally pluggable.
Installation and the configuration surface you actually touch
The README gives two install paths. With uv: uv add bertopic. With pip: pip install bertopic. Both bring in sentence-transformers. If you want a different embedding backend, the extras are bertopic[flair,gensim,spacy,use], and bertopic[vision] adds image support for multimodal topic modeling. The Quick Start in the README imports BERTopic from bertopic and loads the 20 newsgroups dataset, which is the standard first run. Configuration happens through constructor arguments and through the components you pass in. Because embeddings, dimensionality reduction, clustering and representation are separate objects, replacing the default UMAP or HDBSCAN means constructing your own and handing it to the model rather than editing a config file. There is no YAML layer documented in the material supplied here. That matters for reproducibility: your model definition lives in Python source, so version it the way you version any other code.
Where the design breaks: outliers, re-run instability and tuning debt
HDBSCAN is density based, which means it does not have to assign every document to a cluster. Documents in low-density regions fall into an outlier topic, conventionally labelled -1. On corpora with mixed registers or short texts, that bucket can absorb a large share of the input, and the README's own Quick Start and best-practices material exist partly because the default run is not the final run. The second limitation is stability. Because clustering is density based and UMAP reduction is stochastic, running the same pipeline twice on the same corpus can produce different cluster boundaries and therefore different topic IDs. If you need topic 7 to mean the same thing next quarter, BERTopic does not give you that for free. The third cost is tuning. n_neighbors and min_dist in UMAP, min_cluster_size in HDBSCAN, and the choice of embedding model all interact, and the documentation devotes separate pages to tips and tricks and to best practices rather than claiming defaults work everywhere. This is a library for people willing to iterate on a specific corpus, not a drop-in classifier.
The feature matrix is the real differentiator, and the maintenance surface
The README lists a wide range of modes: guided, supervised, semi-supervised, manual, multi-topic distributions, hierarchical, class-based, dynamic, online and incremental, multimodal, multi-aspect, text generation via LLM, zero-shot, model merging and seed words. Dynamic topic modeling over time and online or incremental fitting are the two that separate BERTopic from most alternatives, because they imply the model can be updated rather than refit from scratch. That breadth has a maintenance consequence. Each mode is another code path, and the release history shows a steady cadence: v0.17.4 in December 2025, v0.17.3 and v0.17.1 in July 2025. Patch-level releases at that frequency usually mean bug fixes and dependency alignment rather than API churn, but pinning your version is still the sensible default for a pipeline you have already validated. The MIT licence permits commercial use and modification; it does not obligate the maintainer to support your deployment, and the material here gives no compatibility guarantees beyond the stated Python 3.10 floor.
How BERTopic differs from LDA and from a plain sentence-transformers clustering script
The obvious comparison is Latent Dirichlet Allocation as implemented in scikit-learn or gensim. LDA models each document as a mixture over a fixed number of topics and each topic as a distribution over vocabulary. You choose the number of topics in advance, and the model will happily produce that many even when the corpus does not support it. BERTopic inverts this: you do not specify a topic count, HDBSCAN discovers however many dense clusters exist, and outliers are permitted. LDA also operates on term counts, so word order and synonymy are invisible to it; BERTopic's embedding stage means two documents that share meaning but not vocabulary can land in the same cluster. The second comparison is against writing your own script: embed with sentence-transformers, reduce with UMAP, cluster with HDBSCAN, then read the top terms per cluster. That is essentially the BERTopic pipeline, and the reason to use the library instead is c-TF-IDF and the surrounding modes rather than the clustering itself. If you only need clusters and are comfortable writing the labelling heuristic, the library earns less of its weight.
Who should adopt BERTopic and what to check before you commit
Adopt it when the deliverable is a readable topic list over an unlabelled corpus, when you can afford a GPU or a long CPU run for the embedding stage, and when you are prepared to tune UMAP and HDBSCAN against your own data. Do not adopt it when you need deterministic, stable topic identifiers across runs, when your documents are short enough that embeddings carry little signal, or when a simple keyword or TF-IDF breakdown already answers the question you were asked. Before committing, do three things. Run the Quick Start from the README on a sample of your own corpus, not the 20 newsgroups set, and look at how many documents land in topic -1. Then check whether the topics that emerge are distinct enough to name, because c-TF-IDF will surface words whether or not the underlying clusters are meaningful. Finally, pin the version in your dependency file and record the embedding model name alongside it, since swapping the embedding backend changes the clusters and therefore every downstream label.
Editorial conclusion
Adopt BERTopic if you need topic labels a human can read, you already have a sentence-transformers pipeline, and you can accept that UMAP and HDBSCAN will need per-corpus tuning. Do not adopt it if you need stable topic IDs across re-runs on shifting data, or if a bag-of-words model already answers your question. Before committing, run the Quick Start on a sample of your own corpus and check the outlier ratio that HDBSCAN assigns to topic -1.
Community notes