0
Best Practices
The following best practices are key recommendations that have proven particularly effective when working with Ninox. They address common pitfalls such as inefficient data access, unwanted trigger cascades, and loop-intensive computations. Consistently applying these guidelines can help reduce load times and conserve system resources.
- Optimize initial views for large tables
When working with large tables, filter the initial view to display only a relevant subset of records - specifically, only those that are really needed. This significantly improves load performance and enhances the user experience.
- Avoid conflicting or circular triggers
Ensure that triggers are designed to operate independently and do not interfere with one another. In particular, avoid configurations that may cause circular references or unintended trigger loops, as these can lead to unpredictable behavior and performance issues.
- Use select statements sparingly
Only useselect
statements when absolutely necessary. If references to the target table already exist, leverage those instead. For accessing related data in sub-tables, prefer dot notation overselect
statements to improve performance and maintain clarity.
Instead of:
let me := this; sum((select InvoiceItems where Invoice = i).total)
better use:
let me := this; sum((me.InvoiceItems[Invoice=i].total)
- Minimize select statements in function fields
Avoid usingselect
statements within function fields displayed in table or form views whenever possible. If aselect
statement is required, use thewhere
clause for defining conditions instead of square bracket syntax[...]
.
Avoid repeated select executions
When a select statement is required in a script, execute it only once and store the result in a variable. Reuse this variable to access multiple fields as needed. This approach enhances performance and reduces redundant database operations.
- Avoid select statements in nested loops
Wherever possible, refrain from usingselect
statements within nested loops. This pattern can lead to significant performance degradation due to repeated database access. Instead, consider retrieving data in advance and working with caching.
- Prefer writing static values over repeated formula evaluation
Instead of recalculating formulas dynamically each time ("on the fly"), consider writing static values to data fields using triggers - provided it's appropriate and beneficial. This reduces processing overhead and improves overall system efficiency.
- Efficient searching in table views from dashboard form views
When performing searches in table views via a form view (e.g., used as a dashboard), define all variables usinglet
before executing the search with aselect
statement. To optimize performance, limit the result set—e.g., to 100 records—to avoid loading unnecessary data. Additionally, use thenot
command to properly handle empty search fields and ensure accurate filtering.let mySearch := 'Project search'; select Projects where (not mySearch or ProjectName + concat('Project staff'.'Choose Person'.('First name' + " " + 'Last name')) like mySearch) from 0 to 100
- Avoid storing large text blocks in text fields
Refrain from storing large content—such as CSV files for data transfer or JSON payloads for API calls—directly in text fields. Since Ninox logs every change, this can lead to an excessively large change history and impact performance. A better approach is to generate such content usingcreateTextFile()
and store it as an attachment. The file can then be accessed via the API when needed.
- Use indexing selectively
Apply indexing thoughtfully - only to fields that are frequently searched and benefit from faster access. Fields with limited value sets, such as Yes/No fields, typically do not require indexing. In tables where records are regularly deleted, it's recommended to periodically reset indexing via the database options to maintain optimal performance.