public and global are both “visible from outside the defining class,” but they differ in how far outside. The rule of thumb:
public— visible everywhere in your org’s Apex, but invisible to managed-package consumers.global— visible everywherepublicis, plus to subscriber code from another managed package, and to web service callers.
For internal org code, public is sufficient 99% of the time. global is the right choice only when you ship a managed package or expose a SOAP/REST endpoint.
public — the everyday everyone-in-the-org modifier
public class OrderService {
public Decimal totalWithTax(Decimal amount) {
return amount * 1.18;
}
}
Any class in the same org can construct OrderService and call totalWithTax. Triggers, batch jobs, controller classes, even anonymous Apex.
What public does NOT cover:
- Code in a different installed managed package cannot see it.
- An external system calling a SOAP web service method cannot reach it.
- JavaScript inside an LWC cannot directly call it (LWCs use
@AuraEnabledApex methods regardless of class modifier).
For most Salesforce projects — where everything is in one org’s namespace — public is the right escalation from private whenever you genuinely need an external caller.
global — the wider-reach modifier
global class StripeGateway {
global static String charge(Decimal amount, String token) {
// visible to subscriber orgs if this is a managed package
// visible as a SOAP method if marked webService
return 'ch_' + token;
}
}
global is required when:
- You ship a managed package and want subscribers to call into your Apex.
- You expose a SOAP web service method with the
webServicekeyword. - A class implements
Database.Batchable,Schedulable, orQueueableand is invoked by name from a managed-package subscriber org — the class itself must beglobal. - A REST resource class — the class is
globaleven though only Apex within the org sees it directly.
@RestResource(urlMapping='/orders/*')
global with sharing class OrderResource {
@HttpGet
global static List<Order__c> get() {
return [SELECT Id FROM Order__c LIMIT 100];
}
}
For an @RestResource class, the class and the methods must be global.
The contract burden
The big difference in spirit: a public method can be renamed, removed, or changed with only your own codebase to consider. A global method becomes part of a public contract — subscriber code, integration partners, or external systems may depend on it. Removing or changing a global method’s signature in a managed package is a breaking change for every subscriber org.
That’s why senior developers reach for global last. It’s not a “wider public” — it’s a contract you can’t easily walk back.
What global does NOT mean
- It does NOT mean “callable from JavaScript LWC.” LWC reaches Apex via
@AuraEnabledmethods on a class, regardless of whether the class or method ispublicorglobal. (The class still has to bepublicorglobal; methods have to be@AuraEnabled.) - It does NOT bypass FLS, sharing, or CRUD. All standard security still applies.
- It does NOT mean “shared across orgs.” Each subscriber org installs the managed package;
globalmethods are callable within the subscriber org, not magically shared.
A quick comparison table
| Visibility | Same class | Same org (Apex) | Subscriber of managed package | SOAP / REST clients |
|---|---|---|---|---|
private | Yes | No | No | No |
protected | Yes | Subclasses only | No | No |
public | Yes | Yes | No | No |
global | Yes | Yes | Yes | Yes (with webService) |
A pragmatic checklist
Use global if and only if at least one of these is true:
- The class is in a managed package and external code must invoke it.
- The class has
@RestResourceand is the HTTP entry point. - The class implements
Database.Batchableand is invoked from a managed-package subscriber. - The class has a method marked
webServicefor SOAP exposure.
Otherwise, use public. Inside public classes, default member visibility to private, escalate to public only when you need to expose it.
What interviewers are really looking for
The naming check: public is “org-wide,” global is “across-package.” Strong signals: (1) global is required for managed-package entry points and REST/SOAP web services, (2) global is a contractual commitment — much harder to change later, (3) @AuraEnabled is what makes a method callable from LWC, not global, (4) the seniority cue is the bias toward public and treating global as a deliberate escalation.
Verified against: Apex Developer Guide — Access Modifiers, REST and SOAP Web Services in Apex. Last reviewed 2026-05-17.