Skip to main content
SFDC Developers
Admin

Salesforce Validation Rules: 12 Examples & Best Practices

Vinay Vernekar · · 5 min read

Salesforce validation rules are the workhorse of declarative data integrity. They prevent bad data at the source, run on every insert and update, and (critically) work for both UI users and API integrations alike. Here are 12 patterns that cover roughly 80% of real-world needs, plus the formula tricks that make them maintainable.

How validation rules work

A validation rule is a formula that returns Boolean. TRUE = block the save. When TRUE, Salesforce displays the error message you configured (either inline next to a field or at the top of the page) and the record fails to save. They run between the BEFORE triggers and the database commit, on every insert and update — including bulk operations and API calls.

Three things to know:

  1. They block, they don't warn. If TRUE, save fails. There's no soft-warning mode in standard Salesforce.
  2. They run on every save. Even if no field changed, the rule still evaluates. Use ISCHANGED() to scope the rule to actual changes.
  3. They affect API too. Data Loader, Apex DML, and external integrations all hit the same rules. This is usually what you want — but it's also why poorly-written rules break overnight ETL jobs.

12 copy-paste validation rule examples

1. Email regex

Block invalid email format on a custom email field:

NOT(REGEX(Email_Address__c, "^[a-zA-Z0-9._-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9.-]+$"))

Works for any standard regex; the ^ and $ anchors are required to prevent partial matches.

2. Required only when another field is set

Phone is required but only if Lead Status is "Qualified":

AND(
  ISPICKVAL(Status, "Qualified"),
  ISBLANK(Phone)
)

3. Block close date in the past

AND(
  ISCHANGED(CloseDate),
  CloseDate < TODAY()
)

The ISCHANGED guard means existing records with old past dates can still be saved — the rule only fires when CloseDate is being changed.

4. Discount cap by profile

Block discount > 20% unless the user is a System Administrator:

AND(
  Discount__c > 0.2,
  $Profile.Name <> "System Administrator"
)

5. Custom-permission override

Cleaner version of the above using a custom permission rather than profile name:

AND(
  Discount__c > 0.2,
  NOT($Permission.High_Discount_Override__c)
)

Custom permissions survive profile renames and let you grant the override to multiple profiles via permission sets.

6. Account-industry cross-object check

On Contacts, require Title when Account.Industry is "Technology":

AND(
  TEXT(Account.Industry) = "Technology",
  ISBLANK(Title)
)

7. Renewal vs new business

Different revenue rules for renewals:

AND(
  IsRenewal__c = TRUE,
  Amount < PRIORVALUE(Amount) * 0.9
)

PRIORVALUE returns the value before this save — useful for "amount cannot decrease by more than 10%" patterns.

8. Phone number length

Require US phones to be exactly 10 digits:

AND(
  TEXT(Country__c) = "US",
  NOT(REGEX(Phone, "^\\d{10}$"))
)

9. Conditional read-only after stage

Block edits to Amount once Opportunity reaches "Closed Won":

AND(
  ISPICKVAL(StageName, "Closed Won"),
  ISCHANGED(Amount)
)

This is the standard pattern for "freeze fields after stage X."

10. Date range on creation only

Birthday must be between 1900 and today, only enforced on insert:

AND(
  ISNEW(),
  OR(Birthday__c < DATE(1900, 1, 1), Birthday__c > TODAY())
)

ISNEW() returns TRUE only on insert — the rule doesn't fire on subsequent updates.

11. Multi-select picklist requires specific value

Require Tags to include "VIP" when Annual Revenue exceeds $1M:

AND(
  AnnualRevenue > 1000000,
  NOT(INCLUDES(Tags__c, "VIP"))
)

12. Block edits on locked records

Prevent any edit when a checkbox is set:

AND(
  Locked__c = TRUE,
  $Profile.Name <> "System Administrator"
)

Best practices

Keep rules narrow. One rule = one business intent. Combining "phone required AND email format AND amount cap" into one mega-rule is unmaintainable. Split them — they fire in any order anyway.

Use ISNEW() and ISCHANGED() guards. Without them, your rule fires on every save of every record forever, including legacy data and integrations updating unrelated fields. The ETL job at 3am does NOT want to be blocked by a rule that should only run on user-initiated changes.

Reference custom permissions, not profile names. $Profile.Name = 'Sales Manager' breaks the moment HR renames the profile. $Permission.Custom_Sales_Override__c survives the renames.

Write the error message from the user's perspective. Bad: "Validation rule X1 failed." Good: "Discount over 20% requires manager approval. Talk to your manager or use a Permission Set."

Test with a real bulk insert. A rule that's fine for one record can choke an integration loading 200 leads at once. Always test with Data Loader before deploying.

When NOT to use a validation rule

  • For data cleanup of existing records. Validation rules don't fix existing bad data — they only block future writes. Run a Data Loader update after deploying the rule, or write a one-shot Flow.
  • For complex multi-record logic. A validation rule sees only the record being saved. To enforce "no two Opportunities for the same Account in 30 days," use a Trigger or Flow with a Get Records.
  • For warnings, not blocks. No warning mode exists. If you need "yes/no, are you sure?" prompts, use a Flow with a screen component.

Validation rules are one of the highest-leverage tools in the Salesforce admin toolkit — declarative, instant, and impossible to bypass via API. The 12 patterns above will cover most data integrity needs you'll ever face. Pair them with Salesforce Flow best practices for the cases where validation alone isn't enough, and your data quality will outlast every developer who ever touched the org.

Share this article

Get weekly Salesforce dev tutorials in your inbox

Comments

Loading comments...

Leave a Comment

Trending Now