Before Salesforce, I spent twenty years in education, and one fixture of that world was the course list. The school offered one catalog of courses, but no student ever saw the whole thing. A ninth-grader didn’t get the senior seminar list. A student who hadn’t passed the prerequisite didn’t get the advanced track. We filtered before the student chose, because letting someone pick a course they couldn’t take and then saying no afterwards helps nobody.

Product catalogs have exactly the same problem. Your company sells many things, but not every account is allowed to buy every thing. A reseller has one commercial agreement; an enterprise customer has another. And yet in many orgs, every rep sees the entire catalog for every account, picks something, and finds out later that the choice was wrong.

In Revenue Cloud (Salesforce’s quote-to-cash product line, often called RLM), the tool for filtering before the choice is called an Expression Set. Today I want to explain what it is, show you the one use case I know from real work, and be honest about its limits.

What an Expression Set actually is

An Expression Set is declarative decision logic: you give it criteria, it gives you an outcome, and the platform evaluates it at runtime.

Let me unpack those words.

  • Declarative means you build it with clicks, not code. No Apex class, no deployment pipeline for every change.
  • Criteria in, outcome out means it behaves like a function: “given these inputs about the situation, here is the answer.”
  • Evaluated by the platform means you don’t call it manually — Revenue Cloud consults it at the right moment in the flow.
  • Versionable means you can build a new version of the logic, keep the old one, and switch when you’re ready.

The mental model I give beginners: think of an Expression Set as a decision table the runtime consults — not code. A decision table is just a grid: if the situation looks like this row, the answer is that column. You author the rows; the platform looks them up.

An Expression Set is a decision table the platform consults at runtime — criteria in, outcome out, built with clicks, versioned like a document.

The use case: which products can this account even buy?

Here is where this became real for me. In TechnoStore — the retail build I do my real experiments in, and have written about here before — the question was account-context-aware product qualification: which products should a given account even see in the catalog, before anyone configures or prices anything?

The inputs are account attributes — things like segment and region. The outcome is the qualified subset of products for that account.

Concretely: a reseller account in one segment opens the product list and sees the subset that resellers in that segment are allowed to buy. An enterprise account sees a different subset. Same catalog underneath; different lawful views of it. The rep never has to remember the commercial policy, because the list in front of them is the policy.

This is the school course list, rebuilt in Revenue Cloud. Filter first; choose from what’s actually allowed.

Why not just write Apex? Why not a validation rule?

When beginners meet this problem, they usually reach for one of three familiar tools. Each fails in a specific, predictable way.

Hardcoding the rules in Apex. Apex is Salesforce’s programming language, and yes, you could write code that filters products by account attributes. But commercial rules change constantly — a new partner tier, a region opening up, a product retired for one segment. If the rules live in code, every commercial change is a deployment: a developer, a test cycle, a release window. You’ve turned a business decision into an engineering project. With an Expression Set, the same change is a new version of a decision table, authored by clicks.

Validation rules. A validation rule is a check that blocks a record from being saved when a condition is violated. The problem is timing: it fires after the wrong choice, not before it. The rep finds the product, adds it, maybe configures it, and only at save time gets an error saying this account can’t buy it. That’s the school letting the student enroll in the wrong course and then rejecting the form. Qualification prevents the wrong choice from ever appearing.

Doing nothing — the unfiltered catalog. This is the quiet default, and it’s the worst. When every rep sees everything, wrong picks get through, workarounds appear, one-off products get created to paper over the gaps, and the catalog slowly stops being a source of truth. I have written about catalog pollution here before, and an unfiltered catalog is one of the ways it starts: if the system won’t tell reps what’s allowed, they’ll improvise, and the improvisations accumulate.

Apex makes every rule change a deployment. Validation rules say “no” after the mistake. Qualification says “here’s what’s possible” before it.

Where this sits in quote-to-cash

Quote-to-cash is the whole journey from “customer wants something” to “money arrives”: choose products, configure them, price them, quote, order, invoice.

Qualification sits at the front — before configuration and before pricing. That position is the whole point. Because the rep’s product list is already the lawful subset for this account, everything downstream gets simpler. Your configuration rules don’t need clauses like “unless this is a reseller in region X, in which case…”. Your pricing logic doesn’t need to defend against products this account should never have seen. Each stage can trust that the stage before it already did its filtering.

This is a general design lesson, not just a Revenue Cloud one: push your constraints as early in the process as you can. Every rule you enforce at the start is ten exceptions you don’t have to handle at the end.

The honest limits

Two things I want to say plainly, because I’d rather you trust me than think this is effortless.

First: naming and navigation move. Exact setup paths and even feature naming in Revenue Cloud evolve from release to release. I’ve deliberately described the concept here rather than a click-path, which would be stale within a release or two. When you’re ready to build, search the current documentation for Expression Sets in your org’s release, and verify in your org how they’re set up there.

Second: declarative rules deserve tests too. “No code” does not mean “no bugs.” A decision table can be wrong just as easily as an Apex class — it’s just wrong faster. My working habit: when you change a rule version, take a known account — one where you can say from memory which products it should qualify for — and verify the qualified list against your expectation before activating the new version. Versioning gives you this safety for free; use it. An untested rule change in qualification doesn’t throw an error anywhere. It just quietly shows the wrong catalog to real accounts.

Your next step

You don’t need a project to start thinking this way. Pick one real account from your org — or an imaginary one, if you’re learning — and answer on paper: which products should this account be able to buy, and which attributes decide that? Segment? Region? Something else your business cares about?

If you can fill in that little table by hand, you’ve already authored your first Expression Set — everything after that is transcription. And if you find you can’t fill it in, because nobody actually knows the rules — that’s not a failure. That’s the most valuable discovery of the whole exercise, and the real place to begin.

Mustafa Aksu

Salesforce developer & ISV builder focused on Revenue Cloud, Agentforce, and Data Cloud. I write from real, shipped work.