Is Hardcoding Ids a Good Idea in Salesforce Flows?

Every Salesforce admin and developer has been tempted by the quick fix. You are building a Flow, and you need it to route an automated email to a specific queue, assign a task to a generic system user, or refer to a specific Record Type.

SurveyVista: Effortless Data Collection to Action

You open the record in your browser, copy the 15- or 18-character string from the URL (0058W00000Gxxxx), paste it directly into a Flow text variable, and click Save. It works perfectly in your sandbox. You deploy it. Everything seems fine.

There are many situations this approach fails, though.

Hardcoding Ids is one of the most common anti-patterns in Salesforce development. While it feels harmless in the moment, it creates fragile automation that is prone to catastrophic failure during deployments. Let’s break down exactly why this happens, how Salesforce handles Ids across environments, and the best-practice alternatives you should use instead.

The Root of the Problem: Data vs. Metadata

To understand why hardcoding fails, we have to look at how Salesforce separates Metadata (the structural bones of your org such as Flow definitions, custom fields, and page layouts) from Data (the actual records living inside those structures, like Accounts, Contacts, Users, and Queues).

When you deploy a Flow using a Change Set, DevOps Center, or a CLI tool, you are deploying metadata.

Free Mentorship With Talent Stacker

If your Flow contains a hardcoded Id pointing to a specific User or Queue record, you are embedding a data reference directly inside your metadata. The deployment tools will happily move your Flow structure to the target environment. But if that exact target environment doesn’t contain a record with that identical 18-character Id string, your Flow will throw an unhandled fault the second it runs.

Sandbox Creation: When Do Ids Match?

A common point of confusion is how Ids behave when you spin up or refresh a sandbox from your Production environment. Do the Ids copy over? Are they the same?

The answer depends entirely on whether you are looking at data or metadata, and what type of sandbox you are creating.

Metadata Ids (Record Types, Queues, Roles, Profiles)

When you create any sandbox from Production (Developer, Developer Pro, Partial Copy, or Full), Salesforce replicates your metadata layout.

Record Type Ids and DeveloperName values will match between Production and the newly created sandbox because Record Types are metadata.

Queue and Public Group Ids will also match initially because their structural definitions are pulled directly from Production.

Data Ids (Users, Accounts, Custom Object Records)

This is where things diverge significantly:

  • Full Sandboxes: A Full Sandbox copies all metadata and all data records from Production. Consequently, the record Ids for your Accounts, Contacts, and Users will match Production exactly upon creation.
  • Partial Copy Sandboxes: These copy a sample of your data based on a sandbox template. The records that are copied will retain their original Production Ids.
  • Developer and Developer Pro Sandboxes: These environments copy zero data records from Production (except for standard Setup data like Users). If you create a brand-new Account record in a Developer Sandbox to test your Flow, it will generate a brand-new, completely unique ID that has absolutely no relationship to Production.

The Danger Zone: Disconnected Environments and Scratch Orgs

Even if you use a Full Sandbox where data Ids match Production perfectly, relying on hardcoded Ids is still a ticking time bomb. The risk skyrockets when your deployment pipeline introduces disconnected environments or scratch orgs.

If your team utilizes modern DevOps strategies such as Salesforce DX and Scratch Orgs, your environments are spun up completely from source code repository configurations.

A scratch org has absolutely no data relationship to your Production environment. When a scratch org is built, it is a completely blank canvas.

If your Flow expects a hardcoded User Id like 0058W00000Gxxxx to exist, it will instantly fail in the scratch org because that User simply does not exist. The same issue occurs if you have to manually recreate test records in a clean Developer sandbox; the text strings will never align across the pipeline.

Furthermore, if a record is accidentally deleted in Production and recreated by an admin, it receives a brand-new Id. Your hardcoded Flow will instantly break, requiring an emergency deployment just to update a text string.

Best Practices: How to Avoid Hardcoding Ids

How do you build robust, environment-agnostic Flows that seamlessly transition from a scratch org to a sandbox, and ultimately to Production? Use these three reliable alternatives:

Use the Get Records Element (The Gold Standard)

Instead of hardcoding a Record Type Id or a Queue Id, use a Get Records element at the beginning of your Flow to query the system dynamically using a unique developer name.

Instead of: Filtering a record variable by RecordTypeId Equals 0128W000001xxxx

Do this: Add a Get Records element looking at the Record Type object where SubjectType Equals 'Account' and DeveloperName Equals 'Corporate_Account'. Then, reference the Id dynamically from that query step.

Developer names are metadata; they remain identical across all environments, making your query 100% safe during deployment.

Leverage Custom Labels or Custom Metadata Types

If you must reference a specific system user or external integration Id that cannot be queried easily via a developer name, store that Id outside of the Flow.

Create a Custom Metadata Type or a Custom Label (e.g., Default_Task_Assignee_ID).

Populate the label with the sandbox-specific Id in your sandbox, and reference that label inside your Flow using global variables: {!$Label.Default_Task_Assignee_Id}.

When you deploy the Flow, the metadata structure moves safely. You can then update the text value inside the Custom Label in Production manually or via deployment scripts without touching the core Flow logic.

Custom Settings can also be used for this purpose depending on your use case.

Use Global Variables for Profiles and Roles

If your Flow needs to validate a user’s Profile or Role, avoid hardcoding the Profile Id. Salesforce provides global system variables that let you look at the running user’s contextual information directly:

  • {!$Profile.Name} (e.g., Equals System Administrator)
  • {!$UserRole.Name} (e.g., VP of Global Sales)

Using names rather than hardcoded alphanumeric Ids ensures your logic remains readable, maintainable, and completely deployable.

A Quick Tip on Roles: Just like hardcoding IDs, checking {!$UserRole.Name} directly in Flow logic can be risky if someone renames the Role in Setup. Where possible, checking Custom Permissions using {!$Permission.Your_Custom_Permission} is an even safer, more maintainable alternative!

Read our post on custom permissions HERE.

Stop Hardcoding Ids: Build Deployment-Safe Flows Instead

Is hardcoding Ids ever a good idea? No. Never.

While it might save you two minutes during initial development, it passes an invisible technical debt down the line to your future self or your deployment team. By taking the extra moment to implement a dynamic query or reference a Custom Metadata Type, you ensure your Screen and Record-Triggered Flows remain unbreakable, no matter how complex your sandbox ecosystem or deployment pipeline becomes.

Explore related content:

Should You Use Roll Back Records in Salesforce Screen Flows?

Unanimous Flow Approvals – No More Workarounds

Open a Page Action: Redirect Users After a Screen Flow

Andy Engin Utkan

Andy Engin Utkan is a Salesforce MVP with 24 certifications. He is the founder of Salesforce Consulting Partner BRDPro Consulting. Utkan is a consultant, trainer, and content creator, focusing on automating business processes using Salesforce flow. He is recognized for his expertise in Salesforce flow, providing guidance through various courses and contributing actively to the Salesforce community.

Leave a Reply

Back to top button

Discover more from Salesforce Break

Subscribe now to keep reading and get access to the full archive.

Continue reading