I am running this script from developer console.

List<Account> lstAccount = [SELECT Id, Name, BillingStreet From Account LIMIT 1];

Debug Log:

23:47:04:012 USER_DEBUG [5]|DEBUG|(Account:{Id=0019000001nNLGEAA4, Name=Acct_nm001, BillingStreet=xyz Road, RecordTypeId=01290000000iaNiAAI})

I never queried for RecordtypeId in SOQL, but it is included in the list.

Although, if I run the query from the query editor, it is not showing RecordtypeId column.

Is this by design? Then why not Salesforce is not providing us audit fields in the first scenario.

  • I don't see the same behaviour in my spring 17 Developer edition org with the same code running in developer console.
    – javanoob
    Jan 15, 2017 at 5:12
  • I was able to reproduce this. @javanoob have you defined record types for Accounts in your org?
    – martin
    Jan 15, 2017 at 5:20
  • @martin you are correct. I tried in a different org and I see this. In my developer edition org record type is not enabled. Thanks!
    – javanoob
    Jan 15, 2017 at 5:23

2 Answers 2


In Apex Code, the SOQL engine automatically includes RecordTypeId and Id in any query result, even if you don't ask for it. There are a few other hidden parameters that appear in a query when presented to the SOQL engine.

For example, if you don't include a LIMIT statement, or set it to higher than 1+Limits.getLimitQueryRows()-Limits.getQueryRows(), the system automatically adds or changes the limit to LIMIT :1+Limits.getLimitQueryRows()-Limits.getQueryRows(). This is how the governor limits are enforced. The exception to this is for Batchable classes that use a Database.getQueryLocator statement, where the limit is set 50,000,001 rows. Also, when you don't specify ALL ROWS, Apex Code silently includes a filter IsDeleted = FALSE. In other words, whatever you put into your code isn't necessarily what will be executed by the SOQL engine.

Note that this means the following two queries are (approximately) the same in Apex Code:

Account[] accounts1 = [SELECT Id, RecordTypeId, Name, (SELECT Id, RecordType, Name FROM Contacts WHERE IsDeleted = FALSE) FROM Account WHERE IsDeleted = FALSE LIMIT :1+Limits.getLimitQueryRows()-Limits.getQueryRows()];
Account[] accounts2 = [SELECT Name, (SELECT Name FROM Contacts) FROM Account];

I don't know if there's a documented reason why RecordTypeId was specifically included, while audit fields were not, but I seem to recall that this behavior did not always exist in Apex Code, which suggests to me that some new SObject method was added that required this field to be present to function correctly. My best guess is that this field was needed for the Visualforce runtime engine to correctly render dynamic picklists on records.

  • 3
    That behaviour can’t be taken for granted. Always query all you want explicitly
    – stwissel
    Oct 10, 2017 at 16:19
  • @stwissel It's better to, but knowing the corner that salesforce.com has painted themselves in to, I suppose they'll never get rid of at least Id as an automatic suggested field. I do agree that you should explicitly list all the fields you need, though, because it makes the code easier to read and gives you better compilation errors. Id is the only field I routinely leave out of my queries.
    – sfdcfox
    Nov 30, 2017 at 7:58

I would like to point CurrencyISOCode which would also included by default, if your Org is Multicurrency enabled one.

You must log in to answer this question.

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