JourneyApps Best Practices

In this post, we’ll cover general practices for developing applications on the JourneyApps platform. If you have any of your own and would like to share it with our community, please comment on this post.

App Development

  1. Start with your data model definitions and iterate fast. The best way to achieve this would be to have the app open whilst you write code so you can see your change in real-time.
  2. Don’t be afraid to change the app. The JourneyApps rapid development paradigm makes it easy to change your app based on user feedback.
  3. Familiarize yourself with the performance suggestions as outlined in this article.
  4. Limit queries in XML functions as these functions execute on each digest cycle. For more information on this topic, please see the $: functions and the digest cycle section of the Improving App Performance article.
  5. Cache data as long as it will scale appropriately, i.e., store commonly executed query results as variables in your views.
  6. Utilize .include() when working with related objects on your queries and arrays as it improves the performance of the look-ups. Please see the Include related objects in a query section of the Querying DB Objects documentation.
  7. When setting relationships to a parent object you could use the object.parent_id = instead of object.parent(existingParent) function if the parent is nested as this removes an additional network request.
  8. If you find yourself writing the same code over and over in different app views, create modules for common functions that are shared in your views. This makes things easier to debug and improves the quality of your code overall. To create modules in a JavaScript application, please see this guide on our dev community. If you are using a TypeScript app, use the command palette and search for “Create app module”.
  9. It’s important to understand the difference between using array:object vs. query:object when bound to the query attribute of components (on an object-table, for example). Please make sure you familiarize yourself with the difference between the two by reading the Guidelines for choosing between array and query in this article of the official documentation.
  10. Using the .forEach() function on query results yields unexpected results due to the asynchronous nature of the function. Note, this does not apply to query results that have been cast to an array via the .toArray() function.
  11. When working with larger or distributed teams, make sure to leave comments in your code as this reduces the effort it takes to share context with team members.
  12. Avoid excessive console.log statements in your code in a production environment. This will consume valuable memory on devices.


  1. When defining Webhooks on data models which are of type update, add a value that must be present on a field before the CloudCode task is invoked. This allows you to avoid writing code to check if certain values are set before data can be processed. In addition to this, it will also allow you a mechanism to avoid the webhook retrying/retriggering itself in an infinite loop. For more information on how to configure conditional values on Webhooks in JourneyApps, please see the Conditions and Embedded Fields section of this article.
  2. When developing CloudCode tasks that need to process large amounts of data, make sure to add functionality that caters to limiting the number of objects a single task instance can process and also add in the ability to enqueue a new instance of the task to continue with the process once these limits are reached. Familiarize yourself with the limits of CloudCode by reviewing the Limits section of this article. The easiest limits to run into will be the total runtime limit and the memory usage limit. This post shows the built-in mechanisms for catching and handling this before it is a problem.
  3. Strongly consider importing error monitoring solutions into your CloudCode tasks in the event that the CloudCode tasks error. This will allow you to catch errors and exceptions in your code and report these errors for responsive actions before users notice anything. A good example of this would be rollbar. But there is a wide variety of services that offer the same functionality. Here is a list of other such services.
  4. Implement shared functionality using the shared CloudCode template.

Data Model, Sync Rules & Backend

  1. Only use single-choice or multiple-choice field types for static field options (options that will not change over time). If you expect the options to change rather use separate models to define the options and refer to them using relationships by setting belongs-to or has-many join models. If your single-choice or multiple-choice options need to change you will most likely require data migrations to ensure historical data accuracy.

  2. Familiarize yourself with app indexes and add them to your data models. This significantly improves the performance of your application queries. For more details on how to configure indexes, please see this article in our documentation.

  3. Always include conditions to your sync rules. Keep in mind that sync rules need to be reprocessed when updates to the rules are deployed to your application. The time it takes to reprocess these rules is dependent on the amount of data in your application database, the number of recent changes to your data, and the number of recent deletes, so make sure to define the rules early on.

  4. If changes are made to your sync rules, always check the sync diagnostics page to see how long the reprocessing of the will take. To find the Sync Diagnostics page, open the backend data browser for a particular instance, select the dropdown arrow (top right), elevate permissions if needed (this will refresh the page, meaning you’ll need to open the dropdown again), and then select the “Sync Diagnostics” option from the dropdown list.

  5. Try to synchronize master data between environments when developing. This helps when debugging production code, without having to enroll a device in your production backend. The easiest way to accomplish this is through the use of the import/export CSV functionality on the backend instances.

  6. Consider adding the following fields to all your models and populating them throughout. This will make it easier to find, audit and debug your data.

  • deleted_at
    A Datetime field of when the data was deleted

  • created_at
    A Datetime field of when the data was created

  • deleted_by
    A belongs-to relationship between the object and the user who deleted the data

  • created_by
    A belongs-to relationship between the object and the user who created the data


Thanks for this @mike_barnes