Upsert Flows

There is a software development concept called “don’t repeat yourself” (DRY) which every admin and developer should practice. Declarative adminiss are able to apply this more and more with each Salesforce release! I have a set of subflows that I’ve had for a very long time. I call them my “upsert flows.” Upsert is a database operation where are you *up*date or in*sert* a new record. I have been using my upsert flow​​s for at least six years. I can’t imagine the countless hours they have saved. And they’ve improved our UX consistency and data integrity, too. Let’s learn how…

The basic concept is you have a subflow (a flow called by something else like flow, process builder or APEX but can also be a Lightning component or button) which is capable of updating the information that you care about in your organization about a contact. Not every org uses every field, but we all have fields which should be relevant and some which should be required. The upsert flow begins by receiving a recordId (this is a safe standard Salesforce name required by a few Lightning components). The flow retrieves the record and displays the information that you typically care about, allows the user to update that information (including flow validation rules, flow conditionally display fields, flow help, and flow conditionally display text if you like), saves it, and returns you the record ID. By itself, this might not be amazing, but it is very useful as D.R.Y. I have many flows that we offer or require the user to update information as part of a regular process. In fact, if you implement this with the modern recordField Flow Screen Component (FSC) found at, it’s literally a single element. This FSC leverages the same APEX developers have been using for years to get a good and consistent UI fast. My flow screen has literally one component on it in which I called out the fields I wanted. No hard design at all. But the upsert flow gets better…

If you start the flow with an RecordId equal to CREATE (or blank), the flow does not bother searching the database but rather prompts for information (using the same screen to be DRY) and creates a new ID and returns that ID. In fact, if you use recordField FSC, all you have to do is actually set the recordId to “empty” and it will create a new record. So now you have a “twofer.” Whether you want to create a new contact *or* edit the current contact already in your database, you have one flow. Cool! But it still gets better…

If you start the flow with recordId equal to SEARCH, you can pass in or be prompted for a search string. Perhaps you are looking for George and just want to make sure you don’t duplicate before you add. Type Geo and you are then shown all contacts that match that search string for selection along with the possibility of creating a *new* contact. So now you have one flow that can allow a user to choose from everyone named George or create a new George. So you have “search before create” built into this flow for greatly increased data integrity. It’s one flow no matter whether you’re creating a new contact, finding an existing contact for selection, or updating an existing contact with new data. And I chose to use DataTable from and I had to code very little. My whole table is literally one screen component and I get to pick the fields that are shown to allow the user to make the selection. Admittedly, the flow now has about 8 items that are checking and assigning the MASK and recordId so everything works in all the input combinations, but it’s very simple (ha ha… I know). But wait… There’s still more!

You can do a quality check inside the flow! I created an edit mode flag that is passed in. If set, it words as described above. But if you turn it off, the record is checked and you are only prompted with an update screen for an existing contact if certain fields which your organization defines as critical are missing or have values that are insufficient. The record check is placed in a formula that works like a validation rule. If the validation formula evaluates to FALSE, the flow says nothing and just returns the recordId. If true, something is missing or wrong and the record pops up on the screen for review. For example, we have Gender, Ethnicity, City, State, and email defined as critical so when working with a contact missing one of those, it always shows the update screen. You can also add red advisory messages above fields based on the validation formula. The user doesn’t have to fill them in but gets a chance to do so. This improves database integrity with a little user training. 

So we have a single reusable sub-flow that can create a new contact, search and select a contact, update a contact, scan a contact for missing critical data and allow the user to add missing info (or not). This is very useful. And not too terribly complex. At the core are two complex screens provided by unofficialSF and some decision and simple assignment.

More than this, we have a single place to go update our flow UI when we decide to start tracking a new field on all contacts. And a single place to update when you want to start scanning your database for contacts with new missing or invalid information. For example, we didn’t require City and State on all contacts until we started operating in multiple regions. Tracking it on all our contact, was as simple as adding it to our upsert. We allow creating contacts without gender and ethnicity but we want to fill these in over time. So doing this just required scanning all contacts in our upsert flow for missing gender or Gender set to “not specified”. If you’ve ever wanted to notify someone of a dangerous person or a VIP, this might also be a great place to do it.

Some practicalities… I did this seven years ago so I had to do all sorts of ugly things. I wrote the flow that I’m showing with modern techniques and best practices (I hope). 

We weren’t able to settle on one set of fields for every contact. But we were able to settle on one set of fields for clients, volunteers, donors, and “supporters”. We made separate flows (upsert_client, and upsert_contact, and upsert_contact_simplified to cover all our cases.) That’s not very DRY, so today I would consider making yet another input parameter called TYPE. But there is a balance to complexity, even with DRY.

Since this screen may show up just about anywhere for your user where you are using upsert flows, you should make things nicer for your user by passing in a top line and bottom line that can provdie context and advice. This is simply two input parameters which you simply display at the top and bottom of every screen. That’s how I generated the comment test in my screenshots.

Once you have mastered this upsert, you may find that you want one for a donation, a payment, an affiliation, a relationship, a campaign, a campaign membership, a volunteer hour. I have almost all of these.  You can see form the dates that some get modified and some hardly ever.

Frankly speaking, I’m of the opinion that these upsert flows should *come with Salesforce core, NPSP, PMM, and V4SF* so an admin can use them out of the box. They should be templates so you can copy and customize them. Feel free to make an idea and vote it up!

Leave a Reply

Your email address will not be published. Required fields are marked *