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
    Commented Jan 13, 2017 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
    Commented Jan 13, 2017 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
    Commented Jan 13, 2017 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
    Commented Jan 13, 2017 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
    Commented Jan 13, 2017 at 14:22

1 Answer 1


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';

  • Very helpful example. Thanks for sharing!
    – mchandler
    Commented Jan 21, 2023 at 23:19

You must log in to answer this question.

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