A Salesforce push upgrade moves a customer org to a newer version of your managed package without the customer installing anything. Customized push upgrades are the opposite control. They let you give one specific customer org the right to block your push upgrades for one package, optionally for a set number of days, while that customer still installs new versions manually when they choose.
For a SaaS company with a managed package on AppExchange, both matter for the same reason. Every customer org you leave on an old version is a version you keep supporting, and every enterprise customer with a strict change process will eventually ask you not to touch their org. Appnigma builds and maintains marketplace apps for B2B SaaS teams, "a Salesforce managed package or HubSpot app built around your product," so release and upgrade planning is part of the work we do every week.
Updated October 2026. Checked against the First- and Second-Generation Managed Packaging Developer Guides and the Object Reference. The earlier version described the expiration days as a window after which Salesforce stops retrying a push, and said customers can never decline a push upgrade. Salesforce's docs say the expiration days control how long a customer is allowed to block pushes, and that blocking is exactly what the feature is for. This update corrects both and adds the rollout and tracking steps a partner actually runs.
What a push upgrade does to a customer org
Salesforce's guide is direct about the trade. "A package subscriber doesn't need to do anything to receive the push upgrade," and "the developer initiating the push resolves upgrades that fail" (Push Package Upgrades to Subscribers). The same guide warns that "you're making changes to a subscriber's org without explicit consent" (Push Upgrades).
Three conditions come before the first push. The package must have passed AppExchange security review, push upgrades must be switched on by a case with Salesforce Partner Support, and the user scheduling the push needs Upload AppExchange Packages for 1GP or Create and Update Second-Generation Packages for 2GP (PackagePushRequest). How you schedule depends on the package type.
| Package type | Push from the UI | Push with Salesforce CLI | Push with SOAP API |
|---|---|---|---|
| First-generation managed (1GP) | Yes | No | Yes |
| Second-generation managed (2GP) | No | Yes | Yes |
| Unlocked | No | Yes | Yes |
Source for the table is Push a Package Upgrade for Second-Generation Managed Packages. For a 2GP package the whole job runs from the Dev Hub that owns it.
sf package push-upgrade schedule --package 04txyz --org-file upgrade-orgs.csv
sf package push-upgrade list --package 033xyz --status Failed
sf package push-upgrade report --push-request-id 0DVxyz --target-dev-hub myDevHubThe org file holds one org ID per line, and a start time you pass is read as UTC (Schedule a Push Upgrade Using CLI). Each org in a push gets its own PackagePushJob, and its status ends as Succeeded, Failed or Canceled (PackagePushJob). Nothing in the docs describes Salesforce retrying a failed job on its own. Failed is a final status. The reason lands in a PackagePushError record, with types such as ApexTestFailure, DeployError and LockingFailure (PackagePushError), and the org stays on its old version until you fix the cause and push again. Abort works only while a request is still Created or Pending.
Can a customer block push upgrades of your managed package?
Yes, if you enable it for that customer's org. Salesforce calls this customized push upgrades. "Customized push upgrades let Salesforce Partners give customers the ability to restrict push upgrades to a specific customer org for a specific package" (Enable a Package Subscriber to Restrict Push Upgrades). It takes a step from you and then a step from the customer.
You go first. Log in to your 1GP packaging org, or the Dev Hub for a 2GP package, open Execute Anonymous in the Developer Console, and create a record for the package ID (starts with 033) and the customer's org ID (starts with 00D).
String pucId1 = PushUpgradeCustomizationRepository.create('packageID', 'subscriberOrgID', true, 90);
System.debug('pucId1 =' + pucId1);The fourth argument is optional. Leave it off and the customer can block with no end date. Pass 90 and the right to block expires after 90 days. The same class has the calls you need afterwards.
| Call on PushUpgradeCustomizationRepository | What it does |
|---|---|
| create(packageId, subscriberOrgId, true) | Lets that org block pushes of that package, with no end date |
| create(packageId, subscriberOrgId, true, days) | Same, but the right to block expires after the given days |
| setExpirationDaysForIndex(packageId, subscriberOrgId, days) | Changes the days for a package and org pair |
| setExpirationDaysForId(recordId, days) | Changes the days for one PushUpgradeCustomization record |
Then tell the customer it is switched on. Their admin opens Setup, goes to Installed Packages, selects your package and clicks Block Push Upgrades. From then on, "package upgrades can only be installed manually," and the admin can click Allow Push Upgrades at any time to undo it (same source).
The record behind this is the PushUpgradeCustomization object, available since API version 60.0 (Spring '24). The optional expiration days, and the methods that change them, first appear in the Summer '26 version of the packaging guides. Aquiva's Summer '26 release roundup reads the addition the same way, as a way to keep one-time customer accommodations from becoming permanent. Its ExpirationDays field is "the number of days that a subscriber is allowed to block push upgrades," and a value of -1 sets the block to never expire (PushUpgradeCustomization). Two other fields tell you what happened. HasRestrictionEnabled shows whether the customer actually blocked, and IsRestrictionOverridden shows whether Salesforce Customer Support overrode the block for that org.
Does the expiration window stop Salesforce retrying a push?
No. The expiration days on a customized push upgrade have nothing to do with how long a push upgrade keeps running, which is the mistake our own earlier version of this page made. They cap how long one customer org is allowed to keep your push upgrades out. When the days run out, the customer's right to block ends, and your scheduled pushes can reach that org again.
The difference changes how you use it. Read the wrong way, you would set a short window on a hotfix to stop a push from lingering. Read the right way, you set a window when an enterprise customer asks for a change freeze, so the freeze ends on its own instead of quietly lasting for years while that org falls further behind your current version.
Choosing the expiration days for a customer who asks to block
One rule in the docs decides the strategy. "If the customer has blocked push upgrades from the subscriber org, it's not possible to decrease the number of expiration days" (Enable a Package Subscriber to Restrict Push Upgrades). You can raise the number later with setExpirationDaysForIndex or setExpirationDaysForId. You cannot pull it back once the block is on.
So start short. Match the first window to the reason the customer gave, such as a quarter-end close or an audit, and extend it if they ask again. A block created with no days, or with -1, never ends unless the customer clicks Allow Push Upgrades, which means that org drifts from your release train for as long as nobody remembers it exists.
Four more limits in the same guide affect planning. Patch versions can't be blocked, so a customer on a patch must upgrade to a non-patch version before they can freeze, and you should check the installed version before promising one. Sandboxes follow production, getting the ability to block automatically when the parent production org has it. Each production org is its own record, so a customer with three production orgs needs three create calls. A 2GP ownership transfer to another Dev Hub keeps neither the records nor the permissions, and you repeat both steps for every customer.
Rolling out a push upgrade across hundreds of customer orgs
Salesforce's own best practices read like a release plan. Push to your own test orgs first, then to customer sandboxes, and give customers "a week or more to test" before production. Production starts in small batches. The page's own example is a base of 1,000 customers pushed "50 or 100 customers at a time" for the first few rounds (Push Upgrade Best Practices). The same page suggests waiting 3 to 4 weeks after a major Salesforce release before pushing a major upgrade, and avoiding customers' month-end, quarter-end and year-end.
The arithmetic from those numbers is worth doing before you promise a date. At 50 orgs per wave, 1,000 customers is 20 production waves. At 100 per wave it is 10. Add a sandbox round with a week of testing and a major upgrade is several weeks of work, not an afternoon. Patches move faster because, as the 1GP guide notes, subscribers aren't notified of push upgrades beyond a change in version number, which is also why visible changes don't belong in a patch (Push Upgrades).
Before each wave, take the blocked orgs out of your list. Query PackageSubscriber from the Dev Hub or packaging org and filter on HasRestrictionEnabled, which "indicates whether the subscriber org has blocked push upgrades" (PackageSubscriber). For 1GP pushes from the UI there is also a Push Upgrade Exclusion List that takes up to 500 comma-separated org IDs (Push Package Upgrades to Subscribers).
One more thing changes what customers see. "By default, any new components included in the push upgrade package version are assigned only to admins" (Assign Access to New and Changed Features). Salesforce recommends a post install script that assigns access for enhancements to features users already have, and no automatic access for brand new features, so each customer's admin decides when to roll those out. If that script fails, the upgrade is aborted for that org.
Mistakes partners make with push upgrades and blocks
- Granting a block with no expiration. It is the easiest call to write and the hardest to unwind, because you can't shorten it later.
- Promising a freeze to a customer on a patch version. They can't block until they're on a non-patch version.
- Pushing without checking HasRestrictionEnabled. Your wave plan and your customer's change freeze should agree before the push is scheduled.
- Treating a Failed job as something that heals itself. Pull the errors with the report command and push again once the cause is fixed.
- Shipping a visible change in a patch. Customers only see a new version number, so a changed screen arrives without warning.
Where Appnigma fits
Salesforce push upgrades and customer blocks are release operations, and they sit on top of a managed package that someone has to keep building, versioning and shipping. Our marketplace apps work ends with a launch step that tells you to "Agree on upgrades and ongoing support" before customers install. The same page says ongoing fixes and upgrades "can be covered by a separate maintenance retainer." On done-for-you work, fixes are submitted as pull requests for your review, and "support and release responsibilities are agreed upfront." The push upgrade decisions stay yours. Which customers get a block, how long it lasts and when each wave goes out are product and customer calls, and the release plan is built around them.
Frequently Asked Questions
What happens when the expiration days run out?
The customer's right to block ends. Nothing about the push itself changes, and the customer can still install newer versions manually at any time.
What does ExpirationDays mean on PushUpgradeCustomization?
It is the number of days the customer org is allowed to block push upgrades. A value of -1 means the block never expires, and the days can't be lowered once the customer has blocked.
Do push upgrades work for 2GP managed packages?
Yes. Schedule them with sf package push-upgrade schedule or the SOAP API from the owning Dev Hub, after the package passes security review and Partner Support enables pushes.
Does Salesforce retry a failed push upgrade?
The docs don't describe automatic retries. A failed org shows a Failed job, you read the error, and you push again after fixing the cause.
Can Appnigma manage push upgrades for our managed package?
Upgrades and ongoing support for a managed package we build are agreed upfront, often under a maintenance retainer. Which customers get blocks and when to push stays your decision.
About the author
Sunny Chauhan is the co-founder and CEO of Appnigma AI, which builds and maintains customer integrations and native Salesforce and HubSpot apps for B2B SaaS teams. Before Appnigma, he was on Salesforce's AppExchange team, where he worked with more than 300 SaaS partners. He has spent close to a decade on the Salesforce platform, including work at Zennify, and holds Salesforce certifications including Platform Developer II, Platform App Builder, Administrator, Data Cloud Consultant, and AI Associate.
Related Articles
- What is a managed package in Salesforce
- Salesforce managed package guide
- 1GP to 2GP managed package migration
- Salesforce security review for managed packages
Sources
- Salesforce Developers, Enable a Package Subscriber to Restrict Push Upgrades (2GP guide)
- Salesforce Developers, Enable a Package Subscriber to Restrict Push Upgrades (1GP guide)
- Salesforce Developers, Object Reference, PushUpgradeCustomization
- Salesforce Developers, Push a Package Upgrade for Second-Generation Managed Packages
- Salesforce Developers, Schedule a Push Upgrade Using CLI
- Salesforce Developers, Push Package Upgrades to Subscribers (1GP guide)
- Salesforce Developers, Push Upgrades (1GP guide)
- Salesforce Developers, Push Upgrade Best Practices
- Salesforce Developers, Object Reference, PackagePushRequest
- Salesforce Developers, Object Reference, PackagePushJob
- Salesforce Developers, Object Reference, PackagePushError
- Salesforce Developers, Assign Access to New and Changed Features
- Aquiva, Summer '26 Salesforce Release Highlights That Matter
- Salesforce Developers, Object Reference, PackageSubscriber



