I'm building a Custom List Button in a Dev Environment, and I'd like it to work with no changes when deployed to Production even though all IDs will change.

The list button (which will be displayed in a related list) allows users to create a new related object, but specifies a specific Record Type, and pre-fills the new object with data from the current record.

It looks like this:

{!URLFOR( $Action.Contact.NewContact , null, [CF00NJ0000000QIX7=Contact.Id, RecordType="012J00000004NGB"])}

The problem is that this RecordType ID will change with deployment. I'll always know it's name, though. Is there any way to use that?

Update: Also, won't the custom field ID change also (CF00NJ0000000QIX7 above) -- what do I do about that?

  • Benj, 2 things: (1) yes, the custom field ID is different in every org (e.g. Prod, Test Sandbox, Dev Sandbox), and use of this 'Id' is NOT supported, but it should remain constant in a single org, so as long as you figure out what it is in every org you use, you could store it in a custom setting, as @Forceguru suggests. (2) It is always best practice to use RecordType.DeveloperName when possible, not the Id.
    – zachelrath
    Sep 28, 2012 at 17:10
  • Zach, that's helpful. Can I refer to RecordType.DeveloperName in custom links URLs like the above?
    – Benj
    Sep 28, 2012 at 17:14

5 Answers 5


You can use custom setting for this. Keep the record type Id in custom setting and use that in your button code, it will look something like this "{!$Setup.CustomSettingAPI_c.RecordTypeId_c}"

  • 1
    Hm. This would require a configuration change on deployment, but it can be documented easily. Thanks.
    – Benj
    Sep 25, 2012 at 4:23
  • Good solution Forceguru. The $RecordType global variable is not available in Custom button context, but the $Setting.<SettingName> variable is, so this would work great for your solution, and requires no Apex code.
    – zachelrath
    Sep 25, 2012 at 12:24
  • There are many other options, but this is the shortest and sweetest.
    – Forceguru
    Sep 28, 2012 at 22:50

As an aide once you deploy to Production and refresh your sandboxes from Prod, record type ids and for that matter all ids (metadata) will be in sync (I.e. same ) across environments

  • Do you know where SF has that documented (link)? I agree with you, but just wonder where SF has it documented. Sep 29, 2012 at 0:59
  • Just know from practical experience. Don't think I've seen it in documentation. Sep 29, 2012 at 1:05

Great question!

For the sake of anyone who's doing this in Visualforce (which, Benj, I recognize you're not), here's what I would do: get a reference to the record type Id in Apex using a method similar to this: (note that I am returning a Map keyed by RecordType DeveloperName, NOT Name, because Name can always be changed/overridden in Production org, whereas DeveloperName does not change. This is an especially important best practice when developing managed packages.

// Returns a map of active, user-available RecordType IDs for a given SObjectType,
// keyed by each RecordType's unique, unchanging DeveloperName 
global static Map<String, Id> GetRecordTypeIdsByDeveloperName(
    Schema.SObjectType token
) {
    // Build a map of RecordTypeIds keyed by DeveloperName
    Map<String, Id> mapRecordTypes = new Map<String, Id>();

    // Get the Describe Result
    Schema.DescribeSObjectResult obj = token.getDescribe();

    // Obtain ALL Active Record Types for the given SObjectType token
    // (We will filter out the Record Types that are unavailable
    // to the Running User using Schema information)
    String soql = 
        'SELECT Id, Name, DeveloperName '
        + 'FROM RecordType '
        + 'WHERE SObjectType = \'' + String.escapeSingleQuotes(obj.getName()) + '\' '
        + 'AND IsActive = TRUE';
    List<SObject> results;
    try {
        results = Database.query(soql);
    } catch (Exception ex) {
        results = new List<SObject>();

    // Obtain the RecordTypeInfos for this SObjectType token
    Map<Id,Schema.RecordTypeInfo> recordTypeInfos = obj.getRecordTypeInfosByID();

    // Loop through all of the Record Types we found,
    //      and weed out those that are unavailable to the Running User
    for (SObject rt : results) {  
        if (recordTypeInfos.get(rt.Id).isAvailable()) {
            // This RecordType IS available to the running user,
            //      so add it to our map of RecordTypeIds by DeveloperName

    return mapRecordTypes;

TO use this to accomplish your need, you could do something like the following:

public class MyController() {

    public transient Id myRecordType {
         public get {
              if (myRecordType == null) {
                 myRecordType = GetRecordTypeIdsByDeveloperName(
              return myRecordType;  
         } private set;

 // Visualforce Page with Link to create a new record of this type
       <apex:commandLink value='{!URLFOR( $Action.Contact.NewContact , null, [CF00NJ0000000QIX7=Contact.Id, RecordType=myRecordType])}'/> 

Yes. You can query the RecordType object in your controller and then reference that property in your VF page.

Here's an example using the Account object:

Id recTypeId = [
     Select Id 
     From RecordType 
     Where SObjectType ='Account' 
       And Name = 'Your Record Type Name' Limit 1
  • This isn't actually a VF page - it's a custom list button (on a related list). But useful nonetheless!
    – Benj
    Sep 25, 2012 at 4:22
  • Gah! Sorry about that. Sep 25, 2012 at 10:46
  • 3
    This is a good way to go, however you should also check to make sure the RecordType is Active and available to the running user. Also, it is best practice to query against the DeveloperName / API Name of a RecordType, as this will never change, whereas the Name of a RecordType can be overridden or translated in target/Production orgs.
    – zachelrath
    Sep 25, 2012 at 12:04

You can also do this with an on-click java script and to call an apex web-service to return the recordtype ID. Use the returned record type ID string to create your new contact.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .