Dynamics 365 Development Best Practice Guide

This guide provides the best practices you need to optimize the following Dynamics 365 (D365) functions:

  1. Solutions
  2. Fields
  3. Relationships
  4. Forms
  6. Model-driven Apps
  7. Processes
  8. Web Resources
  9. Plug-ins


  1. Add a publisher prefix

  2. Adding a prefix to solution components that’s relative to you or your organization enables users to quickly identify who created or customized each component.

  3. Manage customizations in custom solutions (not default solutions)

  4. Customizations created within default solutions cannot be exported or distributed to other environments. In addition, the default solutions use their default publisher, which results in an unspecified/uncontrolled publisher being assigned to components. To avoid these issues, create custom components (e.g., entities, web resources, modern apps, processes, security roles) within custom solutions. If you want to customize out-of-the-box (OOB) components, add them to the custom solution before customization.

  5. Add detailed component descriptions

  6. Adding detailed descriptions to entities, forms, views, fields, and processes prevents confusion and enables fellow developers to easily identify what the component is for.

  7. Export unmanaged and managed solutions for every release

  8. Unmanaged solutions can be used to reconfigure the system or set up a new instance if the development environment fails. Managed solutions must be used to deploy customizations in higher environments (QA, pre-production, and production).

  9. Create separate, unmanaged solutions for ribbon customizations

  10. Ribbon workbench imports entire solutions, recreates each entity ribbon, and then publishes them. Fewer entities reduce ribbon update time.


  1. Use unique field names

  2. Duplicate field names may cause an error while importing data, or confuse users creating personal views, Power Automate flows, and more.

  3. Choose the correct field data type

  4. Choose a data type that accurately reflects the data you want to store. If your data contains null values, ensure the data type you select supports null values.

    For example: If time is not required for a date, then choose the “Date Only” field data type. Or, if a field allows only two values without any default value, then choose the “Option Set” data type.

  5. Create alternate keys for fields or group of fields

  6. This prevents the user from creating records with duplicate field values or combination of field values.

    Warning: Once the key is deployed to the managed environment, it cannot be deleted.

  7. Check ‘Disable most recently used items for this field’ setting for filtered lookup fields

  8. This prevents users from selecting unrelated options from recent searches.

    For example: If the lookup fields are ‘State’ and ‘City’, disable most recently used items for ‘City’. If not disabled, users may be able to select a city from recent searches irrelevant to the selected state.


  1. Enable field mapping

  2. Enable field mapping to auto-populate field data from a parent record when a child record is created (common for sub-grids).


  1. Remove asynchronous function calls when saving quick create forms

  2. On quick create forms, the Save & Close button does not wait for asynchronous function calls to complete (e.g. retrieve record WebAPI). If possible, remove asynchronous calls when saving quick create forms and instead execute the calls upon form load, or upon change of field values.

  3. Register Event Handlers for field events programmatically

  4. Use JavaScript method addOnChange to bind field onChange events instead of binding it from form properties. This helps you programmatically gain control over field events.


  1. Use only alphanumeric characters for view names

  2. Using special characters for view names may cause issues when importing from Excel.

  3. Limit view columns to show only required fields

  4. Optional fields may not have data and may increase the size of the grid to accommodate empty cells.

  5. For sub-grid views, which show related records, don't add a parent column to view

  6. If you add a parent column to sub-grid views, the same value will be shown for all related records.

    For example: If a state entity is added as a sub-grid in a country entity, don't add a country column in sub-grid view of state, as it will be the same for every country record.

  7. Add icons for categorical fields

  8. Adding icons for status, gender, rank, profit, loss, etc. enables users to quickly identify fields.

  9. Ensure columns and relative orders are consistent across both active and inactive views

  10. This ensures consistency in information available for records across both states.

Model-driven Apps

  1. Replace the app’s GUID with a user-friendly URL name

  2. Use the app’s URL suffix to access the app instead of the app’s globally unique identifier (GUID). Using the URL suffix is more user-friendly.


  1. Update the stage of Business Process Flow (BPF) with custom fields

  2. Instead of executing moveNext() and movePrevious() operations from scripts, consider updating custom fields (such as status or gender) directly from scripts. This action activates predefined background workflows, plug-ins, and Power Automate flows linked to the Business Process Flow (BPF) entity, updating the active BPF stage.

Web Resources

  1. Use namespace for JavaScript web resources

  2. This ensures JavaScript methods are unique and prevents collisions between identifiers.

  3. Use relative paths to reference web resources

  4. This ensures the web resource references are environment independent, as absolute path references include the environment name.

    For example: use an HTML page to reference a JavaScript library.

  5. Write code in a common JavaScript web resource and add it to entity forms

  6. This saves time by enabling developers to quickly reference and reuse common code.

  7. Pass ExecutionContext only when it's necessary; otherwise, use FormContext

  8. ExecutionContext is a parent object of FormContext, which enables not only form event handlers, but grid event handlers also using GridContext.

  9. Bind preSearch lookup field event only on form load and use a global variable for dynamic custom filtration and update it whenever required

  10. This ensures high performance and easy maintenance of code related to custom filtration of lookup fields.

  11. Use Xrm.Constants

  12. Use Xrm.Constants to access constants like attribute required levels (e.g., none, required, recommended), attribute types (e.g., Boolean, date/time, lookup), and form notification levels (e.g. error, warning).

  13. Open forms with navigation popup

  14. Use Xrm.Navigation.navigateTo to open forms (entity record, entity list or HTML web resource) as a modal dialog instead of using Xrm.Internal.openDialog or jQuery custom dialog frameworks which are either deprecated or unsupported.

  15. Use browser-specific web developer tools to debug your code

  16. Debugging a JavaScript web resource in console often requires re-writing code. Debugging from browser tools is faster than using external tools.

    For example: To retrieve current record data from Xrm.WebApi, use Chrome DevTools’ Run Snippet feature, which has access to the page's JavaScript context and can run on any page (Firefox DevTools has a similar feature called Scratchpad).


  1. Use context.depth when updating fields using plug-ins

  2. If context.depth is not used, it causes infinite recursive plug-in calls.

  3. Update entity by creating a new instance with required fields only

  4. Instead of directly updating a case entity like service.Update(case), create a new entity using Entity temp = new Entity('case'), temp['x'] = 'value', service.Update(temp)). This creates a new instance with required fields only, which avoids unnecessary field updates and effort.

  5. Declare main execution function as static

  6. All other helper functions should be declared as private to reduce code duplication and improve performance.

  7. Create separate C# files to declare constants and XML expressions and to handle custom and system exceptions

  8. Creating separate files improves code readability.

  9. Limit plug-in files to a maximum of 8MB

  10. Microsoft Dynamics CRM plug-ins have a maximum plug-in size. Exceeding that limit prevents remaining plug-ins from being imported.


Up Next

Dynamics 365 Deployment Best Practices

Learn More →