I have a requirement to create triggers dynamically after a managed package is installed. I have read that the tooling API can be used to create triggers dynamically however it cannot be used in production. Is it possible to create triggers from a managed package in an org? I want to be able to create the trigger based on some user inputs.

  • 4
    Why do you think you can't use the Tooling API in production? – Adrian Larson Jan 13 '17 at 14:17
  • can't you add your triggers to managed package? Or write triggers in a sandbox with this package installed and then deploy them to prod? – Novarg Jan 13 '17 at 14:19
  • Why do you need to create a new trigger? Can't you have a trigger as part of the package and let the user inputs be saved as custom settings? – martin Jan 13 '17 at 14:19
  • @martin it is not always true that trigger should be on the object, which is part of managed package. gerad26 -- you can use tooling api, as Adrian Larson said – kurunve Jan 13 '17 at 14:22
  • 7
    DLRS does this on a configuration page (visualforce). It's open source, so you can take a peek under the hood. – sfdcfox Jan 13 '17 at 14:22

Yes, it's possible via the SOAP API (in Enterprise production systems the Tooling API will indeed not work. It does in Dev Hub orgs and dev orgs, which makes things pretty confusing). You'll need a zip library to zip up the triggers, then create a package.xml file with ApexTrigger and (assuming you have test classes for your triggers) ApexClass Sections.

Due to the requirement to zip the files, we do that part in Javascript, using jszip, adding "files" (the strings making up the triggers and classes) with code like this:


To actually deploy the file, we are not using Javascript but rather the MetadataAPI surfaced by the Metadataservice class, generated from the SOAP API with wsdl2apex using this code:

    /* create triggers and classes with zipped metadata */
public static String createNewMetadata(String zipData,List<String> allTestClasses) {
     // Deploy zip file           
    MetadataService.MetadataPort service = MetadataService.createService();
    MetadataService.DeployOptions deployOptions = new MetadataService.DeployOptions();
    deployOptions.allowMissingFiles = false;
    deployOptions.autoUpdatePackage = false;
    deployOptions.checkOnly = false;
    deployOptions.ignoreWarnings = false;
    deployOptions.performRetrieve = false;
    deployOptions.purgeOnDelete = false;
    deployOptions.rollbackOnError = true;
    deployOptions.testLevel = 'RunSpecifiedTests';
    deployOptions.runTests = allTestClasses;
    deployOptions.singlePackage = true;

    // if its not test code deploy, otherwise return a fake ID
    if (!Test.isRunningTest())  {
        MetadataService.AsyncResult asyncResult = service.deploy(zipData,deployOptions);  
        return asyncResult.id;
    else {
        return '123';


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.