EspoCRM formula scripts for calculated fields and validation

Formula scripts let EspoCRM calculate field values and reject bad data when records are saved. This page covers where they run, how to configure and debug them, and what to confirm before relying on them.

On this page

When EspoCRM formula scripts fit calculated fields and validation

A sales or service team needs order totals, renewal dates and status values computed the same way on every record, and it needs incomplete or contradictory entries blocked at save time rather than cleaned up later. Formula is EspoCRM's built-in scripting language for before-save logic, used in before-save scripts configured in the Entity Manager, in API before-save scripts, and in workflows and BPM. Those four places cover most calculated-field and validation needs that do not require a database lookup, an external call or a custom PHP class.

Formula is easy to confuse with two neighboring tools. Dynamic logic only changes how forms behave in the browser (showing, requiring or locking fields), so it does not protect data written through the API or import. Hooks run PHP when records are saved, removed or related, which suits logic that outgrows Formula. Workflows and BPM, which provide the process automation layer, are part of the Advanced Pack, included in all EspoCRM Cloud plans, so confirm whether your self-hosted edition will include that extension before you design a process around it.

Before you commit, check three things with your own team: which entities need the same rule in the UI and through the API, whether the logic needs data from other records, and who will maintain the scripts after go-live. Formula is a good fit for deterministic rules over the record being saved. If a rule depends on several related entities, external systems or code that must be tested in a deployment pipeline, plan for a hook or extension instead and confirm the exact script capabilities against the EspoCRM formula documentation for your version.

Choosing where a formula script runs

This table compares the four places a rule can live in EspoCRM: Entity Manager before-save scripts, API before-save scripts, workflows and BPM, and dynamic logic or hooks. Read each row against your own rule to see which mechanism fits, who can change it, and where a duplicated rule will drift out of step. The main takeaway is to pick one owner for each rule before writing any script.

OptionWhen it fitsWho can change itWhat breaks if the rule is duplicated
Entity Manager before-save scriptCalculated fields and validation that must hold for every save made through the user interface and the APIAdministrators with Entity Manager access, so changes need change control and a test recordTwo scripts can overwrite each other's field values on the same save, and the last save wins without any warning
API before-save scriptRules that should apply only to API traffic, such as integration imports, while interface users see different behaviorAdministrators, but the script is tied to API requests and is easy to forget during reviewsInterface users and integrations get different results for the same record, which shows up as reconciliation gaps
Workflows and BPMMulti-step actions, approvals, timed updates or actions that call external systems after a record changesAdvanced Pack administrators and process owners, who may not be the people who maintain the data modelWorkflows fire after save, so a field recalculated in both a script and a workflow can flip back and forth on each update
Dynamic logicShowing, hiding, requiring or locking fields in forms based on values, without changing stored dataAdministrators through layouts and field settings, often without code reviewDynamic logic does not store anything, so a rule copied into a script will still store values the form has hidden
Hooks (PHP)Server-side logic that needs custom code, such as complex lookups or behavior tied to relationshipsDevelopers with access to the server and deployment pipeline, not form editorsHook code is outside the Entity Manager, so a formula change may not reveal that a hook is also changing the same field

How to set up a formula script safely

This sequence takes a calculated field or validation rule from a written requirement to a tested, promoted Formula script, so each script is checked against valid and invalid saves before any production record depends on it.

  1. Document the field rules in writing

    Before opening the Entity Manager, the business owner and the administrator write down each rule as a plain statement: which entity it applies to, which fields it reads, which field it sets, and what must block a save. Include the expected result for at least one valid and one invalid example record. This document becomes the acceptance list for the testing step. The step is done when the rule list has been signed off by the person who owns the process, and each rule has a named test case.

  2. Confirm entity and field names

    Using the Entity Manager and field administration in the non-production instance, the administrator records the exact internal names of every entity, link and field the script will reference, including custom fields with the c prefix. Formula references depend on these internal names, not on display labels, so a label change later can break a script silently. Check field types too, since a script that expects a number will behave differently with a text field. The step closes when the names are listed next to the rules from the previous step.

  3. Write the script in a non-production instance

    The administrator writes the Formula script in the before-save script section of the target entity, or in an API before-save script if the rule must also apply to records created through the REST API. Keep each script focused on one rule so failures are easy to trace. Where a script needs a date or record function, confirm the function name in the Formula documentation before relying on it. The step is complete when the script saves without a syntax error and the entity can still be opened and edited normally.

  4. Test a valid save and confirm the recalculation

    Create or edit a test record that meets every rule, then save it. Open the saved record and check that the calculated field holds the expected value and that no unexpected field has changed. Repeat the check after editing an input field to confirm the value updates on the next save, not only on creation. Record the result against the test case from the first step. The step is done when valid records save and show the exact values the rule document predicts.

  5. Test invalid saves and confirm clear rejection

    Create or edit test records that break each rule, one at a time, and attempt to save them. Confirm the save is blocked and that the error message tells a user which field or condition failed in terms they can act on. If the message is unclear, adjust the script's error text and repeat the test. Also test edge cases the business owner named, such as empty inputs and boundary values. The step is complete when every invalid case is rejected, and every rejection message has been reviewed by the process owner.

  6. Check imports and API saves

    Run the same valid and invalid cases through a CSV import in a test run and through an API call with a dedicated API user, because the rule should behave the same way for every path that writes records. Review how the import handles rejected rows and confirm that the API user's permissions allow the expected fields to be read and written. Document any path where the behavior differs from the UI. The step closes when each save path produces the same result for the same input.

  7. Promote the script with a rollback record

    Export or record the final script text, the entity and field names it depends on, and the test results, then apply the same change to the production instance through your normal change process. Note the previous state of the entity so the script can be removed if needed. Run a small set of valid and invalid checks in production using test records that your team then deletes. The step is done when production behaves as the test results predict and the change record is filed with the rollback steps.

How a before-save formula changes a record during save

A before-save formula runs after a user submits a record and before EspoCRM writes it to the database, so it can calculate values and reject bad input in the same pass. The script sees the attributes as they were submitted and can change them before the save completes. Your team should map the order in which the Entity Manager's before-save script, field validation and any workflows fire on the entity in question, because a calculated field that depends on another calculated field only works if it runs in the right sequence. Confirm this order by saving a test record in a non-production instance and watching the resulting values, not by assuming it from the layout.

Inside the script, reads come from the attributes on the entity and writes go back to those same attributes, with the entity object as the handle for both. A calculation such as a discount total is safe to write back, but a script that overwrites a user-entered value without a visible trace makes the record hard to audit. Validation logic should return a clear error message to the user and stop the save, rather than quietly setting a field to a default. A silent correction hides the problem from the person who entered the data and from anyone reviewing the record later, so decide with your business owners which fields may be corrected and which must be rejected.

API saves follow the same save-time rules only when API before-save scripts are configured for that entity. Without that configuration, an integration that writes records through the REST API can bypass the checks your users see in the browser, which is a common gap in mixed deployments. Treat this as a question to confirm with a test call: send a request that should fail validation, confirm the rejection, and confirm that the stored value matches what your rules intend. Repeat the test for each integration account and each API user role you have issued, since their permissions and the scripts they hit may differ.

Security and operational risks of formula scripts

Formula scripts run on record saves and can change data in bulk, so their risks are less about the code itself and more about who can edit it, what it overwrites and how it gets reviewed. The cards below cover the controls to set before scripts go live. Each one maps to a point where a script can quietly change customer records.

Limit who can edit scripts

Editing a before-save script in the Entity Manager requires administrator rights, and an administrator can also change the API paths that run formulas. Treat script editing as a privileged change, not a routine task for anyone with a CRM login. The EspoCRM security docs advise against using admin accounts for daily work, so script authors should work from a separate, named administrator account used only for configuration. Confirm which accounts can reach the Entity Manager and review that list whenever staff change roles.

Avoid daily admin work

Because administrators can change formula logic, using an admin account to browse, sell or edit records widens the blast radius of a mistake or a compromised session. Give sales and service staff roles that do not reach configuration, and keep administrator sessions short. The security docs also recommend limiting auth token lifetime and restricting admin access by IP address. Ask your partner to document which controls apply to the admin accounts that maintain scripts.

Overwrites during imports and API writes

Before-save scripts run when a record is saved, which includes CSV imports and API requests, not only when a user clicks Save. A formula that recalculates a field can overwrite values supplied by the source file or an integration. Test imports in a staging instance with sample rows that include edge cases, and check whether the import mode you choose will trigger the script on update. Decide in advance which system owns each calculated field.

Change review and version control

Formula logic lives in the Entity Manager database configuration, so a change can be made in the UI without a trace in your code repository. Export and store the script text in version control, or keep a manual change log with the date, author, reason and test result for each edit. Require a second person to review any change that affects a financial or compliance field. Ask your partner how they will export, review and restore script configuration during the build.

Bulk updates and performance

A script that runs once per record is cheap on a single save but can slow a mass update or large import that touches thousands of rows. Heavy lookups inside a script multiply that cost, and the work competes with other requests on the same server. Test bulk operations against a copy of production volumes before go-live, and schedule large imports for periods of low use. Check the background job setup as well, since long-running work depends on cron or a scheduled task.

Audit trail and recovery

When a calculated value is wrong, you need to know which save produced it and how to restore the previous data. Confirm that the audit and stream history in your instance captures the changes you need, and keep database backups that can be restored to a point before a faulty script was deployed. Test the restore on a copy so the procedure is known before an incident. Record who approves a rollback of script logic and who decides which records to correct.

Debugging formula scripts that fail or misbehave

Why does my EspoCRM formula field stay empty after a record is saved?

Most empty calculated fields come from a script that never ran on the save path you used, or from a condition that evaluated to a value you did not expect. Start by confirming that the before-save script is configured on the entity in the Entity Manager and that the target field name matches exactly. Next, save a single record through the UI and check whether the field populates. If it stays empty, look for null inputs: a function that reads a field the user left blank will return nothing rather than an error. Add a temporary string\concatenate or a plain assignment of a known value to confirm the script executes at all. Then reintroduce your logic one line at a time until the blank result returns.

Why do my date calculations in EspoCRM return unexpected results?

Date arithmetic often breaks because of time zones, date-only versus date-time fields, or mixing string and date values. Check the field type first, since a date-only field and a date-time field are stored and compared differently. Then confirm the exact output format of each date function in the Formula documentation before chaining calls, and convert values explicitly where the format matters. Test with fixed sample dates at month ends, leap days and daylight saving changes, because these edge cases expose most off-by-one errors. Compare the value shown in the UI with the value stored in the database for the same record so you know whether the problem lies in the calculation or in display formatting.

How do I find out why a validation rule fires during a CSV import?

Imports run through the same save logic as the UI, so a validation script that blocks a manual save will also block an imported row. Confirm that the import mode you chose (Create Only, Create and Update, or Update Only) matches what you expect, because Update modes load existing records that may already contain values the rule rejects. Map the fields carefully, since an unmapped column can leave a required value empty. Run a small test file of five to ten rows first, using the reverting option if a batch goes wrong. The EspoCRM import documentation describes idle execution through cron for large files, so check that the background job runs and that you read the results of each run before judging the rule itself.

Why does a record saved through the API behave differently from one saved in the UI?

API saves can differ because they may run through API before-save scripts rather than the Entity Manager scripts, and the API user's role determines which fields and actions are permitted. Check whether your script is configured for the correct save path, since a script that is only attached to the UI flow will not run for an integration call. Also review the API user's permissions, because a field the user cannot write may be silently skipped or may cause a failure depending on the request. Send the same payload through the UI and the API for one test record and compare the stored values, which quickly shows whether the difference comes from the script, the permissions or the request body.

How do I reproduce a formula script problem with a single record?

Reproducing with one record removes noise from bulk data, background jobs and other scripts. Pick a record that shows the problem, note its current field values, and save it once without other changes to confirm the symptom. Then copy the record's inputs into a dedicated test record created in a non-production instance, which lets you change one input at a time. Record each result in a short table of input, expected output and actual output. This approach shows which input triggers the fault and keeps the test repeatable when you hand the case to a colleague or a partner.

How do I isolate the function causing a formula error?

Split the script into its smallest parts and test each function on its own before combining them. Replace nested calls with intermediate attributes so you can see each value, then save a record and check what each one holds. When a step returns an unexpected type, compare it with the function reference for that call. Once the faulty function is identified, rewrite it with explicit null checks and retest the single-record case, then rerun the full script on the sample set. Keep the working version in version control with a note of the input that broke the earlier version, so the same regression is caught on the next change.

What should I check in logs when a formula script fails?

Check the EspoCRM application log first, because it records PHP and script errors with timestamps you can match against the save you just performed. Also review the web server error log, since a timeout or a PHP fatal error may appear there rather than in the application log. Background jobs such as imports and workflows write to the same log set, so note the time of each test to avoid confusion. Confirm that the cron job or scheduled task required for background processing is running, because a job that never starts will look like a script that never fires. The EspoCRM operations documentation covers log locations for each deployment, and that is the right place to confirm the file paths for your own server.

When should I hand formula debugging to a partner instead of fixing it myself?

Handle simple faults in-house when a single record reproduces the problem and the fix is a field name or a null check. Bring in an implementation partner when scripts interact with workflows, hooks, permissions or imports, or when several teams depend on the same calculated values and a change could break reporting. The cost depends on how many scripts are involved, how well documented they are, how many save paths they touch and whether your test environment mirrors production. Ask for a written scope that lists the scripts, the save paths to be verified, the test records to be used and the handover documentation before any work starts.

Limits to confirm in your EspoCRM version

Formula behavior changes between releases, and the function list is the first thing to confirm. The cards below cover the parts of the formula documentation that shape a calculated field or validation rule, from function arguments to how scripts interact with workflows. EspoCRM 10.0.0 and later releases are the versions in scope for this work.

Supported functions and argument rules

Check the function list in the formula documentation for your exact release, not an older guide or a forum post. For each function you plan to use, confirm the expected argument types, the return type and what happens when an argument is empty. A calculation that works with a populated field can silently fail when the field is blank, so test the empty case explicitly. Record the verified function list in your build specification.

Available record helpers

Scripts that read or relate other records depend on which record helpers the version provides and how they resolve linked entities. Confirm whether a helper can read a related record, how it handles a missing link, and whether it respects the permissions of the user who saved the record. Cross-entity logic that works in a test instance with an administrator account may behave differently for a sales user with restricted access.

Available date helpers

Date logic is where formula scripts most often break in production, because time zones, date-only fields and datetime fields behave differently. Confirm which date helpers exist, what format they expect and how they treat the user's configured time zone. Test a due-date or renewal calculation across a daylight saving change and a month end before relying on it for billing or service commitments.

API before-save script behavior

API before-save scripts run for requests made through the REST API, which may differ from scripts that run when a user saves in the interface. Confirm when each script type fires, which fields are available at that point, and whether a validation error returned to an API client is reported in the form your integration expects. Test both paths with the same record so calculated values match regardless of how the record was created.

Interaction with workflows and BPM

Formula scripts, workflows and BPM processes can all change the same field, and the order of execution determines the final value. Confirm which runs first in your version, whether a workflow update re-triggers a before-save script and whether a loop is possible. Document which component owns each calculated field so that a later workflow change does not overwrite a validated value.

Debugging and error reporting

Confirm how script errors surface in your version, including whether a failing script blocks the save, logs a message or fails silently. Check where the server logs record script failures and whether your team can reproduce the error in a staging instance with the same configuration. Agree on a test plan that covers blank inputs, boundary values and failed API requests before go-live.

Questions buyers ask about EspoCRM formula scripts

What drives the effort and cost of EspoCRM formula work?

The main drivers are the number of rules, how many fields and entities they touch, whether formulas depend on related records or integrations, and how deeply the rules must be tested. A handful of before-save rules on one entity is a small, contained job. A rule set that spans quotes, invoices, pricing and external data needs more design, more test cases and more review before go-live. Cost is one-time for the build and recurring only if you retain someone for changes. Ask any quote to list each rule, the entities it affects, the test cases it requires and whether integrations are in scope. DeployOpen does not publish prices, and a quote follows from the written scope.

Can an internal administrator maintain formula scripts after go-live?

Often yes, for simple rules. Formula Script is EspoCRM's built-in scripting language and runs in before-save scripts configured in the Entity Manager, API before-save scripts, workflows and BPM. A competent administrator can read and adjust a short script if the team keeps a written rule register, names the owner of each rule and tests changes on a copy of the instance first. Complex rule sets with nested date logic or cross-entity lookups are harder to change safely without documentation. Ask the partner to hand over a rule register, sample inputs and expected outputs so your administrator has a reference for each rule.

How long does it take to validate a typical formula rule set?

No duration is supplied for this work, so treat any figure you hear with caution. Validation time depends on the number of rules, the number of records and edge cases in your data, and whether testing happens on a staging instance that mirrors production. Plan for time to write expected results for each rule, run representative records through create and update paths, check API saves separately from interface saves, and retest after each change. Ask the quote to state the testing steps, the number of test cases and who signs off each rule before it moves to production.

What does the work need from our team before it starts?

The work needs three things. First, sample data that reflects real edge cases, such as partial quotes, currency changes, empty dates and records created through the API. Second, named rule owners who can state the business logic in plain language and approve expected results. Third, a test instance that matches your production configuration, including custom fields, teams and the entity types the formulas read or write. Without a test instance, validation happens in production, which raises risk. Confirm these inputs in writing before the scope is agreed.

Can formula scripts replace PHP hooks?

Sometimes, but not always. Formula scripts cover many field calculations and validation checks that run when a record is saved, which is where most calculated fields and simple rules belong. PHP hooks are the better fit when logic needs external systems, complex data access, custom error handling or code that must be versioned and packaged as an extension. Before choosing, list each rule and check whether the Formula documentation covers the functions it needs. Keep the decision recorded, because moving logic between formulas and hooks later changes how upgrades and testing are handled.

Do formula scripts affect upgrades or security?

They can. Formula logic lives in the instance configuration, so each upgrade needs a check that the scripts still behave as expected on the new version. Scripts that write to fields used by permissions, approvals or integrations deserve particular attention, because a silent change can alter access or data flow. On the security side, review who can edit Entity Manager settings, since changing a before-save script is a configuration change with effects on stored data. Ask for the rule register to include owners and a review step for each change.

Does the work include a debugging and handover plan?

It should, and you should confirm it in the written scope. A usable handover includes the final script for each rule, a short description of what it calculates or validates, the expected results from the test cases, notes on known limits, and the steps for debugging a failing script. Ask whether the debugging steps cover checking the Entity Manager configuration, reproducing the save through the interface and through the API, and reviewing the server logs. Confirm the format of the handover and who keeps it current after the engagement ends.

How DeployOpen scopes and delivers EspoCRM formula work

DeployOpen treats EspoCRM formula scripts as part of the running system, not a quick patch. We agree the calculated fields and validation rules in writing, build them in your own infrastructure, test them against real record flows, and hand over documented scripts your administrators can maintain after the engagement ends.

How we scope

  • We list each calculated field and validation rule, the entity and trigger it applies to, and the expected result for each case.
  • We confirm which scripts run in the Entity Manager before-save hook and which need API before-save behavior or workflow steps.
  • Scope, deliverables and timelines are agreed in writing before work starts, since most engagements are fixed-scope.

How we build

  • We write Formula Script against your EspoCRM version, checking function names and null handling for empty fields and date values.
  • We build test records for each rule, including boundary values, blank inputs and bulk updates through the API and import.
  • We confirm the scripts behave the same way on a staging copy of your instance before anything reaches production.

How we hand over

  • We deliver each script with a short note covering its purpose, inputs, outputs, dependencies and known limits.
  • We document the test cases and expected results so your team can rerun them after upgrades or field changes.
  • We walk your administrators through debugging steps and where script errors appear in your logs.

How we support

  • Ongoing support, upgrades and continuous testing are available as a retainer if you want scripts reviewed after each EspoCRM release.
  • We can revisit formulas when your sales or service process changes, with changes scoped and agreed in writing first.
  • Ask us to confirm how a retainer would cover script regression checks alongside upgrades of your EspoCRM version.

Talk to our team.

Tell us what you're working on, whether it's a deployment, an audit, a security test or a cyber range. You'll speak with an engineer who can help you scope it.

  • 30-minute call: free, with no obligation.
  • NDA on request: we can sign before you share details.
  • Clear next steps: a scope and plan after the call.