Skip to content

Salesforce

What We Learned Shipping a Salesforce Managed Package

There’s a large gap between customising Salesforce for one company and shipping a package that other companies install into orgs you will never see.

Most Salesforce work is the first kind, and it’s valuable work. But the moment your code has to run inside someone else’s org — with their customisations, their data volumes, their edition, their admin who has never heard of you — nearly every assumption changes.

We’ve done it both ways: CallHippo, a telephony integration published on the AppExchange that lets agents call, text and log every interaction without leaving the CRM, and Accordsign, a private managed package installed and running in production with paying customers. Here’s what that teaches you.

A managed package is a product, not a project

The mental shift is the whole thing.

A customisation has one customer, one org, and a change request process. If something’s wrong, you fix it in place next Tuesday. A managed package has many customers, each on their own upgrade schedule, running your code in an environment you can’t inspect. You can’t hotfix your way out of a design mistake, and some decisions can never be undone at all.

That means the design phase carries far more weight than it does in delivery work, and the things that matter most aren’t features.

Namespaces are forever

Every managed package gets a namespace prefix, registered once, permanently. It prefixes your objects, fields and classes in every org that installs you.

You cannot change it. You cannot move a component out of it. Get it wrong and you live with it, or you start a new package and migrate every customer.

This sounds like trivia. It isn’t — it’s the first genuinely irreversible decision in a Salesforce product, and it’s usually made in the first week by whoever set up the dev org, often before anyone’s thought about what the product will be called in three years.

Governor limits are part of your specification

Salesforce is multi-tenant, which means hard limits on queries, CPU time, rows processed and callouts. Every Salesforce developer knows this. What changes in a package is whose limits you’re consuming.

Your code runs inside the customer’s org, sharing their limits with their own automations, other vendors’ packages, and whatever a consultant built in 2019. Code that runs comfortably in your clean development org can fail in a customer org that’s already at 80% of its limits before your package loads.

So limits stop being an implementation detail and become a design constraint you specify against: bulk-safe by default, no queries inside loops ever, asynchronous processing wherever the work might scale, and defensive behaviour when you can’t get the resources you need. “It works in our org” is not evidence.

Security review is a gate, not a formality

Publishing on the AppExchange means passing Salesforce’s security review, and it’s genuinely rigorous — sharing and permissions enforcement, injection protection, secure storage of secrets, and a full pass over your external components.

The mistake teams make is treating it as a submission step at the end. It isn’t; it’s a set of architectural requirements. Retrofitting proper sharing enforcement or credential handling into a nearly-finished package is expensive and demoralising. Build to the standard from the first sprint and review becomes a checkpoint rather than a crisis.

A private managed package skips the public review, but not the discipline — you still have customers whose data you’re responsible for, and the same standards apply whether or not someone external is checking.

Upgrades are a promise you’re making

In a bespoke build, a schema change is a migration script. In a package, it’s a commitment.

Once a component is released in a managed package, you’re constrained in what you can change about it — removing fields, changing types, altering signatures. Customers may skip versions. Some will be several releases behind. Your code has to upgrade cleanly across that spread without touching their data.

The practical consequence: you version deliberately, you deprecate rather than delete, and you think hard before exposing anything publicly, because a public interface is a contract. Packages that stay maintainable are the ones that kept their exposed surface small on purpose.

Every org is different, so make it configurable

Your package will land in orgs with unfamiliar record types, mandatory custom fields, validation rules that reject your writes, and automation that fires on your objects in ways you didn’t anticipate.

The defence is configuration over assumption. Anything an admin might reasonably need different — field mappings, behaviours, thresholds — should be settings, not constants. And your installation experience needs to be genuinely self-service, because the admin installing you has no access to your team and no patience for a fifteen-step manual setup.

Testing follows from this: not just your clean dev org, but orgs deliberately made messy — different editions, existing automation, realistic data volumes, a Person Accounts org if you claim to support it.

If you’re an ISV starting out

A few things we’d say to anyone considering their first package.

Decide early and honestly whether you need a package at all. If you have one enterprise customer, a customisation may serve them better and cost far less. Packaging is for products with many installs.

Register the namespace only when you’re confident about the product’s name and scope, because that decision is permanent.

Design for limits, sharing and upgradeability from the first line of code, not as a hardening phase before submission.

And budget realistically for the distance between “working demo” and “installable product.” It’s the same gap that exists in every kind of software, and on the Salesforce platform it’s wider than most teams expect — the platform gives you an enormous amount, and asks for real rigour in return.


Building a product on Salesforce? See our Salesforce practice — implementation, APEX, integrations and managed-package development — or talk to us about the build.