Stored vs. Unstored vs. Scripted in FileMaker: The Right Calculation Pattern
You create a new calculation field in FileMaker and check that little box: "Do not store calculation results." Or maybe you leave it unchecked. The decision feels arbitrary, maybe based on something you read once or just what seemed right at the moment. Six months later, your solution is slow, or worse, displaying incorrect data, and you're not sure why.
The choice between stored calculations, unstored calculations, and scripted values isn't just a technical checkbox. It's an architectural decision that affects performance, data accuracy, storage space, and how your solution behaves under edge cases. Make the wrong choice consistently, and you'll spend your time troubleshooting mysterious performance issues or explaining to clients why their reports show different numbers than their detail screens.
After a decade of FileMaker development, I've seen the consequences of these decisions play out in production systems. This article provides decision frameworks for choosing the right calculation pattern based on your specific needs, helping you build FileMaker solutions that are both fast and reliable.
Understanding the Three Approaches
Before diving into decision frameworks, let's clarify what we're choosing between.
Stored calculations evaluate when dependencies change and save the result in the database. FileMaker stores this value just like any other field data. When you view a record, you're reading the pre-calculated result, not calculating it in real time.
Unstored calculations evaluate on-demand every time they're accessed. Each time a layout displays the field or a script references it, FileMaker recalculates the result from current data. This happens whether dependencies changed or not.
Scripted values aren't calculations at all but regular fields populated by scripts. You control exactly when the value updates by explicitly running a script to set the field. This gives maximum control but requires maintenance and can lead to stale data if not managed carefully.
Each approach has specific use cases where it excels and situations where it creates problems. The key is matching the pattern to your requirements.
The Performance Trade-Off
The most obvious difference between stored and unstored FileMaker calculations is performance, but the relationship isn't as simple as "stored is always faster."
Stored calculations are faster to read because the value already exists. When displaying 100 records in a list view with a stored calculation, FileMaker reads 100 pre-computed values from disk. Fast and predictable.
Unstored calculations are faster to write because nothing saves. When you import 10,000 records into a table with unstored calculations, those calculations don't run during import. No computational cost, no disk writes.
The performance crossover point depends on your read-to-write ratio. If you calculate once and read hundreds of times, stored wins. If you write constantly but rarely display the value, unstored wins.
Consider a "Days Since Created" calculation: Get(CurrentDate) - CreationDate. As a stored calculation, this would need to recalculate for every record every single day, triggering potentially millions of unnecessary disk writes. As an unstored calculation, it computes only when displayed, making it far more efficient.
Now consider a "Full Name" calculation: NameFirst & " " & NameLast. Names rarely change but display constantly. Calculating this on-demand in every list view, report, and search is wasteful. Store it, calculate once per change, read it thousands of times.
According to FileMaker's performance best practices documentation, excessive stored calculations on large tables can significantly impact import and editing performance, while excessive unstored calculations in portal rows or list views can create rendering delays.
The Data Accuracy Consideration
Performance matters, but correctness matters more. The different calculation patterns have different data accuracy characteristics that affect which approach is appropriate.
Stored calculations reflect the state when they were calculated, not necessarily the current state. If your stored calculation references a related record's field, and that related record changes, your calculation doesn't automatically update unless FileMaker recognizes the dependency.
This creates subtle bugs. A stored calculation Invoice::Total that sums LineItems::Amount will update when line items in that invoice change. But if it references Products::Price through the line items, and you change a product's price, existing invoices won't recalculate because FileMaker doesn't track that indirect relationship.
Unstored calculations always reflect current state because they evaluate on demand. They can't become stale. This makes them ideal for calculations dependent on global fields, current date/time, or complex relationship paths where FileMaker might not track dependencies correctly.
Scripted values are as current as your script logic makes them. They can be perfectly accurate if you script the updates correctly, or completely wrong if you miss an update scenario. The burden is entirely on you.
For financial data, reporting totals, or anything requiring audit trails, stored calculations or scripted values create a record of what the value was at a specific point in time. Unstored calculations don't provide this historical context because they always show current values.
Decision Framework 1: The Dependency Map
Your first decision framework focuses on what the calculation depends on.
Use stored calculations when:
- Dependencies are fields in the same record
- Dependencies are predictable related records with clear relationships
- The calculation result rarely changes relative to how often it's read
- You need historical accuracy (what the value was, not what it would be now)
Use unstored calculations when:
- Dependencies include Get functions (CurrentDate, CurrentTime, AccountName)
- Dependencies include global fields that change independent of records
- Dependencies cross multiple relationship hops where FileMaker might not track changes
- The calculation is expensive but accessed infrequently
- You're calculating across large portals or related sets
Use scripted values when:
- Dependencies are too complex for FileMaker to track reliably
- You need precise control over when values update
- Calculation would be too slow even when stored
- You need to maintain historical snapshots at specific moments
Example: A Task::IsOverdue calculation that compares DueDate to Get(CurrentDate) should be unstored. It needs to reflect today's date, not the date when the record was last modified. Making it stored would require a script to touch every task record daily just to update the calculation.
Conversely, Task::DaysToComplete that calculates CompletionDate - StartDate should be stored. Once both dates exist, the value never changes, and you might search, sort, or report on this field frequently.
Decision Framework 2: The Usage Pattern
How you use the field determines the right pattern as much as what it calculates.
Use stored calculations for:
- Fields displayed in list views or portals with many rows
- Fields used in find requests
- Fields used for sorting
- Fields indexed for relationships
- Fields exported or reported on frequently
FileMaker can only search and sort on stored fields efficiently. While you can technically sort by an unstored calculation, FileMaker must calculate the value for every record in the found set before sorting, which becomes prohibitively slow on large data sets.
Use unstored calculations for:
- Conditional visibility calculations on layouts
- Calculations displayed only on single-record detail layouts
- Validation calculations
- Fields that adapt to the current context (user, date, related data)
Use scripted values for:
- Values that snapshot at specific business events (invoice posting, order shipping)
- Denormalized data for performance (cached calculations from related tables)
- Values requiring complex multi-step logic beyond calculation capabilities
Example: An Order::Status field determining if an order is "Pending," "Shipped," or "Delivered" based on dates and related shipment records might start as a stored calculation. But if you need the status to lock at "Shipped" when a shipping record is created (historical accuracy), convert it to a scripted value set by your shipping workflow script.
Decision Framework 3: The Relationship Context
Calculations involving related records require special consideration because FileMaker's dependency tracking has limitations.
FileMaker tracks first-level dependencies well. If your calculation in Table A references a field in related Table B through a single relationship, changes in Table B will trigger recalculation in Table A (for stored calculations).
FileMaker struggles with deeper dependencies. If your calculation in Table A references Table B which references Table C, changes in Table C might not trigger recalculation in Table A.
Use unstored calculations when:
- The calculation aggregates portal data (Sum, Count, List)
- Relationships involve multiple hops
- Related records can be added/edited/deleted outside your control
- You're calculating across filtered relationships
Portal aggregations like Sum(LineItems::Amount) should generally be unstored unless you have very few records and high read frequency. When line items change, FileMaker recalculates the stored sum, but this happens for every record in the parent table that displays the field, even records with no changed line items.
Use stored calculations or scripted values when:
- You need to search or sort by the aggregated value
- The portal data rarely changes
- You're willing to accept the recalculation overhead
- You need historical accuracy of what the total was at a specific time
Example: An invoice total that sums line items might be unstored during draft status (changes constantly, only displayed to one user) but converted to a scripted value when the invoice posts (fixed historical record needed for accounting).
Decision Framework 4: The Scale Factor
The size of your data set dramatically affects which pattern performs best.
Small tables (under 1,000 records): Store almost everything. The performance difference is negligible, and stored calculations enable searching and sorting without penalty.
Medium tables (1,000--50,000 records): Be selective. Store frequently accessed calculations with stable dependencies. Use unstored for time-based calculations and complex aggregations. Profile your solution to identify bottlenecks.
Large tables (50,000+ records): Minimize stored calculations. Each stored calculation adds overhead to every record creation and edit. Consider scripted values for expensive calculations needed for reporting, calculating them on-demand via script rather than maintaining them for all records.
The FileMaker Data API documentation notes that stored calculation overhead scales with table size, making design decisions more critical as data volumes grow.
Example: A "Status Summary" calculation that concatenates several status fields might be fine stored in a 500-record Projects table. In a 100,000-record Tasks table, that stored calculation adds unnecessary overhead. Make it unstored and only display it on detail views, not list views.
The Hybrid Approach: Conditional Storage
Sometimes the right answer is changing your approach based on state. A calculation might need different patterns at different points in a record's lifecycle.
Pattern: Draft vs. Final
- While records are in draft status, use unstored calculations for flexibility
- When records finalize, run a script to copy calculations into stored fields or regular fields
- Provides real-time accuracy during editing, historical accuracy after finalization
Pattern: Active vs. Archived
- Active records use unstored calculations for current data
- When archiving, script copies unstored values to stored fields
- Active records stay lean, archived records preserve snapshot
Pattern: Cached Summaries
- Complex aggregations are normally unstored
- When generating reports, script calculates and stores results temporarily
- Report uses stored values for speed, then clears them after
Example: A project management solution might have an unstored Project::CurrentBudgetStatus that calculates complex cost projections. When the project closes, a script captures this calculation into a stored Project::FinalBudgetStatus field, preserving the final state for historical reporting.
Common Pitfalls and How to Avoid Them
Pitfall 1: Storing date/time-dependent calculations. Never store calculations using Get(CurrentDate), Get(CurrentTime), or Get(CurrentTimestamp). They calculate once and never update unless triggered by a field change. Use unstored or script on a schedule. Unless the field is for housekeeping, such as CreatedDate.
Pitfall 2: Unstored calculations in portal filters. Portal filters that reference unstored calculations can create severe performance problems. FileMaker must calculate the value for every record to determine portal membership. Store the value or use scripted finds instead.
Pitfall 3: Circular dependencies. Field A calculates based on Field B, Field B calculates based on Field A. FileMaker can't resolve this with stored calculations. Use unstored or break the dependency through scripted values.
Pitfall 4: Over-storing in mobile solutions. FileMaker Go performance suffers more from excessive stored calculations due to device constraints. Be more aggressive with unstored calculations in mobile-first solutions.
Pitfall 5: Assuming stored is always faster. Storing a calculation that changes constantly can actually decrease performance due to repeated recalculations and disk writes. Profile before deciding.
A Practical Testing Strategy
Don't guess. Test your FileMaker calculation performance and make informed decisions.
Create test records: Generate 10,000+ test records to observe performance at scale. Small datasets hide problems that appear in production.
Time operations: Use Get(CurrentTimeUTCMilliseconds) before and after operations to measure impact of different calculation approaches.
Monitor during import: Import 1,000 records and watch how long it takes with various calculation configurations. Stored calculations add visible delay.
Test list view scrolling: Open a list view showing 100+ records with calculations. Smooth scrolling indicates good performance. Lag suggests too many unstored calculations evaluating.
Check find and sort speed: Time how long finds and sorts take on stored vs. unstored fields. This quickly reveals if you need to store for search performance.
Use the Data Viewer: FileMaker's Data Viewer can evaluate calculations and show execution time, helping you identify expensive operations.
When to Reconsider Your Choices
Your calculation patterns aren't permanent. As your solution evolves, reassess your decisions:
Signs you should store a currently unstored calculation:
- Users complain about slow list views or portal rendering
- You're adding search or sort functionality for the field
- The underlying data changes infrequently
- You're using it in a portal filter
Signs you should unstore a currently stored calculation:
- Import or record creation has become noticeably slow
- The table has grown significantly
- The calculation's dependencies have expanded beyond FileMaker's tracking
- You discover records with stale values
Signs you should convert to scripted values:
- You need to lock values at specific business process moments
- The calculation is too complex or slow even when stored
- You need different values for the same calculation logic in different contexts
- FileMaker's dependency tracking isn't capturing all changes
Real-World Example: E-Commerce Order System
Let's apply these frameworks to a realistic scenario. You're building an order management system with Orders, LineItems, Products, and Customers tables.
Order::OrderDate (regular field, not calculated)
- Foundation data entered by script or user
Order::CustomerName (stored calculation)
Customers::FullNamethrough relationship- Rarely changes, frequently displayed and searched
- Needs to reflect customer name at time of order (historical accuracy)
Order::TotalItems (unstored calculation)
Count(LineItems::ItemID)- Line items can be added/deleted frequently during order entry
- Only displayed on detail view, not list view
- Making it stored would trigger recalculation on every line item change
Order::SubTotal (unstored during draft, scripted when finalized)
Sum(LineItems::Total)while in "Draft" status- When order status changes to "Confirmed," script copies value to
Order::SubTotal_Stored - Provides flexibility during editing, fixed value for accounting
Order::DaysSinceOrder (unstored calculation)
Get(CurrentDate) - OrderDate- Must reflect today's date, not calculation date
- Used for dashboard aging reports, not searched
Order::StatusDisplay (stored calculation with conditional logic)
- Complex calculation with multiple status rules
- Displayed in list views frequently
- Dependencies are fields in same record
- Store for search and display performance
LineItem::ProductName (scripted value)
- Copies
Products::Namewhen line item created - Must preserve product name at time of purchase
- Product names might change, but historical orders shouldn't
- Regular field populated by script, not calculation
This mixed approach optimizes for different needs within the same solution. No single pattern fits everything.
Let's summarize..
Choosing between stored calculations, unstored calculations, and scripted values isn't about following rigid rules. It's about understanding the trade-offs and matching patterns to requirements.
Ask yourself these questions for each calculation:
- What does it depend on?
- How often does it change vs. how often is it read?
- Do I need search/sort capability?
- Is historical accuracy or current accuracy more important?
- How does it perform at scale?
- Is the dependency trackable by FileMaker?
The answers guide you toward the right pattern. Sometimes you'll make a choice, deploy it, and later need to change it as requirements evolve. That's normal. The key is making informed decisions based on understanding rather than arbitrary preferences.
Your FileMaker calculation performance and data accuracy depend on these architectural choices. Invest time upfront thinking through calculation patterns, and you'll avoid months of performance troubleshooting and data inconsistency investigation later.
What should you do next?
Audit your current FileMaker solution. Look at your calculation fields and ask: is this stored or unstored, and why? Are there fields that should be reconsidered based on the frameworks in this article?
Pick three calculations that seem problematic: slow performance, stale data, or just uncertainty about whether they're configured correctly. Apply the decision frameworks and make intentional choices about their configuration.
Test the changes with real data volumes. Create test records, time operations, and verify that your choices improve both performance and accuracy.
Remember that these patterns apply to new development and refactoring existing solutions. You don't need to fix everything at once, but every informed decision moves your solution toward better performance and reliability.
What calculations in your current FileMaker project could benefit from rethinking their storage approach? Start there and build better calculation patterns into your development practice.
Further Reading
FileMaker Performance and Optimization:
- FileMaker Performance Best Practices --- Official Claris performance guidelines and optimization strategies
- FileMaker Calculations Guide --- Defining Calculation Fields
- FileMaker Bottlenexks and Performance Optimization ( Dimitris Kokoutsidis, Axelar)