sObject
An sObject (short for Salesforce Object) is the Apex data type that represents a row of Salesforce data.
Definition
An sObject (short for Salesforce Object) is the Apex data type that represents a row of Salesforce data. Every standard object like Account or Contact, and every custom object like Invoice__c, has a matching sObject type in Apex. When you query a record, build one to insert, or pass record data between methods, you are working with an sObject.
There is also a generic sObject type with a lowercase first letter in writing but the same SObject class underneath. The generic type can hold a record of any object, which lets you write code that does not know its object type until runtime. Specific types such as Account give you compile-time field checking. Both share the same DML and method surface, so the choice is about how much type safety you want.
How sObjects model your data inside Apex
The bridge between your data model and your code
Salesforce stores data in objects, and each object holds records made of fields. An sObject is how that record shows up once Apex gets hold of it. The Apex name of an sObject always matches the object's API name, not its display label. So the Account object is the Account sObject, and a custom object named Invoice becomes Invoice__c. Custom fields follow the same rule and carry the __c suffix. This naming link is strict. If you rename an object's label in Setup, the API name and the sObject type stay the same, which keeps your code from breaking. You instantiate an sObject the way you would any Apex object, with the new keyword. A handy shortcut lets you set fields right in the constructor, like new Account(Name = 'Acme', Industry = 'Technology'). Each record you build this way lives in memory until you commit it with a DML statement. Until then it has no Id and does not exist in the database. The sObject is the unit that flows through almost every data operation you write, from a single record update to a batch job processing millions of rows.
Generic sObject versus a specific type
The generic sObject type is the parent of every specific type. You can assign any record to a variable typed as sObject, which is what makes dynamic code possible. A method signature that accepts an sObject can take an Account, a Contact, or a record of an object that did not exist when the method was written. Trigger frameworks, generic save handlers, and integration layers all lean on this. The cost is that the compiler cannot check field names. Reading a field on a generic sObject uses the get('FieldName') method or the put('FieldName', value) method, and a typo there fails at runtime rather than at compile time. Specific types flip that trade. When you declare Account a = new Account(), you get dot notation like a.Name, and the compiler rejects a field that does not exist on Account. You can move between the two with casting. A generic sObject known to hold an Account can be cast back with (Account) record. The general rule is to use specific types whenever you know the object, and reach for the generic type only when the code genuinely has to handle more than one.
Reading and writing fields
On a specific sObject, fields behave like properties. You read account.Industry and assign account.Industry = 'Finance' directly. Relationship fields let you walk to a parent record, so contact.Account.Name reaches the related account's name if that relationship was loaded by your SOQL query. Trying to touch a field or parent that was not queried throws a System.SObjectException for the field not being set, which is one of the most common runtime errors new developers hit. On a generic sObject you use methods instead of dot notation. The get('Industry') method returns the value as an Object that you cast to the expected type, and put('Industry', 'Finance') sets it. Two methods are worth knowing. The getSObjectType() method returns a token describing which object the record is, useful when branching logic on type. The getPopulatedFieldsAsMap() method returns only the fields that were actually queried or set, which is the safe way to loop over a record's data without guessing field names. These methods are the toolkit for code that has to stay object-agnostic.
sObjects in collections and DML
Real Apex rarely touches one record at a time. The platform is built around bulk processing, and sObjects collect naturally into lists, sets, and maps. A List<Account> holds many account records, and a Map<Id, Account> keys records by their Id for fast lookup. DML statements operate on whole collections in one call. Writing update accountList sends every changed account in a single transaction, which is how you stay inside governor limits instead of issuing one DML statement per record inside a loop. The five DML verbs all take sObjects or lists of them. Insert adds new records and stamps each with a fresh Id. Update saves changes to existing records. Delete moves records to the Recycle Bin. Upsert inserts or updates based on Id or an external Id field. Undelete restores deleted records. You can also mix a list with the generic type, so a List<sObject> can carry records of different objects in one batch, which is handy for generic data loaders. Each call counts against the per-transaction DML limits, so batching is not just style, it is a hard requirement.
Where sObjects come from: SOQL and SOSL
Most sObjects in your code start life as query results. A SOQL query returns records already shaped as sObjects, and the type matches the object you queried. List<Contact> contacts = [SELECT Id, Name FROM Contact] gives you strongly typed Contact records. Only the fields you list in the SELECT clause are populated, which ties back to the not-set exception. Query a field, and it is available, skip it, and reading it throws. You can also assign a query result to a generic List<sObject> when the object type is not known until runtime, which pairs with dynamic SOQL built from a string. SOSL searches return a List of Lists of sObjects because a single search can span several objects at once. Beyond queries, the Schema describe methods hand back sObject type tokens and field metadata, letting code inspect an object's structure before deciding what to do. This describe layer is what powers tools that adapt to any org's data model, including managed packages that cannot know a subscriber's custom objects in advance.
Common pitfalls and good habits
The not-set exception is the pitfall that bites everyone first. It means you read a field or relationship that your query never loaded. The fix is to add the field to the SELECT clause, or to check whether it was populated before reading it. A related trap is assuming a freshly built sObject has an Id before you insert it. It does not, and reading record.Id returns null until DML runs. Mixing object types in one DML call has a real limit. While a List<sObject> can hold different object types, a single insert or update statement cannot save more than one object type at once, so you split the list by type first. Setup objects and certain non-setup objects also cannot be mixed in the same transaction without care. Finally, sObjects are heavier than primitives, so holding huge lists in memory can hit heap limits. Query only the fields you need, process in batches, and clear references when you are done. These habits keep code fast and inside the platform's limits as data volume grows.
Trust & references
Cross-checked against the following references.
- sObject Types | Apex Developer GuideSalesforce
- SObject Class | Apex Reference GuideSalesforce
Straight from the source - Salesforce's reference material on sObject.
Hands-on resources to go deeper on sObject.
About the Author
Dipojjal Chakrabarti is a B2C Solution Architect with 29 Salesforce certifications and over 13 years in the Salesforce ecosystem. He runs salesforcedictionary.com to help admins, developers, architects, and cert/interview candidates sharpen their fundamentals. More about Dipojjal.
Test your knowledge
Q1. What is an sObject in Apex on the Salesforce platform?
Q2. Why does Apex expose a generic sObject base type alongside concrete subtypes like Account?
Q3. How do Apex developers typically read and write sObject records inside a class?
Discussion
Loading discussion…