Can a 2GP Depend on a 1GP with the Same Namespace?

Question
Can I Create a 2nd-Generation Package (2GP) Dependent on a 1st-Generation Package (1GP) with the Same Namespace
Answer
No, this is not possible. According to Salesforce documentation, if a 1GP and a 2GP share the same namespace, they cannot be installed in the same org. This restriction applies regardless of whether the packages have a dependency on each other.
If your goal is to create a 2GP that extends a 1GP, the 2GP must use a different namespace. However, 1GP packages can have 2GP extension packages, provided that the 2GP packages use a different namespace.
If your 1GP provides Apex-based services that the 2GP needs to use, those services must be declared global
so they can be accessed externally.
Additionally, multiple 2GP extension packages can share the same namespace among themselves, but this requires careful management to avoid name clashes. Since Salesforce does not scope API names to a package—only to a namespace—any two 2GPs in the same namespace with identically named classes or components will conflict if installed in the same org. To prevent this, a common practice is to use a unique prefix for all API names originating from each package.
Example Scenario
If you have a 1GP named MyPackage with the namespace mypkg
, and you want to create a 2GP extension package, you cannot give the 2GP the same mypkg
namespace. Instead, you must use a different namespace, such as mypkgext
.
1GP Apex Class (Namespace: mypkg
)
global with sharing class UtilityClass {
global static String getGreeting() {
return 'Hello from 1GP!';
}
}
Breakdown of Each Keyword and Concept
global
(Class Level)
Declares the class as global, meaning it can be accessed from anywhere, including outside the package. This is required when exposing Apex classes from a managed package (like a 1GP) to other packages or orgs.with sharing
Enforces sharing rules, meaning the class respects record access permissions based on the running user’s profile and sharing settings. If omitted or replaced withwithout sharing
, the class could bypass org-wide security restrictions.class UtilityClass
- Declares a class named
UtilityClass
. This class contains methods and logic that can be reused.
- Declares a class named
global static String getGreeting()
global
(Method Level): Makes the method accessible outside the package, just like the class itself. This is necessary if another package (like a 2GP) needs to call this method.static
: The method belongs to the class itself rather than an instance of the class. This means it can be called without creating an object ofUtilityClass
.String getGreeting()
: Defines a method namedgetGreeting()
that returns aString
.
return 'Hello from 1GP!';
- The method simply returns the string
"Hello from 1GP!"
when called.
- The method simply returns the string
2GP Extension Package (Namespace: mypkgext
)
public with sharing class ExtendedUtility {
public static String fetchGreeting() {
return mypkg.UtilityClass.getGreeting(); // Accessing 1GP class
}
}
Breakdown of Each Keyword and Concept
public
(Class Level)- Declares the class as public, meaning it is accessible within the same namespace and org.
- Unlike
global
, apublic
class cannot be accessed by external orgs or packages. - Since this is a 2nd-generation package (2GP), it does not need to be
global
unless it is explicitly meant for external access.
with sharing
- Enforces sharing rules, ensuring that the class respects user permissions and sharing settings when accessing records.
- If omitted or replaced with
without sharing
, the class would not enforce sharing rules, which could lead to unintended data access.
class ExtendedUtility
- Declares a class named
ExtendedUtility
. This class is part of a 2GP extension package that depends on a 1GP.
- Declares a class named
public static String fetchGreeting()
public
(Method Level): The method is accessible within the same org and namespace.static
: The method belongs to the class itself rather than an instance of the class. This means it can be called without creating an object ofExtendedUtility
.String fetchGreeting()
: Defines a method namedfetchGreeting()
that returns aString
.
return mypkg.UtilityClass.getGreeting();
- Calls the
getGreeting()
method fromUtilityClass
, which is part of a 1GP managed package with the namespacemypkg
. - This works because
UtilityClass
and its methodgetGreeting()
are declared as global in the 1GP. - The
mypkg
namespace ensures that the correct class is referenced, avoiding potential conflicts with similarly named classes in different packages.
- Calls the
This setup ensures that the 2GP can reference the 1GP’s global classes while adhering to namespace restrictions.
Kick Start Your Journey with Real-Time Project-Based Salesforce Learning
Our Salesforce Course is structured to provide a deep understanding of the Salesforce platform, equipping you with the essential skills to excel in the CRM industry. The curriculum covers vital modules such as Salesforce Admin, Developer, and AI, seamlessly integrating theoretical concepts with practical application. Through hands-on projects and real-world exercises, you will gain the expertise needed to solve complex business challenges using Salesforce solutions. Our experienced trainers ensure you develop both technical proficiency and industry insights to succeed in the Salesforce ecosystem.
In addition to technical training, our Salesforce Training in McLean offers personalized mentorship, certification guidance, and interview coaching to enhance your career prospects. You will have access to extensive study materials, live project experience, and dedicated support throughout your learning journey. By the end of the program, you will be fully prepared for certification exams and possess real-world problem-solving skills that employers highly value. Start your Salesforce career with us and open the door to endless opportunities. Enroll for a Free Demo today!