Big Objects in Salesforce | Design and Query Guide

Written by Prasanth Kumar Published on Updated on

Big objects are Salesforce objects designed for datasets that can grow far beyond the practical size of standard or custom objects. They work best for records that are written in large volumes, retained for years, and queried through a fixed access pattern rather than edited through normal record pages.

A big object is not a drop-in replacement for a custom object. Its index defines both record identity and the query paths available to your application, so the index must be designed before production data is loaded.

What are big objects in Salesforce?

Salesforce provides two categories: standard big objects supplied by Salesforce products and custom big objects created for an org-specific data model. A custom object uses the __c suffix, while a custom big object uses __b.

Common uses include long-term audit records, historical snapshots, telemetry, transaction history, and archived operational records. The stored data should normally be append-oriented or replaced by its composite index rather than managed with frequent interactive edits.

Requirement Standard or custom object Custom big object
Normal Lightning record pages Supported Not the primary access model
Frequent updates and workflow Suitable Poor fit
Very large retained dataset Can become costly or hard to operate Designed for high-volume retention
Query flexibility Broad SOQL support Queries must follow the index
Triggers Supported Not supported
Record identity Salesforce record ID Composite index values

Salesforce big object naming and field support

A custom big object can contain Lookup Relationship, Date/Time, Email, Number, Phone, Text, Text Area (Long), and URL fields. At least one required custom field must be included in the index before the object can be deployed. Salesforce documents a maximum of five fields in an index, and all indexed fields must be required.

The combined length of indexed text fields cannot exceed 100 characters. Long Text Area fields cannot be indexed. After creation, the index cannot be edited or deleted; changing it requires a new big object and a migration.

How do you decide whether to use big objects?

Use big objects when data volume is high, retention is long, the access pattern is known, and users do not need normal CRUD behavior. Do not choose them only because an org is approaching its storage allocation. First determine which records are still operational, which must remain reportable, and which can be archived outside the transactional model.

Good use cases for big objects in Salesforce

  • Compliance archive: retain immutable or rarely replaced evidence keyed by business record and timestamp.
  • Historical snapshots: store periodic values for an account, asset, entitlement, or subscription.
  • Integration telemetry: retain request outcomes, correlation IDs, and timestamps for troubleshooting.
  • Transaction history: retain detailed events while keeping only current balances or summaries on standard objects.

Cases where a Salesforce big object is the wrong choice

  • The record must participate in triggers, Flow-driven record automation, approvals, or frequent user edits.
  • Users need arbitrary filters that were not known during index design.
  • The dataset must be searched with unsupported SOQL operators or joined in many different ways.
  • The main requirement is real-time analytics across changing dimensions.

How should you design a big object index?

The index is the most important design decision. It acts as a composite primary key and constrains SOQL filters. Put the field used in nearly every query first, followed by fields that narrow the result set. A date or sequence field often belongs later when the application needs a bounded range.

Index example for an account activity archive

Assume the application retrieves activity for one account, one activity category, and a time range. A suitable index order is:

  1. Account__c
  2. Activity_Type__c
  3. Occurred_At__c

This order supports queries for an account, for an account plus activity type, and for an account plus activity type over a date range. It does not efficiently support a query that starts only with Occurred_At__c.

SELECT Account__c, Activity_Type__c, Occurred_At__c, Outcome__c
FROM Account_Activity_Archive__b
WHERE Account__c = '001000000000001'
  AND Activity_Type__c = 'LOGIN'
  AND Occurred_At__c >= 2026-01-01T00:00:00Z
  AND Occurred_At__c < 2026-02-01T00:00:00Z
ORDER BY Account__c, Activity_Type__c, Occurred_At__c

For indexed filtering, use the leading fields in index order. Equality filters are used for the earlier index fields; a range comparison can be applied to the final field included in the filter path. Big object SOQL does not support every operator available for other objects. Salesforce specifically lists operators such as !=, LIKE, NOT IN, INCLUDES, and EXCLUDES as unsupported for big objects.

Index review checklist

  • List the exact queries the application must run.
  • Verify that every query starts with the same leading index field or split the use case into separate objects.
  • Avoid descriptive text in the index unless it is a stable query key.
  • Choose index direction to match the required sort order.
  • Test with realistic data distribution, not only a small uniform sample.

How do you create and deploy a custom big object?

In Setup, search for Big Objects, create the object, add its fields, create the index, and change the deployment status from In Development to Deployed. The object cannot be deployed until its index contains at least one required custom field.

Teams that manage metadata as source should define the object, fields, and index through Metadata API deployment. The following abbreviated metadata illustrates the structure; field definitions must also exist in the object metadata.

<?xml version="1.0" encoding="UTF-8"?>
<CustomObject xmlns="http://soap.sforce.com/2006/04/metadata">
    <deploymentStatus>Deployed</deploymentStatus>
    <label>Account Activity Archive</label>
    <pluralLabel>Account Activity Archives</pluralLabel>

    <fields>
        <fullName>Account_Key__c</fullName>
        <label>Account Key</label>
        <length>18</length>
        <required>true</required>
        <type>Text</type>
    </fields>

    <fields>
        <fullName>Occurred_At__c</fullName>
        <label>Occurred At</label>
        <required>true</required>
        <type>DateTime</type>
    </fields>

    <fields>
        <fullName>Outcome__c</fullName>
        <label>Outcome</label>
        <length>80</length>
        <type>Text</type>
    </fields>

    <indexes>
        <fullName>AccountActivityIndex</fullName>
        <label>Account Activity Index</label>
        <fields>
            <name>Account_Key__c</name>
            <sortDirection>ASC</sortDirection>
        </fields>
        <fields>
            <name>Occurred_At__c</name>
            <sortDirection>DESC</sortDirection>
        </fields>
    </indexes>
</CustomObject>

How do you load data into a Salesforce big object?

Salesforce supports loading through Data Loader, Bulk API, SOAP API, and Apex. Use bulk-oriented integration for archive migrations or event ingestion. Do not build a loop that performs one immediate insert for every source record.

Apex insertImmediate example

Apex uses Database.insertImmediate. When a record is inserted with the same complete index values as an existing record, Salesforce replaces the non-index data in an upsert-like operation. Changing an indexed value creates a different record identity.

public with sharing class ActivityArchiveWriter {
    public static List<Database.SaveResult> write(
        Id accountId,
        List<ActivityInput> inputs
    ) {
        if (accountId == null || inputs == null || inputs.isEmpty()) {
            return new List<Database.SaveResult>();
        }

        List<Account_Activity_Archive__b> rows =
            new List<Account_Activity_Archive__b>();

        for (ActivityInput input : inputs) {
            if (input == null || input.occurredAt == null) {
                continue;
            }

            rows.add(new Account_Activity_Archive__b(
                Account_Key__c = String.valueOf(accountId),
                Occurred_At__c = input.occurredAt,
                Outcome__c = input.outcome
            ));
        }

        return rows.isEmpty()
            ? new List<Database.SaveResult>()
            : Database.insertImmediate(rows);
    }

    public class ActivityInput {
        @AuraEnabled public Datetime occurredAt;
        @AuraEnabled public String outcome;
    }
}

Governor-limit note: collect rows and call Database.insertImmediate once per logical unit of work. The method returns save results, so production code should inspect failures and send rejected rows to a retry or dead-letter process. Salesforce warns that tests writing directly to a big object can leave data behind; isolate the persistence boundary and mock it in unit tests rather than inserting archive records from every test.

How do you query big objects?

Synchronous SOQL can retrieve records when the query follows the index. Select only the fields the caller needs and always provide a bounded filter. A query that omits the leading index field is a data-model problem, not something to fix by adding a larger LIMIT.

public with sharing class ActivityArchiveReader {
    public static List<Account_Activity_Archive__b> findRecent(
        Id accountId,
        Datetime startTime,
        Datetime endTime
    ) {
        if (accountId == null || startTime == null || endTime == null ||
            startTime >= endTime) {
            return new List<Account_Activity_Archive__b>();
        }

        return [
            SELECT Account_Key__c, Occurred_At__c, Outcome__c
            FROM Account_Activity_Archive__b
            WHERE Account_Key__c = :String.valueOf(accountId)
              AND Occurred_At__c >= :startTime
              AND Occurred_At__c < :endTime
            ORDER BY Account_Key__c ASC, Occurred_At__c DESC
            LIMIT 500
        ];
    }
}

For processing that cannot be completed as a small indexed retrieval, review Salesforce’s current Big Objects implementation guide and the available asynchronous or downstream analytics options for your org. Do not assume that a query pattern supported for a custom object is supported for a big object.

Salesforce data storage best practices for archive solutions

Salesforce data storage best practices

  • Separate active and historical data. Keep records required by current automation on standard or custom objects. Archive only after the business process is complete.
  • Store a stable source key. Preserve the original record ID or external business key so archived data can be traced back to its source.
  • Define retention and deletion rules. A large-capacity store still needs legal, privacy, and operational retention controls.
  • Reconcile every migration. Compare source counts, target counts, rejected records, and sampled field values before deleting source data.
  • Keep summaries where users work. Put current totals or recent status on normal objects and retrieve detail from the archive only when requested.
  • Monitor query paths. New reporting requirements can invalidate the original index assumptions.

Security and access control

Grant object and field permissions through profiles or, preferably, permission sets aligned to job functions. Apex running in system context can bypass user-level access checks, so do not expose a generic archive query method without an explicit authorization design. Validate identifiers, restrict date ranges, and return only fields required by the user interface or integration.

Archive migration sequence

  1. Classify records by retention, legal hold, and operational use.
  2. Design the target schema and index from approved query examples.
  3. Load a representative sample and measure retrieval behavior.
  4. Bulk-load a controlled partition and capture all save results.
  5. Reconcile source and target data.
  6. Update reports, integrations, and support procedures.
  7. Delete source records only after sign-off and a recovery window.

Common errors with big objects

Problem Cause Correction
Query fails or returns no usable path Filter skips the first index field Rewrite the access pattern or redesign the object
Index cannot be saved Field is optional, unsupported, or text length is too large Use required supported fields and keep indexed text within limits
Existing row appears replaced The inserted record has the same composite index Include every value needed to make the record identity unique
New reporting request cannot be implemented The requested filter does not match the immutable index Create a derived store, summary object, or a new big object
Unit tests create persistent archive data Tests call immediate big-object DML Mock the writer boundary as recommended by Salesforce

Big objects versus external objects and Data Cloud

Choose based on where the data must live and how it will be used. A custom big object keeps high-volume data on the Salesforce Platform with index-driven access. An external object leaves data in an external system and exposes it through Salesforce Connect. Data Cloud is intended for harmonizing and activating data across sources, not as a direct substitute for every transactional archive. Architecture should start with residency, latency, analytics, security, and cost requirements.

Frequently Asked Questions

Can a Salesforce big object have triggers?

No. Custom big objects do not support Apex triggers, so trigger-dependent processing must occur before ingestion or in a separate service or asynchronous process.

Can you update records in big objects?

You do not use normal update DML. Inserting a record with the same composite index values replaces the stored non-index values in an upsert-like operation. Changing an index value creates a distinct record.

Can the index on a custom big object be changed?

No. After the index is created, it cannot be edited or deleted. Create a new big object with the required index and migrate the data.

How many fields can a big object index contain?

A custom big object index can contain up to five required custom fields. Long Text Area fields cannot be indexed, and the combined length of indexed text fields cannot exceed 100 characters.

Do big objects reduce standard Salesforce data storage?

They can support an archive design that removes eligible historical records from standard or custom objects, but the migration must include retention rules, reconciliation, recovery planning, and updates to reports and integrations.

Official Salesforce references

Related SalesforceTutorial guides