Org Maintenance: Cleanup – Delete and Deprecate Metadata in Salesforce
In our last post we focused on how to manage an org migration and take advantage of the opportunity to clean up some unused features as you move on to a new org. But what if your production environment is not moving anywhere? How do you make sure that what you have is actually used and how do you get rid of the stuff you’re not using anymore? Here we’ll give you some tips on how to detect and clean up the clutter in your org.
Editor's note: This has become a very popular post since it was written. To build on this learning we're hosting a Lunch & Learn live demo of this process with Mario. Read on for an outline of the cleanup recommendations. You can register to join the demo live or receive the recording after here.
Refresher: What’s the Difference Between Data and Metadata?
Metadata is the structure of the data, while data is the actual data that you input. For example:
- Contact object has First Name, Last Name and Address. This is the metadata.
- A contact record has First Name = “John”, Last Name = “Smith” and Address = “123 Fake St”. This is the data, the different records you create (rows of information).
In Salesforce we consider metadata to be basically all the items you can configure in the Setup menu and that defines the way your organization works and what is available to end users.
In this post we will focus on cleaning up metadata, not data. When you clean up data, you’re looking for duplicated records or inconsistent data (formatting and/or completeness). When it comes to metadata, it’s just a simple question: “Are you using this?”, if yes then keep it, if no then deprecate it (archive it) or delete it. And because it’s metadata, removing metadata (that is not object and/or fields) means you get rid of functionality you’re not using anymore, but the data remains untouched. For example: you may not use a workflow rule anymore, so if you decide to delete it, any data that was modified by that workflow rule in the past will remain in the org as is.
We want to review our org and identify those items that are no longer needed and can be deprecated or deleted. Our goals are to:
- Make sure end users are not using deprecated components (components that perform outdated functionalities that may no longer align with the business processes).
- Prevent users from becoming overwhelmed by the volume of options they have when actually some of those options are no longer in use.
- Make it easier for future development to identify what’s currently valid and in use.
The Clutter: How Did It Happen?
As you set up your org or build a new feature, whether it’s a simple object with its fields and layouts or a complex workflow with subsequent actions, you go through different phases of configuration, testing and refining your process. For example: you create fields you think you need at first in an object, later on you decide not to use them, but instead of deleting them from the object, you just remove them from the layouts. Eventually the fields stay there, unused, not visible to end users in the layouts, but visible when building reports or list views. You forget those were there or if they were part of your feature or not, and that’s when you start the clutter. In addition, every time someone is building something new and they need to review what’s already in the org, they will have to go through dozens, even hundreds of fields, without being able to easily determine which ones are actually in use and that they should pay attention to.
Depending on what your introduction to Salesforce was, the clutter may have been there pretty much from the beginning. Maybe you started creating your features in production directly. This is why we always encourage everyone to create new features or test new settings in a sandbox, so that you have time to try and discard any unwanted changes before the final version is pushed to production. When you decide to go to production, you only send what’s really needed and used without dragging anything that is not part of your solution.
Another scenario relates to end user adoption. Sometimes a feature has a limited life, it serves its purpose for a while and then it’s no longer needed. Sometimes a feature becomes outdated, it no longer follows the business processes and if not updated, it becomes derelict and useless. Sometimes end users do not adopt a feature because the training or knowledge transfer to them was not complete, maybe they never heard of it or heard about it once and never actually saw it again.
The Plan
Overall here’s the plan we will follow:
- Review metadata.
- Evaluate usage.
- Backup metadata.
- Test and perform deletion.
Step 1: Identify The Metadata To Review
First and foremost, if you have packages installed from the Appexchange, make a list of them and review with your stakeholders if they are currently in use. These packages are the low-hanging fruit of your org. This usually tends to clear up a lot of the metadata left for you to review. When removing a package you may choose to also delete its objects and fields, or leave them to have a historical record of the stored data.
For the rest of your org you can follow the steps to “Make an Inventory” in our previous post. If you already know if something is in use, then you can skip it in that spreadsheet.
Step 2: Review With Stakeholders
Once you have the list of all metadata to review you may need assistance from stakeholders to determine which elements can be deprecated or deleted. This requires the expertise of users who are familiar with the system and know what they need available. This part could be quite extensive, which is why you want to have your spreadsheet available online, so that users can review this on their own and add their notes.
Declarative Metadata Review
There are different criteria you can apply to determine whether something is “in use” or not:
- Is it active? For example: validation rules, workflow rules, process builders and flows have a status. If they are inactive and they have been like that for a while, then likely they will not be used anymore.
- Is it referenced somewhere? For example: if a field is not included in any page layout, or code component or report, then likely it’s not in use.
- You can go to a field and press the “Where is this used?” button to get a list of all references of that field.
- Since this is something Salesforce only allows you to do on a field-by-field basis, you can look in Appexchange for apps that can do this for all fields of one object at a time (search for keywords “field reference”, “field usage”, “unused fields”).
- Does it have information? For example: if a field is blank for all the records ever created of that object, then likely it’s not in use.
- Has it been used in the last year? For example: if the last record of an object was created 3 years ago, then likely that object (and anything that uses that object) is no longer in use (even if there’s still a tab for it and there are reports created on it).
As a result of the user review you should get a spreadsheet with the usage and decision to keep or delete:
Development Metadata Review
Go through the development metadata in your org (Apex classes, Apex triggers, Visualforce pages, Visualforce components, Lightning Components, etc.) and make a list of all the items that you know are deprecated or not in use and that you want to delete. This is best done by an administrator or a developer who is familiar with the functionality of your org and knows how things are done in the backend. If there’s an item that you’re not sure, mark it for review with somebody else who may know their purpose.
For Visualforce Pages and Components you will see that there’s the “Label” and the “Name” fields. Make sure that the Name is the one you keep to later create the file to delete it. The Label is just to show the user when the page is viewed, but the Name is the unique identifier that can be used to perform a deletion on it.
Step 3: Backup! Backup! Backup!
When you are making changes that are not undoable (such as deletion) you have to be prepared beforehand in case you need a historical record of it or to rollback and restore it. So don’t forget to backup the data (if you are deleting objects, fields, etc) and metadata (structure of the objects, fields, workflow rules, flows, Apex classes, Apex triggers, etc.) you are going to delete if you may want to restore it later. You can download the data with reports, or data loader, or any data export tool which are generally available and Administrators are familiar with. For metadata you can use a tool such as Salesforce CLI to download it, which developers are more familiar with. But to keep it simple, here are 3 easy ways to backup your metadata when you are not a developer and you don’t want to install anything in your computer.
Download Metadata Directly From Org
For Apex classes and triggers the easiest way is to go to them in the Setup and press the “Download” button. A version of the file will download to your computer and you can store it safely.
In the case of Visualforce pages and components, they don’t have a “Download” option, so you can select all the content and paste it in a text file that you can save in your computer.
Lightning components do not have an easy way to be downloaded as they are a bundle of different files. Same with objects, fields, validation rules, they don’t have a downloadable version directly from the Setup. But see below the other options you have that apply to all metadata.
Download Metadata From A Change Set
Another easy way to backup your metadata is: in the source org (where the last version of the metadata exists) create an outbound change set, add the metadata you want to backup, upload the change set to any connected org (another sandbox or production). Once uploaded, you will see that the components you added to the change set will have a “View Source” link:
If you click that link you will have the same version of the metadata as when you download it with Salesforce CLI, which is how developers download and backup metadata. You can select the content (what you see in the “Source” section) of each “View Source” link in your change set and paste it in a text file that you can save in your computer:
This can be done to any type of metadata: declarative or development.
Designate a Sandbox as Metadata Backup
Since a sandbox copies everything from one org to another, you can designate one exclusively to be a backup of the current metadata before you delete the metadata from your source org. The only thing is that you have to make sure you don’t inadvertently delete or refresh this sandbox, which would overwrite the environment and everything you had backed up there. This is also a good solution, since if you want to restore the metadata you can create a change set from this sandbox to any connected org with the backup.
Step 4: Delete Metadata
Most metadata in the Setup has a Delete button. But sometimes in order to clean up an org you need to delete code metadata such as Apex Classes, Apex Triggers, Visualforce Pages, Visualforce Components and Lightning Components. There’s two different processes for deletion of code metadata.
Delete Visual Components
For Visualforce Pages and Components you can press the “Delete” button that appears directly on screen.
You will have to confirm the deletion and after confirmation the page or component will be completely removed from the org. This is an undoable action, there’s not recycle bin for metadata as there is for data.
If the page or component is not referenced anywhere then the deletion will work. Otherwise you will get a message such as:
You will have to remove the page or component from each place where it is referenced: the page layout, homepage layout, button, Lightning record page, etc. Then you can try the deletion again. This is something that can be cumbersome as one component can be referenced in multiple places and some of those dependencies can be circular, not allowing the elimination completely (in which case you will have to delete it the same way Apex Classes and Triggers are deleted explained further below).
For Lightning Components, you can press the “Developer Console” button and delete the component from there, but that will only delete the front-end (the visual part of the component), not the classes that implement the back-end (functionality part of the component).
In the Developer Console press the option File > Delete:
and confirm the deletion:
The validation of whether the Lightning Component is referenced anywhere else is also checked and you will get a message with the list of places where it is referenced and that it needs to be removed from before attempting to delete it.
In this case there’s no problem in either a sandbox or a production environment to delete visual components. But for Apex Classes and Triggers there’s no “Delete” button in production environments and a different process needs to be followed. Next we’ll see how to delete code metadata from a production environment.
Create a Destructive Change
This method is valid for anything in the org (objects, fields, layouts, flows, etc), any visual component as well as code components that cannot be deleted from the user interface of Salesforce. To specify which metadata must be deleted you need to create a zip file with 2 xml files in it:
- File “package.xml”: contains configuration for the deployment. You can generate the file with the content as specified below. No other changes needed.
- File “destructiveChanges.xml”: contains the list of metadata to delete. For every type of metadata (ApexClass, ApexPage, ApexTrigger, etc) you create a node named “type” with a subnode “name” with the metadata type and a “member” subnode with the API Name of each metadata to delete.
Each file must have the following content and structure and be saved with the exact name as below.
File “destructiveChanges.xml” following the format of the “types” nodes and with the exact “destructiveChanges.xml” file name:
The files created in the previous step need to be compressed in zip format and uploaded with Workbench to perform the deletion.
Tip to Create a Zip File in Mac
There’s a small issue in Macs: when they generate zip files, they add hidden files and folders with names such as “.DS_Store” and “__MACOSX”. If you decompress a zip file like this in Windows for example, you will see these files and folders you don’t see in Mac. Some tools that receive zip files as input do not accept zip files containing these additional files. When deploying Destructive Changes in Workbench to delete metadata you need to create a zip file with the xml files as is without the hidden Mac files or it will fail.
To create a zip file in Mac without these hidden files, use the zip command in a Terminal to zip the files without the “.DS_Store”, “__MACOSX” and other .* files:
Open a “New Terminal at Folder” in the folder your xml files are:
Paste this command: zip -r destructivechange.zip . -x ".*" -x "__MACOSX" and press Enter.
The zip file called “destructivechange.zip” you need for your Destructive Change is now created in the same folder without the hidden files.
Deploy the Destructive Change
Now we’re ready to deploy our Destructive Change and delete that metadata.
Go to the Workbench login page: https://workbench.developerforce.com/login.php
Select the environment, the most recent API version and check the agreement to the terms of service.
If you are already logged in your org Workbench will detect it and ask for permission to access it:
otherwise, Workbench will ask for Salesforce credentials to log into the org.
Go to Migration > Deploy:
Click “Choose File” and select the zip file with the Destructive Change:
Check “Rollback On Error” and “Single Package”. If there’s an error during deployment, then the org will stay in the same way it was when you started the deployment and no changes will be applied. You can check the “Check Only” option if you just want to validate you’ve built the Destructive Change correctly without actually doing the deletion at the end, just simulating to make sure you have everything needed.
Select Test Level “NoTestRun”. Since you are deleting it would not be necessary to execute any additional tests.
Click “Deploy” and the deployment will start. This will take a couple of minutes depending on how much metadata you are deleting.
Once the deployment finishes you will be able to see the success of the deletion:
In case the deployment fails due to coverage, because maybe you are deleting a test class that provides code coverage, repeat the process but in step 7, select “RunSpecifiedTests” and enter the name of a test class that will have coverage and not cause any issues such as “ChangePasswordController” or “ChangePasswordControllerTest” (whichever exists in your org by default). This is necessary for the deployment to complete correctly. Then the deployment should complete correctly.
Recommendations
Keeping your org healthy takes time, but it pays off (sometimes less is truly more). Here are our recommendations to keep up with your org maintenance:
- Don’t procrastinate, start as soon as possible. Any time you spend cleaning up your org is time saved in future development swifting through things that may no longer be used.
- Keep a log of all your features: who requested it, what is supposed to do, last time reviewed, anything that can give you an idea of its usage.
- Make it a recurrent task at least once a year to review the usage of each feature and consider retirement if no longer used or needed.
- Make regular backups of your metadata to have snapshots of your org configuration after deployment of new features or deletion of deprecated ones.
Make It Happen
Here are some interesting ideas you can vote for:
- Delete Apex Triggers & Classes w/out Force.com IDE
- Delete Apex Classes and Triggers from the GUI
- Easier way to delete apex class or trigger in production
- How to get the Deleted Apex class?
- Allow de-activation of Apex triggers in production
- Allow us to delete inactive/incorrect APEX triggers without using external tools
- Admin Ability to Activate Deactivate APEX triggers from UI
- Allow deactivate apex triggers in production directly. - Ideas
- Disable Trigger and Validation Rules while running dataloader operation
Resources
Here are some resources to learn more:
- Deleting Files from an Organization
- Deleting Components from an Organization
- Remove Apex Class or Trigger in Production Org to unblock Deployment
- Disable a Trigger in a production environment
- Understanding Metadata API
- Blog: Better Than You Found It
Lunch & Learn: Watch the Process
Take your learning to a new level with a live walk-through of this post and a demo of the destructive change process. You can register here to join live on August 25th, 2021 at 12:15pm EST or click-through to access the video of the recording after.
What do you think of this summary? Is there anything else that should be brought to attention when cleaning up orgs? Tell me all about it in the comments below, in the Salesforce Trailblazer Community, or tweet directly at me @mdigenioarkus. Subscribe to the Arkus Newsletter here to get the top posts of the Arkus blog directly to your inbox.