Recommendation systems come down to answering one question in one of two fundamentally different ways: "what do people similar to you like?" or "what is similar to what you already like?" Almost every production recommender is some combination of these two ideas, and the trade-offs between them explain most of the design decisions you'll actually make.

Collaborative filtering: recommendations from behavior, not content

Collaborative filtering ignores what an item actually is and instead uses patterns in interaction data — who bought, watched, or rated what. The classic formulation is matrix factorization: represent the user-item interaction matrix as the product of two lower-dimensional matrices, a user embedding matrix and an item embedding matrix, learned so that their dot product approximates observed interactions.

python
import numpy as np

def matrix_factorization(R, k, steps=500, lr=0.01, reg=0.02):
    n_users, n_items = R.shape
    P = np.random.normal(scale=0.1, size=(n_users, k))
    Q = np.random.normal(scale=0.1, size=(n_items, k))
    for _ in range(steps):
        for u, i in zip(*R.nonzero()):
            err = R[u, i] - P[u] @ Q[i]
            P[u] += lr * (err * Q[i] - reg * P[u])
            Q[i] += lr * (err * P[u] - reg * Q[i])
    return P, Q

The strength of this approach is that it discovers patterns no one would think to hand-engineer — it might learn that people who like a particular obscure film also tend to like a specific genre of music, purely from co-occurrence in behavior, with no notion of "film" or "music" ever encoded. The weakness is the cold-start problem: a brand-new user with no interaction history, or a brand-new item nobody has interacted with yet, has no signal for the factorization to work with.

Content-based filtering: recommendations from item attributes

Content-based approaches represent items by their actual features — genre, cast, text description, product category, price — and recommend items similar to ones a user has already liked, using similarity in that feature space rather than similarity in behavior. This directly solves the item cold-start problem: a brand-new item can be recommended immediately based on its attributes, without needing any interaction history to accumulate first.

The trade-off is that content-based recommendations tend to stay narrow — a user who likes one true-crime podcast gets recommended more true-crime podcasts, with little of the serendipitous cross-category discovery collaborative filtering can surface by exploiting patterns across the whole user base.

Where each one actually breaks

Approach Strength Failure mode
Collaborative filtering Discovers non-obvious behavioral patterns Cold start for new users and items
Content-based Works immediately for new items Narrow, low-serendipity recommendations

Hybrid systems are the practical default

Most production systems blend both — using content-based signals to handle new items and new users, and collaborative signals once enough interaction data has accumulated to make them reliable, often via a learned model that takes both sets of features as input rather than choosing one output over the other:

python
features = np.concatenate([
    user_collaborative_embedding,
    item_collaborative_embedding,
    item_content_features,
    user_recent_category_affinity,
])
score = ranking_model.predict(features)

Retrieval versus ranking is the architecture that actually ships

At real scale, you rarely score every item for every user directly — with millions of items, that's computationally infeasible per request. Production systems split the problem into a fast retrieval stage that narrows millions of items down to a few hundred plausible candidates (often using approximate nearest-neighbor search over embeddings), followed by a more expensive, more accurate ranking model that scores just that shortlist. Collaborative and content-based signals both feed into this pipeline, but usually at different stages — content features are often cheap enough to use in retrieval, while the richer, slower ranking model is where most of the modeling complexity and most of the offline/online evaluation effort actually lives.

Getting this two-stage structure right typically matters more to production quality than which single algorithm you pick for either stage — a mediocre ranking model over well-chosen candidates beats a great model with no efficient way to narrow the field first.