When I'm within a Salesforce org, how can I tell if that org is a Scratch Org or not?

Ideally this would be via Apex, but it could be an API call if required.

This would be useful information for the creator of a managed package who may not otherwise know what type of org is running the code.

I've had a couple of thoughts on how this might be achieved:

  1. Check if the pod/instance that Scratch orgs are created on are separate from the general population of sandbox orgs. I suspect that scratch orgs have dedicated hardware. E.g. a new scratch org I just created is on p0/CS31.
  2. Look for describe Metadata that is unique to only scratch orgs.
  • Full disclosure, this question has been discussed in the GoodDaySir slack channel. For posterity, it would be useful to have a solution listed in the open. gooddaysir.slack.com/messages/C3BJMEH3J/convo/… Commented Apr 4, 2019 at 1:31
  • Can you see the relevant ActiveScratchOrg or ScratchOrgInfo from within one?
    – Adrian Larson
    Commented Apr 4, 2019 at 1:33
  • @AdrianLarson Those are in the DevHub, aren't they? I don't think they would be reachable from the Scratch org itself in isolation. Commented Apr 4, 2019 at 1:38
  • For scratch dev edition orgs in specific, they are always located on CS sandbox pods but also identify as Developer Edition. That's a combo you don't see anywhere other than scratch orgs at the moment.
    – Charles T
    Commented Apr 4, 2019 at 4:54
  • 1
    One other option could be to query the Organization object and identify the difference between CreatedDate and TrialExpirationDate for an Org. In majority of the cases say for DE Orgs, Prod, and Sandboxes, TrialExpirationDate will be null. If you are not considering any trial orgs, then just having TrialExpirationDate populated will help identify that the org is a Scratch Org. For Scratch Orgs, the difference between the dates though will be anything between 1-30.
    – Jayant Das
    Commented Apr 4, 2019 at 13:12

6 Answers 6


Using the Organization object, both scratch and trial orgs have TrialExpirationDate, but we can use IsSandbox to differentiate the two.

Organization org = [SELECT IsSandbox, TrialExpirationDate FROM Organization];
Boolean isScratchOrg = org.IsSandbox && org.TrialExpirationDate != null;
Boolean isTrialOrg = !org.IsSandbox && org.TrialExpirationDate != null;
  • That's pretty clever, but won't this be fooled by a real Trial org? Commented May 8, 2019 at 2:05

The SourceMember sObject is only present in scratch orgs. Its presence would be a sign that you are in a scratch org. The gotcha would be that it is only accessible via the Tooling API and not Apex alone.


  • This seems like a great solution and shouldn't be too difficult with an HTTP request from Apex. Especially since we don't need the Remote Site setting anymore. Commented Apr 4, 2019 at 1:40
  • 1
    Unfortunately, this approach is not working anymore, since it is allowed now to enable source tracking for sandboxes as well.
    – wesaw
    Commented Feb 10, 2022 at 12:09

I don't have the rep to comment on Kevin Vizcarra's answer but I tested creating a sandbox from a Trial org and TrialExpirationDate was null so his answer does seem like the easiest to implement. To sum up, the query SELECT IsSandbox, TrialExpirationDate FROM Organization results in...

IsSandbox == true && TrialExpirationDate != null //in a scratch org
IsSandbox == false && TrialExpirationDate != null //in a trial org
IsSandbox == true && TrialExpirationDate == null //in a sandbox created from a trial org

I believe that the new SourceChangeNotification object will also work for this, even from within Apex. I tested this in a bunch of different orgs - scratch, sandbox, dev, production. It only returned true from within a Scratch Org.

Map<String, Schema.SObjectType> allObjects = Schema.getGlobalDescribe();
  • I think this approach is likely no longer viable since Salesforce has extended source tracking to more org types.
    – Phil W
    Commented Sep 23, 2020 at 8:19

Using the Organization object is a good answer, apart from IsSandbox and TrialExpirationDate you can also use Name which relates directly to "orgName" in the project-scratch-def.json. So if that doesnt change for your scratch builds then that is probably the safest.


If you only use the default generated usernames then you can use this Regex Check:

public static Boolean runningInAScratchOrg {
    get {
        if (runningInAScratchOrg == null) {
            runningInAScratchOrg = Pattern.matches('^test-[a-z0-9]{12}@example\\.com$', UserInfo.getUserName());
            // e.g. [email protected]
        return runningInAScratchOrg;

You must log in to answer this question.

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