Briefly: a lookup filter restricts which records a user can pick in a lookup field, and the only decision that really matters is required versus optional. A required filter is a rule enforced on save, so it blocks bad data from every direction including the API. An optional filter is a convenience that narrows the search dialog and stops nothing. Choosing optional when you meant required is the mistake that leaves admins convinced the feature does not work.
Where it lives
Lookup filters are configured on the lookup field itself, not on the target object. Object Manager, the field, edit, then the Lookup Filter section. You add criteria rows in the familiar field, operator, value grid.
What you can compare against is the useful part:
- Fields on the record being looked up, which is the common case. Only show active accounts, only show contacts with an email address.
- Fields on the source record, so a Contact lookup on a Case can be limited to contacts belonging to that case’s account.
- Fields on the current user, which is how you restrict selection to records matching the picker’s region, business unit or role.
- A literal value you type.
Criteria combine with AND by default and accept filter logic the way report filters do. Every row must be referenced in the logic, and deleting a row renumbers the rest without updating the logic string.
Required and optional
A required filter is enforced when the record is saved, no matter what saved it. The lookup dialog shows only matching records, the user cannot type their way around it, and a value written by Data Loader, an integration or Apex that does not match the criteria is rejected with an error. This is the setting to use when the constraint is a business rule.
An optional filter narrows what the lookup search returns and nothing more. A user who knows the record name can still enter a record outside the criteria, and any write that does not go through the lookup dialog ignores the filter entirely. Use optional when the filter is there to make a long list usable, not to enforce anything.
There is also an active flag. A filter that appears to have stopped working is sometimes just deactivated.
The error message
The default message on a required filter is generic, something to the effect that the value does not exist or does not match the filter criteria. Users read that as “the record has been deleted” and raise a ticket.
A required filter lets you supply your own message, and you should always write one. Say what the constraint is: “Choose a contact that belongs to this account.” Use the words the business uses. This one field cuts more support volume than the filter saves in data quality.
What breaks when you add one
The thing to plan for: existing records that violate a new required filter are not rejected when you save the filter, but they cannot be saved again until the lookup is corrected. A user opens a record from 2022, edits a completely unrelated field, and gets an error about a lookup they did not touch.
So the order of work is the same as for any constraint. Report on the records whose current lookup value fails the criteria, fix them, then activate the filter. Running it as optional first and watching who complains is a reasonable interim step on a busy object.
Automation is the second thing to check. A Flow or trigger that sets a lookup based on some other logic will start failing where its result conflicts with the filter, and the error surfaces as a general save failure on whatever the user was doing.
Limits worth knowing
An org has a cap on the number of active lookup filters, and the limits documentation carries the current figure. It is a number you can hit on a heavily customised object.
Filters also add work at save time, because every save with a filtered lookup evaluates the criteria. On a load of hundreds of thousands of records that is measurable. Rarely the biggest cost in a load, but not free.
Frequently asked
Can a filter reference a field on the parent of the target record? The available fields are those on the target object, the source object and the current user, which includes formula fields on any of them. That is the usual way to reach one relationship further.
Do lookup filters apply to master-detail fields? Yes, and to hierarchical relationships such as the Manager field on User.
Why does my filter work in the UI but not in a data load? Because it is optional. Change it to required and the load will start failing, which is the outcome you were after.