This page covers Appian design guidance in the Appian Designer, including what it is, where it may appear, and how to address it.
Appian design guidance is made up of both warnings and recommendations. Applying these design patterns helps improve the performance of your applications and objects, and reduces the likelihood of runtime problems and maintainability issues. During development, Appian will alert you in real-time if it detects a warning or a risky design pattern that goes against a best practice.
Within objects, warnings and recommendations are indicated with a yellow triangle and lightbulb icon, respectively, and appear in the Appian header next to the object's Save Changes button. When applicable, warnings and recommendations also appear next to the object's relevant field or line.
See all design guidance for a full list of warnings and recommendations available per object type within Appian Designer.
Developers must have at least Viewer permissions to an object to see its design guidance.
The following are examples of warnings and recommendations within various object types.
All design guidance for an environment or an application is visible in a single, centralized place on the Health Dashboard located under the Monitor view. See the Appian Design Guidance grid of the Health Dashboard to learn more.
Process models must be published in order for their guidance to appear on the Health Dashboard.
Appian design guidance includes both warnings and recommendations. Warnings are indicated with a yellow triangle icon and alert you when Appian has detected a design pattern that will cause errors or unexpected behavior at runtime. Warnings cannot be dismissed and should always be addressed.
Recommendations are denoted by a grey lightbulb icon and appear when Appian has detected a design pattern that goes against a best practice. Recommendations should always be reviewed and addressed. Unlike warnings, you can address a recommendation by dismissing it.
Note that Appian recommendations are suggestions based on Appian’s best practices. Depending on your designs and use cases, some recommendations may not apply.
Recommendations can either be active or dismissed.
When a recommendation is first triggered it is immediately active, meaning that it is visible both within the object and on the Health Dashboard. A recommendation will remain active and visible until it is either addressed by making the relevant change to the object’s design, or a developer dismisses it from within an object.
Once dismissed, recommendations are no longer visible within objects. You can see dismissed recommendations for objects at any time on the Health Dashboard by using the Include dismissed recommendations filter.
Dismissed recommendations remain dismissed indefinitely unless one of the following occurs:
Developers must have at least Editor permissions to an object to be able to dismiss its recommendations.
Recommendation dismissals are promoted across environments as part of manual or direct deployments. When an object's recommendation is dismissed on the source environment, it will remain dismissed on the target environment after that object is deployed. If an error is encountered when importing or exporting recommendation dismissals, the related object will not be impacted.
The following table lists the different expression warnings and recommendations. These appear within any expression editor in the product, with the exception of expression editors in the Process Modeler. They also appear on the Health Dashboard in the APPIAN DESIGN GUIDANCE grid.
If an expression has a syntax error (indicated by a red warning icon), expression guidance will not be detected. Resolve the syntax error to see warnings and recommendations displayed within the expression editor, object header, and the Appian Design Guidance grid on the Health Dashboard.
|Name||Type||Description within Object||Additional Information|
|Improperly scoped variable||Recommendation||A variable is not declared or is used outside of its intended location. Declare local variables or use rule inputs to pass data into this object instead. Failing to do so complicates maintainability and testing.||This recommendation can be triggered in one of two ways: if a variable is used without first being declared, or if a variable is called outside of its intended location (for example, if a process variable is referenced in an interface). To address this recommendation, declare the variable as a local variable before calling it or pass the data into the object using a rule input.|
|Invalid keyword syntax||Warning||There are more keywords than arguments. Modify the expression so that each keyword takes a single argument. Invalid keyword syntax will cause problems during export and may affect runtime.||This warning is triggered when the number of keywords and arguments in a function, rule, or type constructor do not match. It is typically caused by a typo in keyword syntax such that a keyword is accidentally repeated (for example,
|Invalid parameter||Warning||Update the underlined parameters so that they match a documented option. Parameters that don't exist in the function, rule, or data type are ignored.||This warning is triggered if an invalid or unrecognized parameter is used when calling a function, rule, or type constructor. Common causes include typos in parameters or referring to an object rule input that has since been renamed or removed. Data passed into invalid parameters is ignored, so Appian strongly encourages you to address this warning by providing a valid parameter.|
|Invalid process parameter||Warning||A process parameter does not match any of the parameters configured in the process model. Ensure that the process model has a corresponding parameter process variable. Invalid parameters will cause the expression to break at runtime.||This warning is triggered if an invalid or unrecognized parameter is used when calling a!startProcess or a!startProcessLink functions. Common causes include typos in parameters or referring to a process model process variable that has not been marked as a parameter, or has since been renamed or removed. You should always address this warning because invalid process parameters will cause your expression to break at runtime.|
|Invalid record field reference||Warning||One or more record field references are invalid because they have been deleted or changed. To prevent errors, update the invalid field references to use valid field references.||This warning is triggered if an invalid or unrecognized record field is used in the expression. The most common cause is referring to a record field that has since been renamed or removed. An invalid field reference will result in an error at runtime, so Appian strongly encourages you to address this warning by providing a valid field reference.|
|Missing domain prefix||Warning||A variable or rule is being called without a domain prefix. It is a best practice to use domain prefixes in your expressions to ensure that the appropriate variable or rule is referenced at runtime.||This warning is triggered when a variable or rule in an expression is missing a domain prefix. Using domain prefixes ensures that the correct variables and rules are referenced at runtime and reduces the likelihood of unexpected behavior. Appian strongly recommends that you address this warning by adding domain prefixes to every variable and rule.|
|Missing keyword syntax||Recommendation||Use keywords to pass inputs into rules or data types. By using keyword syntax, you protect the current expression against backwards compatibility issues if inputs change in the future.||This recommendation alerts you when inputs are passed into a rule or type constructor without using keyword syntax. It is only triggered for rules or data types that have more than one input defined. It is a best practice to use keyword syntax to avoid future backwards compatibility issues when inputs are added, reordered, removed, or renamed.|
|Unsupported function detected||Recommendation||Refactor your expression to use documented functions. The function you have called is not supported and may break on upgrade.||This recommendation is triggered when Appian detects the use of an unsupported function. Unsupported functions are not documented and the behavior may change or break on upgrade. To address this recommendation, refactor your expression to use documented Appian functions.|
|Unused local variable||Recommendation||A local variable is declared but is not used within an expression. If you do not intend to use the local variable, Appian recommends removing it. Unused local variables can perform unnecessary queries and complicate comprehension and maintainability.||This recommendation is triggered when a local variable is defined within an expression but is not referenced. It is a best practice to remove unused local variables to avoid executing unnecessary logic and to make it easier for developers to enhance, debug, and maintain the expression in the future.|
|Unused rule input||Recommendation||A rule input is not referenced in the object definition. If you do not intend to use the rule input, Appian recommends removing it. Unused rule inputs can complicate comprehension and maintainability.||This recommendation is triggered when a rule input is not referenced in an object’s main expression. This recommendation only applies to expression rules, integrations, and interfaces. It is a best practice to remove unused rule inputs and all references to them in dependent objects. The presence of unused rule inputs makes it harder for developers to enhance, debug, and maintain an object in the future.|
|Name||Type||Description within Object||Additional Information|
|Missing primary key||Recommendation||Missing primary key. Add a primary key to ensure that each row in the database is uniquely identifiable and to avoid errors when querying and writing data.||This recommendation only applies to custom data types that are mapped to a data store AND that are missing a primary key. It is a best practice to define primary keys for your data types to ensure that data is properly written to and queried from the database. Learn more about primary keys and how to define them here.|
|Multiple levels of nesting||Recommendation||Multiple levels of nested data types detected. Consider creating a flat data type relationship instead to avoid nesting data types more than one level deep. Multiple levels of nested data types can complicate data access at child levels and reduce query performance.||This recommendation is triggered when a custom data type contains fields of data types with more than one level of nesting (for example, the Company data type has a field of type Employee and Employee has a field of type Address). Highly nested data types create complex many-to-many relationships that are hard to maintain and reduce query performance. Instead of nesting your data types, use flat data type relationships. For example, add a companyId field to the Employee data type instead of having a field of type Employee on Company. This allows you to query employees by company directly.|
|Outdated data type reference||Warning||N/A||This warning alerts you when you have a custom data type that has one or more fields that reference an outdated data type (denoted with a ^ symbol). When you open this data type, validations will appear on the affected fields and you will be required to address them before being able to save a new version of the data type.|
|Primitive type array||Recommendation||Array of primitive type detected. Consider replacing this field with a new custom data type. Data in primitive array fields cannot be updated or interacted with directly, which complicates data management.||This recommendation only applies to custom data types that are mapped to a data store AND that have one or more fields of primitive type arrays. It is a best practice to avoid using arrays of primitive types because Appian treats the values in these arrays as one-to-many relationships and the values cannot be updated (only new values can be inserted). This increases the likelihood of having duplicate data and can cause queries to return unexpected results. Instead of using a primitive type array in your custom data type (Type A), create a new custom data type (Type B) to store that information. Then, add an array field of Type B to Type A; this creates a flat one-to-many relationship.|
|Too many fields||Recommendation||More than 100 fields detected. Consider moving additional fields into a new, related data type. Appian recommends that data types have fewer than 100 fields for better maintenance and performance.||It is a best practice to keep data types small so that they are easier to maintain over time, have better performance when queried, and reduce memory consumption. To learn more about custom data type relationships and how to implement them when breaking a larger data type into smaller related ones, see CDT Design Guidance.|
The following table lists the different process model guidance that may be shown within the Process Modeler or on the Health Dashboard in the APPIAN DESIGN GUIDANCE grid. Warnings and recommendations that are specific to process nodes will list the affected nodes at the end of their description.
|Name||Type||Description within Object||Additional Information|
|Asynchronous subprocess||Recommendation||A subprocess node is set to run asynchronously and is either used in a loop or configured to run multiple instances (MNI). Instead, consider using the Start Process smart service, which has built-in load balancing. Initiating a large number of processes with the Subprocess node can slow down performance.||This recommendation alerts you about the potential performance implications of starting a large number of subprocesses. It is triggered when a subprocess node is configured to run asynchronously AND is used in a loop or set to run multiple instances. Subprocess nodes do not have built-in load balancing across execution engines. Processes that are initiated as a subprocess will run on the same execution engine as their parent process (learn more). This means that when a large number of processes are initiated as a subprocess, process load is not evenly distributed across execution engines and performance can be adversely affected. To address this recommendation, either use the Start Process smart service, which evenly distributes processes across execution engines, or split the load across more parent processes.|
|Data types passed by reference||Recommendation||Subprocess nodes pass custom data types by reference. Consider not passing the data type by reference and instead updating the value with an output variable. Passing data types by reference can cause issues with long-lived processes.||This recommendation is triggered when a custom data type process variable is passed by reference into a subprocess. When a new version of a custom data type is created, active processes are not updated and continue to use the version of the data type that existed when the process started. However, subprocesses always start using the latest version of a data type. Therefore, a parent process and the subprocess model could reference different versions of a data type, depending on when the data type is updated. If this occurs AND the data type is passed by reference, the parent process will break when it reaches the subprocess node. Instead of passing custom data type variables by reference, pass the data into and out of the subprocess using input and output variables.|
|Gateway nodes with multiple incoming flows||Recommendation||Gateway nodes in a loop have more than one incoming flow. Place a script task in front of each of these gateway nodes to merge incoming flows.||This recommendation applies to AND, OR, XOR, and Complex gateway nodes that are used in a loop. Gateway nodes with multiple incoming flows allow first flows through, but wait for all incoming flows to arrive before executing any subsequent flows, which can cause processes to wait indefinitely. For this reason, it is a best practice to merge incoming flows using a script task in front of gateway nodes that are used in a loop.|
|Misconfigured error alerts||Recommendation||This process model uses the system default for alerts. Alerts should be sent to an application-specific group. Using the system default only alerts process administrators, process model administrators, and system administrators, who may differ across environments.||This recommendation is triggered when a process model’s error alerts use the system default. It is a best practice to send process alerts to an application-specific group, by either using a constant or an expression in the process model properties’ alerts tab. Providing an application-specific group ensures that alerts are sent to the appropriate users in each environment.|
|Misconfigured error alerts||Recommendation||This process model targets a user as the alert recipient. Appian recommends sending alerts to groups, since the same users may not exist on all environments.||This recommendation is triggered when at least one individual user has been specified as a process model’s error alert recipient. It is a best practice to use only groups as alert recipients because not all users exist on all environments. Remove users and instead use a constant or an expression in the process model properties’ alerts tab to send alerts to an application-specific group.|
|Multiple node instances (MNI) with activity chaining||Recommendation||Unattended nodes configured to run multiple instances (MNI) have incoming activity chaining. Consider redesigning your process to make this MNI activity a bulk or asynchronous operation. Chaining through these nodes can cause a poor user experience or performance issues.||This recommendation is triggered for unattended nodes that are configured to run multiple instances AND that have incoming activity chaining. Activity chaining through multiple node instances makes it more likely to exceed the 50 node chaining limit. It can also cause performance issues that impact the user experience, such as users seeing long wait times between chained forms. If the activity can be a bulk operation, redesign your process to achieve the same result in fewer steps. For example pass an array of values into a Write to Data Store Entity node or use looping functions to perform the operations in a single script task.|
|No target process for send message event||Recommendation||A send message event is not configured to target a specific process. Consider providing a destination process ID on the Data tab to target specific processes. Sending a message to all process instances is less efficient and can have performance implications.||This recommendation is triggered when a send message event node does not target a specific process using a destination process ID. It is a best practice to target messages to specific processes because sending messages to all process instances can have negative performance implications. The potential for poor performance increases as the number of running processes in the environment grows.|
|Process display name not dynamic||Recommendation||Process display name is not dynamic. Consider using an expression to define a unique display name per process. Having unique process display names makes it easier to monitor and debug active processes.||This recommendation is triggered when the process display name is provided and does not include a variable or expression. It is a best practice to make display names dynamic by including unique information, such as an ID or a timestamp. This makes it easier to differentiate between active processes of the same process model on the Process Activity monitoring tab.|
|Task display name not dynamic||Recommendation||A user input task display name is not dynamic. Consider using an expression to define a unique display name per user input task. Having unique display names makes it easier for users to differentiate between their tasks in Tempo and task reports.||This recommendation is triggered when a user input task’s display name is provided and does not include a variable or expression. It is a best practice to make task display names dynamic by including unique information, such as an ID or a user-entered value. This helps users easily differentiate between instances of the same task in Tempo or task reports.|
|Too many nodes||Recommendation||X process nodes detected. Consider splitting this process into smaller subprocesses. Having more than 50 nodes can complicate maintainability and lead to higher memory consumption.||This recommendation is triggered when a process model has more than 50 nodes. It is a best practice to keep process models small so that they are easier to understand and maintain, and occupy less memory. Reducing the number of nodes in a process model also helps to reduce its completion time. To reduce the number of nodes in your process model, combine nodes where possible or split the model into smaller subprocesses.|
|Too many process variables||Recommendation||X process variables detected. Consider whether process variables should be activity class parameters or split the process into smaller subprocesses. Having more than 100 process variables can complicate maintainability and lead to higher memory consumption.||This recommendation is triggered when a process model has more than 100 process variables. It is a best practice to minimize the number of process variables used in a process model for memory and maintainability reasons. To reduce the number of process variables in a process, convert your process variables into activity class parameters where applicable, or break your process into smaller subprocesses.|
|Unused process variable||Recommendation||This process model contains a process variable that it does not reference. Remove the variable if you do not intend to use it and have confirmed that it is not in use by a process report. Unused process variables can complicate comprehension and maintainability.||This recommendation is triggered when a process variable is not referenced in the process model. This check does not verify whether the process variable is used in any process report. It is a best practice to remove unused process variables and all references to them in dependent or precedent objects. The presence of unused process variables makes it harder for developers to enhance, debug, and maintain objects in the future.|
|Name||Type||Description within Object||Additional Information|
|Incompatible Function Used||Warning||Refactor the portal object precedents to only use functions compatible with portals. Incompatible functions will not work in a published portal.||This recommendation is triggered when any precedents of the portal object use a function that is either not compatible with portals or is only partially compatible. Partially compatible functions require a custom integration to work in a portal. See Appian Functions to determine function compatibility.|
|Incomplete reCAPTCHA setup||Recommendation||If you want to use reCAPTCHA in a portal page, use the recaptchaSaveInto parameter in a button on the interface. Otherwise, you can remove the reCAPTCHA connected system since none of the pages use reCAPTCHA.||This recommendation is triggered when you have specified a reCAPTCHA connected system in the portal object, but none of the interfaces referenced by the portal object have the correct configuration. See Using reCAPTCHA in Portals.|
|Misconfigured data store||Recommendation||Either remove the reference to the following data stores or connect to them using a data source connected system.||This recommendation is triggered when you are connecting a portal to a publicly-available external database using a data store entity and you have not properly connected to it with a data source connected system.|
|Missing document permissions||Recommendation||Give the service account permissions to all documents or document folders used in the portal. The service account grants the portal access to documents stored in Appian.||This recommendation is triggered when the entered service account doesn't have permission to at least view the documents or document folders used in the portal. Check security settings and make sure the group that your service account is in has at least viewer level permission.|
|Missing page||Warning||Add a page to publish the portal. "Published" is selected, but the portal can't be published without a page.||This warning is triggered when the Published option is turned on in the Configurations section without any pages added in the Pages section. See Add a Page to your portal.|
|Missing reCAPTCHA connected system||Warning||Specify a Google reCAPTCHA connected system in the portal object. One or more portal pages use the recaptchaSaveInto parameter, but reCAPTCHA will not work until the connected system is specified.||This warning is triggered when an interface referenced by the portal has a recaptchaSaveInto parameter configured but there is no reCAPTCHA connected system specified in the portal object. See Using reCAPTCHA in Portals and Add a Google reCAPTCHA connected system.|
|No service account||Recommendation||Your portal does not have a service account but references one or more documents or document folders.||This recommendation is triggered when you leave the service account field in the portal object blank and your portal references documents or document folders. See Create a Portal to learn how to add a service account to the portal object.|
|Portal URLs missing UUID||Recommendation||The option to add UUIDs to portal URLs is not enabled in the Admin Console. We recommend enabling this setting for non-production environments to make it harder for unintended users to find portals that are in development.||This recommendation is triggered in development and testing environments when the Add UUID to portal URLs option is not checked in the Admin Console. This setting can be found in the Portals section under System.|
|Rule inputs have changed||Warning||Edit the following page(s) to update the Rule Input Configurations. Then save the portal object to use the updated URL parameters.||If you add, delete, or rename rule inputs in an interface object that is used as a portal page, you need to update the rule inputs on the portal page. If you create or rename a rule input in an interface object, you must save the portal object before you can use them as URL parameters in a!urlForPortal().|
Appian Design Guidance