I have queries pulling all of the information correctly but what I can't seem to find was a way to add new options to a picklist using APEX.

I currently have

Package__c.Products__c.add(new Schema.PicklistEntry(products[j].Name));

Package__c is my custom object, and Products__c is the picklist. products[j] is pulling a list of products pulled from our products page.

And I've tried adding it as a select option, or even casting the variable type.

And this information has to go to the actual picklist within a custom object, and not within a visual force page or anything like that.

  • 2
    That is an administrative capability that I would strongly recommend against exposing to your end users. Can you go into more detail about your use case?
    – Adrian Larson
    Feb 9, 2015 at 20:44
  • Well currently I need a dynamic picklist that pulls in the entire listing of our products to a custom object to build packages with deal based incentives. That way we can select a few products and save it to a package, and then check these packages against the products in an opportunity. Feb 10, 2015 at 15:01
  • Are you sure you need a picklist? Why not use a lookup to Product then?
    – Adrian Larson
    Feb 10, 2015 at 15:05
  • Are there multi-lookups? The person using this needs to be able to select multiple items. Feb 10, 2015 at 15:35

4 Answers 4


The way to do this is using the Apex MetaData API wrapper as provided by esteemed SFSE colleague Andrew Fawcett here

  1. Running user needs to have Customize Application privilege so you really want this to be an admin type user
  2. Read the examples in the GIT package carefully - there is one for picklists. You need to read the CustomField from the MetaData API first then update, otherwise you'll smash all the existing picklist entries.

The relevant example in the package's MetadataServiceExamples.cls file is here:

public static void updatePicklist()
    MetadataService.MetadataPort service = createService();             

    // Read Custom Field
    MetadataService.CustomField customField = 
        (MetadataService.CustomField) service.readMetadata('CustomField', 
            new String[] { 'Lead.picklist__c' }).getRecords()[0];       

    // Add pick list values
    metadataservice.PicklistValue two = new metadataservice.PicklistValue();
    two.fullName= 'second';
    metadataservice.PicklistValue three = new metadataservice.PicklistValue();
    three.fullName= 'third';

    // Update Custom Field
            new MetadataService.Metadata[] { customField })[0]);        
  • 1
    This is very useful but the associated knowledge needed is outside of my scope. Thank you though! Feb 10, 2015 at 17:43
  • Okay so I looked into it deeper and decided to have a go at it. The example shows creating a new picklist and updating the created picklist, but what about updating an existing picklist? Feb 12, 2015 at 16:23
  • @CodyBeaner - I added the code sample from the examples class
    – cropredy
    Feb 12, 2015 at 17:04
  • I've used the code to completely make a new field and it doesn't even show. Is there a comprehensive tutorial for this? Feb 13, 2015 at 15:51
  • @CodyBeaner - Hmm -- the Apex wrapper to the metadata API is basically a wrapper on how a REST or SOAP client would use the API. As such, the SFDC doc developer.salesforce.com/docs/atlas.en-us.api_meta.meta/… was the most helpful to me along with the aformentioned examples class. The doc explains the datastructure
    – cropredy
    Feb 13, 2015 at 20:08

@cropredy answer is correct. But there are some changes in MetadataService class. So code given in above answer will not work. Below code will work with latest version of mdapi GitHub repo.

MetadataService.MetadataPort service = createService(); 

MetadataService.CustomField picklistField =(List<MetadataService.CustomField>) service.readMetadata('CustomField', 'Lead.picklist__c').getRecords();
metadataservice.CustomValue two = new metadataservice.CustomValue();
two.fullName= 'second';


MetadataService.SaveResult result = service.updateMetadata( new MetadataService.Metadata[] { picklistField })[0];

In place of PicklistValue we have to use ValueSet. Also we need to make little change in MetadataService Class. We have to replace ValueSet virtual class in Metadatservice with

public class ValueSet {
        public String controllingField;
        public Boolean restricted;
        public MetadataService.ValueSetValuesDefinition valueSetDefinition;
        public String valueSetName;
        public MetadataService.ValueSettings[] valueSettings;
        private String[] controllingField_type_info = new String[]{'controllingField',SOAP_M_URI,null,'0','1','false'};
        private String[] restricted_type_info = new String[]{'restricted',SOAP_M_URI,null,'0','1','false'};
        private String[] valueSetDefinition_type_info = new String[]{'valueSetDefinition',SOAP_M_URI,null,'0','1','false'};
        private String[] valueSetName_type_info = new String[]{'valueSetName',SOAP_M_URI,null,'0','1','false'};
        private String[] valueSettings_type_info = new String[]{'valueSettings',SOAP_M_URI,null,'0','-1','false'};
        private String[] apex_schema_type_info = new String[]{SOAP_M_URI,'true','false'};
        private String[] field_order_type_info = new String[]{'controllingField','restricted','valueSetDefinition','valueSetName','valueSettings'};

Also Check URL in your metadataPort.endpoint_x. It should be

public String endpoint_x = URL.getSalesforceBaseUrl().toExternalForm() + '/services/Soap/m/42.0';

The above given solutions works perfectly using Apex Metadata Service (https://andyinthecloud.com/2013/10/27/introduction-to-calling-the-metadata-api-from-apex/); but it requires to import all code for even a small requirement. After, release of Tooling API, I find it lifesaver for such implementation without importing and managing too much code. We just need to make a callout using Tooling API.

Full detail article is here: https://sfdcian.com/update-picklist-value-and-add-it-in-record-type-using-apex-salesforce/

Body: <as given at below URL>

Here is JSON Body that has to be sent as request body in this callout: https://github.com/ayub-ansari/Create-Picklist-Field-Using-Apex/blob/master/FirstHTTPRequestToUpdatePicklistField


Based on your comments, what you really want is a Junction object to Create a Many-To-Many Relationship between Product and your Package Deal object. I might call it something like Package Deal Line Item.

  • This seems like it might be exactly what I need, thanks! Feb 10, 2015 at 16:26
  • Haha it was tough to figure out what you really needed. Gotta ask the right questions! :)
    – Adrian Larson
    Feb 10, 2015 at 16:28
  • So for some reason I cannot add a Master relationship to my products? Ideas? Feb 10, 2015 at 17:31
  • You can't make Product master? Well, a junction can still enable many-to-many with a lookup instead. The pairing is not as rigid, but I think it will suit your needs.
    – Adrian Larson
    Feb 10, 2015 at 17:32
  • This does't really seem to be what I'm looking for... Is there a way to put the product layout in my custom object the same way it's in opportunity? Feb 10, 2015 at 17:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.