Blog › ICP guides
Salesforce consultant on retainer: Apex development, Lightning Web Components, SOQL optimization, and org architecture advisory on monthly retainer
August 7, 2026 · ~20 min read
A 200-person B2B software company has a Salesforce org that has accumulated 47 active automations on the Opportunity object: Process Builder workflows built in 2019, record-triggered flows added during the last major CRM project, and three Apex triggers written by two different contractors whose employment overlapped for three weeks. The VP of Sales reports that Opportunity saves occasionally time out after 8 to 12 seconds. The IT director has received three “SOQL 101 queries have been executed” errors in the debug log this week. The Head of Revenue Operations cannot explain why the lead assignment process assigns leads to territories correctly for 94 percent of records but fires the wrong assignment rule for leads created via the API. The company engages a fractional Salesforce technical consultant on monthly retainer to audit the automation stack, resolve the governor limit violations, and redesign the integration API lead creation workflow.
In month one: an org automation audit that maps all 47 active automations on Opportunity by trigger event, identifies the four automations that each contain SOQL inside a for loop iterating over trigger records (producing up to 200 SOQL queries per bulk operation against the 100-query limit), and identifies the conflicting before-save Flow and before-insert Apex trigger that both attempt to populate the same field, with the Apex trigger running last and overwriting the Flow calculation on every insert. The VP of Sales sees the audit report. The 22 hours of automation execution analysis, SOQL query plan review, and debug log trace interpretation behind the six identified architectural problems are not in the report.
Salesforce consultants, Salesforce developers, and Salesforce architects on monthly retainer — independent Salesforce technical consultants, fractional Salesforce architects, and boutique Salesforce consulting partners — perform their highest-value work in the Apex trigger framework design, SOQL query optimization, integration architecture advisory, security model design, and org governance that produces the platform stability and the sales team productivity the Revenue Operations team reports in QBRs. This guide covers Salesforce administration and configuration advisory, Apex and Lightning Web Components development, Salesforce integration architecture, and org design and release management — and how to structure a Salesforce retainer that makes the hours behind each platform function visible.
Salesforce administration and configuration advisory
Salesforce administration advisory covers the configuration layer of the Salesforce platform: the automation architecture, security model, data model, and reporting infrastructure that determine how the platform supports the organization's sales, service, and marketing processes. The advisory function is not configuration execution — it is the architectural analysis that identifies whether the current configuration is producing the outcomes the business requires, where it will fail as the org scales, and what specific configuration changes will resolve the identified gaps.
Automation architecture and Flow Builder design
Salesforce automation architecture has undergone a significant platform evolution: Workflow Rules (deprecated), Process Builder (deprecated), and Apex triggers are being replaced or supplemented by Record-Triggered Flows, which execute in a defined order (before-save flows run first, then Apex before triggers, then system validation, then DML, then after-save flows, then Apex after triggers). A Salesforce org that accumulated automations across three automation generations — Workflow Rules that send email alerts and update fields, Process Builder nodes that call Apex actions, and Record-Triggered Flows added since 2021 — often contains automation conflicts where two automations populate the same field in opposite before-save and after-save contexts, producing a field value that neither the original Workflow Rule nor the new Flow intended.
Flow Builder record-triggered flow design requires explicit attention to: Before-save vs. after-save execution context (before-save flows run synchronously before the database write and can update record fields without a DML operation, consuming zero SOQL queries for field update operations on the triggering record; after-save flows run after the database write and produce a DML operation for each record update, counting against the 150 DML statement per transaction limit); Governor limit awareness in flows (each Get Records element in a flow executes a SOQL query; a flow that calls Get Records inside a loop iterating over a collection of records produces one SOQL query per loop iteration and triggers the “Salesforce has limited the number of queries” error at 101 SOQL queries in a single transaction — the correct pattern uses a single Get Records with a filter condition before the loop and stores the result collection for use inside the loop); and Automation order dependency (when a before-save flow and an Apex before-insert trigger both modify the same field on the same object, the Apex trigger runs after the before-save flow and overwrites the flow's field assignment — resolving this conflict requires either removing the field assignment from one automation or restructuring the execution order through a custom metadata flag that the Apex trigger reads to skip its field assignment when the flow has already populated the value).
Security model design and permission set architecture
Salesforce record access is controlled through a four-layer model that must be designed holistically: Object-level security (configured via profiles and permission sets; defines which object types a user can access at all, and whether they can Read, Create, Edit, or Delete records); Field-level security (configured per field per profile or permission set; defines which specific fields a user can read or edit on a given object, independent of record-level access); Record-level sharing (the Org-Wide Default setting defines the baseline access level for all records of an object type — Private, Public Read Only, or Public Read/Write — and the sharing model layers above the OWD open access upward: role hierarchy grants managers access to their subordinates' records; sharing rules grant access to records owned by role hierarchies or public groups; manual sharing grants record-specific access; Apex managed sharing provides programmatic access control for complex sharing requirements that criteria-based sharing rules cannot express).
A security model design engagement begins with requirements mapping: which user personas need access to which records under which conditions. The Salesforce consultant maps these requirements to the sharing model, identifying where role hierarchy alone is insufficient (a regional sales manager who needs access to all accounts in their territory regardless of who owns the record requires criteria-based sharing rules or Apex managed sharing, not just role hierarchy), where field-level security conflicts produce data quality problems (a field required for a downstream integration that is hidden from the profile used by the integration user produces null values in the integration payload without an error message), and where the OWD settings on parent objects produce unintended child record exposure (setting the Account OWD to Private does not automatically restrict access to Contacts or Opportunities on those Accounts unless the Contact and Opportunity OWDs are also set to Private or Controlled by Parent).
Apex and Lightning Web Components development
Salesforce Apex is a strongly-typed, object-oriented programming language that executes on the Salesforce multi-tenant platform within a strict governor limit framework. Writing Apex that performs correctly in single-record UI interactions is straightforward; writing Apex that performs correctly under bulk data loads — where a Data Loader import of 50,000 records triggers the same Apex code as a single-record save from the UI — requires explicit governor limit awareness in every design decision.
Apex trigger framework design and bulkification
The canonical Salesforce Apex governor limits that constrain trigger design are: 100 SOQL queries per synchronous transaction (200 in asynchronous context); 150 DML statements per transaction; 50,000 records returned by SOQL queries per transaction; 10 MB heap size per transaction; 10,000 ms Apex CPU time per synchronous transaction; and 50 future method calls per transaction. A trigger that contains a SOQL query inside a for (SObject record : Trigger.new) loop violates the bulkification requirement: when 200 records are processed in a single trigger invocation (the maximum batch size for Data Loader), the loop executes 200 SOQL queries and throws a System.LimitException: Too many SOQL queries: 101 at the 101st record.
The trigger framework pattern that enforces bulkification at the architecture level: a single LeadTrigger.trigger that contains only TriggerDispatcher.run(new LeadHandler());; a TriggerHandler abstract class with virtual methods for each trigger event (beforeInsert, beforeUpdate, beforeDelete, afterInsert, afterUpdate, afterDelete, afterUndelete) that receive the full Trigger.new and Trigger.oldMap collections; and a concrete LeadHandler extends TriggerHandler that overrides only the relevant event methods and processes records as collections rather than individual iterations. The bulkification pattern in the handler: build a Set<Id> of related record Ids from Trigger.new in a single pass, execute one SOQL query outside any loop using WHERE Id IN :idSet, store the result in a Map<Id, SObject>, and access the related data from the map inside the processing loop without touching the database again.
Apex asynchronous processing: batch, queueable, and scheduled
When a trigger or transaction must process more records than fit in a single synchronous transaction's governor limits, Salesforce provides three asynchronous execution frameworks. Batch Apex (implements Database.Batchable<SObject>) processes records in configurable chunks (default 200, maximum 2,000 per execute() call) with governor limits reset per chunk: the start() method returns a Database.QueryLocator SOQL query that defines the record set (up to 50 million records); the execute() method processes each chunk; the finish() method sends completion notifications or chains to the next job. Queueable Apex (implements Queueable) provides a flexible single-job execution context with higher governor limits than future methods and the ability to chain jobs sequentially: System.enqueueJob(new LeadEnrichmentJob(leadIds)) enqueues the job; the execute(QueueableContext context) method processes the work and can call System.enqueueJob() once to chain the next job. Scheduled Apex (implements Schedulable) runs Apex on a cron schedule: System.schedule('Nightly Lead Score', '0 0 2 * * ?', new LeadScoringScheduler()) executes at 2:00 AM UTC daily.
Lightning Web Components architecture and wire service
Lightning Web Components (LWC) uses a reactive programming model where property changes trigger automatic re-rendering. The LWC lifecycle sequence for a component render: constructor() (component initialization, no DOM access); connectedCallback() (component added to DOM, safe to query DOM and set up event listeners); renderedCallback() (component rendered, safe to access rendered DOM elements — guard with a boolean property to prevent infinite render loops when renderedCallback modifies reactive properties); disconnectedCallback() (component removed from DOM, clean up subscriptions and event listeners).
The wire service provides a reactive data layer that connects LWC components to Salesforce data and Apex methods without imperative Apex calls: @wire(getRecord, { recordId: '$recordId', fields: FIELDS }) wiredRecord; subscribes the component to live updates of the specified record and fields, re-rendering automatically when the data changes. @wire with Apex methods: @wire(getRelatedContacts, { accountId: '$recordId' }) contacts; calls the @AuraEnabled(cacheable=true) Apex method reactively when recordId changes. Imperative Apex calls are required when the Apex method mutates data (DML operations cannot be marked cacheable=true): await updateOpportunityStage({ opportunityId: this.recordId, stage: this.selectedStage }); followed by a getRecordNotifyChange([{recordId: this.recordId}]) call to invalidate the cache and trigger a UI refresh.
Lightning Message Service (LMS) enables cross-component communication between components that do not share a parent-child relationship in the same Lightning page: define a .messageChannel metadata file; publish with publish(this.messageContext, MESSAGE_CHANNEL, { recordId: id }); in the sending component; subscribe with subscribe(this.messageContext, MESSAGE_CHANNEL, this.handleMessage.bind(this)) in connectedCallback() and unsubscribe(this.subscription) in disconnectedCallback() in the receiving component.
SOQL query optimization and the Query Plan Tool
SOQL queries on high-volume objects (Accounts with 500,000+ records, Leads with 1,000,000+ records) perform orders of magnitude differently depending on whether the database can use an index to locate matching records or must perform a full-table scan. The Salesforce Query Optimizer selects an index based on: the fields in the WHERE clause (standard indexed fields: Id, Name, OwnerId, CreatedDate, SystemModstamp, RecordTypeId, Master-Detail and Lookup foreign key fields; custom indexed fields: fields explicitly indexed by a Salesforce support case or fields marked as External ID); the selectivity of the filter (a WHERE clause that matches more than 10 percent of records on a standard index, or more than 30 percent of records on a custom index, triggers a full-table scan regardless of the index presence); and the filter operator (LIKE with a leading wildcard — WHERE Name LIKE '%ACME%' — cannot use a standard index and always produces a full-table scan).
The Query Plan Tool in the Salesforce Developer Console (Help › Query Plan) shows the execution plan for a SOQL query before it runs in production: the TableScan operation indicates a full-table scan; the Index operation with a field name indicates an indexed lookup; the Cost value (0.0 to 1.0) represents the estimated relative query cost, with values above 1.0 indicating Salesforce considers the query non-selective. The Salesforce consultant uses the Query Plan Tool to diagnose slow Visualforce pages, slow reports, and slow LWC components that call @wire(getRelatedRecords) against high-volume objects, identifies the specific WHERE clause conditions producing the TableScan operation, and restructures the query to use indexed fields or recommends a custom index request to Salesforce support for fields that cannot be restructured.
Salesforce integration architecture
Salesforce provides seven integration API patterns for connecting external systems, each optimized for a different data volume, latency, and directionality requirement. Selecting the wrong API produces integration architectures that work at low volume and fail under production load — an architect who uses the REST API to synchronize 500,000 records nightly via single-record GET requests produces 500,000 HTTP round-trips where a single Bulk API 2.0 job would produce one.
REST API, SOAP API, and Bulk API 2.0 selection
The Salesforce REST API provides JSON-based access to standard and custom objects via resource URLs: GET /services/data/v59.0/sobjects/Account/{id} retrieves a single record; POST /services/data/v59.0/sobjects/Account/ creates a record; PATCH /services/data/v59.0/sobjects/Account/{id} updates a field subset; POST /services/data/v59.0/composite/ executes up to 25 subrequests in a single HTTP call, with each subrequest referencing the results of prior subrequests by reference ID, reducing the round-trips required for related-record create sequences. REST API is the correct pattern for real-time, low-latency integrations (CRM data sync triggered by a user action in an external system, webhook-driven record creation) where data volume is under 10,000 records per operation.
The Bulk API 2.0 is the correct pattern for high-volume data operations: creating a bulk job (POST /services/data/v59.0/jobs/ingest/), uploading records as a CSV with a Content-Type of text/csv (PUT /services/data/v59.0/jobs/ingest/{jobId}/batches/), closing the job (PATCH /services/data/v59.0/jobs/ingest/{jobId} with {"state":"UploadComplete"}), and polling for completion (GET /services/data/v59.0/jobs/ingest/{jobId}) and downloading success and failure records. Bulk API 2.0 processes records in server-side batches without counting against the API governor limits that throttle REST API calls, making it the correct choice for nightly data synchronization jobs (50,000+ records), initial data migration loads, and periodic bulk enrichment operations.
Platform Events and Change Data Capture
Platform Events provide a publish-subscribe integration pattern for real-time event-driven communication between Salesforce and external systems: define a Platform Event object (Order_Shipped__e with fields for order ID, tracking number, and ship timestamp); publish from Apex (EventBus.publish(new Order_Shipped__e(Order_Id__c = orderId, Tracking_Number__c = tracking))) or from an external system via the REST API (POST /services/data/v59.0/sobjects/Order_Shipped__e/); subscribe from Apex (@AuraEnabled method using CometD long polling), from a record-triggered Flow (Subscribe to Platform Event trigger), or from an external system using the CometD streaming channel. Platform Events are the correct pattern for event-driven microservice communication where the publisher does not need to know about or wait for subscribers.
Change Data Capture (CDC) provides a streaming feed of all create, update, delete, and undelete operations on enabled Salesforce objects: subscribe to the CDC channel (/data/AccountChangeEvent) via CometD; each event payload includes the ChangeEventHeader with the changed fields list, the record ID, the transaction ID, and the change type (CREATE, UPDATE, DELETE, UNDELETE); the subscriber processes only the changed fields listed in changedFields rather than polling the REST API for the full record on every synchronization interval. CDC is the correct pattern for external data warehouse synchronization, external search index maintenance (Elasticsearch, Solr), and external cache invalidation where the external system needs to react to every Salesforce record change without polling.
Salesforce org design and release management
Salesforce org governance — the combination of sandbox strategy, deployment methodology, change management process, and governor limits management that determines whether the production org remains stable as the development team adds configuration and code — is the advisory function that is most invisible to the business stakeholders who approve the retainer budget. A production Salesforce org that has never had a formal change management process has typically accumulated configuration debt: production hotfixes that were never back-ported to the full sandbox, sandbox configurations that were never deployed to production because the change set failed mid-deployment, and metadata conflicts between org changes made by two developers working in the same sandbox without a version control baseline.
Salesforce DX and unlocked package architecture
Salesforce DX (SFDX) provides a source-driven development model for Salesforce metadata: a local project directory structure (force-app/main/default/ with subdirectories for classes/, lwc/, flows/, objects/, permissionsets/, profiles/) that stores all metadata as version-controlled files; the Salesforce CLI (sf project deploy start, sf project retrieve start) that syncs between the local project and scratch orgs or sandboxes; and Unlocked Packages, the deployment unit that groups related metadata into independently versioned, installable packages.
Unlocked package architecture for a mid-sized org: one package per business domain (Sales Automation, Service Cloud, Marketing Integration) with explicit package dependencies; a package.xml manifest that includes only the metadata in scope for each package; a CI/CD pipeline (GitHub Actions or Copado) that runs Apex test classes (minimum 75 percent code coverage for production deployment), validates the package version against the full sandbox, and deploys to production on merge to main. The Salesforce architect designs the package dependency tree to minimize coupling: cross-package references require an explicit dependency declaration in sfdx-project.json, and circular dependencies are not permitted, which forces the architect to resolve the coupling at design time rather than discovering it at deployment time.
CPQ and Revenue Cloud configuration
Salesforce CPQ (Configure, Price, Quote) and Revenue Cloud extend the standard Salesforce Opportunity and Quote objects with a product catalog, pricing engine, and quote approval workflow. The CPQ architecture centers on: Product and option configuration (Product objects with Product Features and Product Options that define valid configuration combinations; Option Constraints that enforce mutual exclusivity or co-requisite rules between options); Price Rules (Price Conditions that evaluate quote or quote line field values, Price Actions that set target field values when conditions are met — used to implement volume discounts, customer-specific pricing, and promotion rules); Quote Calculator Plugin (a Salesforce-supported JavaScript callback that the CPQ calculation engine invokes at defined stages: before/after calculate, before/after pricing, before/after custom action — used for complex pricing logic that price rules cannot express); and Approval processes (CPQ Approval Rules that evaluate discount percentage thresholds, quote total values, and custom field conditions to route quotes to the correct approval chain automatically).
HourTab for Salesforce retainers
Salesforce retainer work produces org stability, sales team productivity, and integration reliability — the governor limit exceptions that stop happening, the report that now loads in 1.2 seconds instead of 18, the lead assignment process that routes 100 percent of API-created leads correctly. The hours behind each outcome — the automation audit behind the governor limit elimination, the Query Plan Tool analysis behind the report performance improvement, the trigger framework refactoring behind the bulk data load reliability — are not visible to the VP of Sales, the IT director, or the Head of Revenue Operations without a work log that connects each hour block to the specific Salesforce function performed.
HourTab gives Salesforce consultants a retainer dashboard that their IT directors and Revenue Operations clients can bookmark without creating an account: the month’s committed hours, the hours consumed to date, and the work log entries that connect each hour block to the automation audit, the Apex trigger refactoring, the SOQL optimization, or the integration architecture session being worked on. When the IT director can see that 13 of the month’s 60 retainer hours went to Lead trigger refactoring and 9 went to Opportunity query plan analysis, the retainer renewal conversation is grounded in the actual distribution of Salesforce development work rather than an abstract sense of whether the platform advisory investment was worth the fee.
The retainer model works for Salesforce consulting because platform governance and ongoing development are continuous rather than project-scoped — every Salesforce release (three per year: Spring, Summer, Winter) introduces new platform features, deprecated APIs, and governor limit changes that require advisory evaluation; every business process change requires configuration and Flow architecture review; every integration partner update requires API compatibility verification. A monthly hour commitment provides the Salesforce consultant’s sustained availability across the full platform maintenance and development calendar.
Frequently asked questions
What does a Salesforce consultant on retainer typically do?
A Salesforce consultant on monthly retainer provides ongoing platform advisory and development: Salesforce admin configuration (automation architecture using Flow Builder, security model design, custom object schema, reports and dashboards); Apex development (trigger framework design with bulkification, batch and queueable jobs for large data processing, SOQL query optimization); Lightning Web Component development (reactive component architecture, wire service integration, Lightning Message Service for cross-component communication); and integration architecture (REST API, Bulk API 2.0, Platform Events, and Change Data Capture selection and implementation). The retainer typically also covers org design advisory: sandbox strategy, Salesforce DX deployment pipeline, unlocked package architecture, and governor limits management.
What Salesforce work is most commonly underlogged?
The most systematically underlogged categories are automation architecture audits (mapping all active automations on a single object, identifying execution order conflicts and governor limit violations — typically 8 to 20 hours of org analysis invisible in the audit report); SOQL query optimization (Query Plan Tool analysis and WHERE clause restructuring — typically 4 to 12 hours per problematic query invisible in the page load improvement); Apex trigger framework design (designing and implementing the trigger dispatcher pattern and bulkified handler classes — typically 12 to 25 hours invisible in the elimination of governor limit exceptions); and security model design (mapping access requirements to the correct combination of OWD, role hierarchy, sharing rules, and permission sets — typically 10 to 20 hours invisible in the security configuration document). Detailed work log entries that capture the specific object, violation, and architectural change behind each hour block make this invisible platform investment visible.
What should a Salesforce retainer agreement include?
Retainer agreements should specify: scope boundary between advisory, configuration, and Apex development; system admin access level required to perform scoped work; deployment environment authority (sandbox-only vs. production deployment); IP ownership for Apex code and LWC components; and a shared work log that documents each configuration session, code review, and architecture advisory. Monthly retainer amounts for Salesforce advisory and development support typically range from $8,000 to $20,000 per month for admin and configuration retainers, increasing to $15,000 to $35,000 per month for full-stack retainers covering Apex, LWC, and integration architecture.
What are typical retainer rates for Salesforce consultants?
Salesforce admins and junior developers with 2 to 4 years of experience and Administrator and Platform Developer I certifications typically bill $75 to $135 per hour. Experienced Salesforce developers with 5 to 9 years of experience, Platform Developer II certification, and expertise in Apex, LWC, and integration architecture typically bill $125 to $225 per hour. Senior Salesforce architects and Certified Technical Architects (CTA) with 10 to 15 years of experience typically bill $200 to $375 per hour. Salesforce consulting firms typically bill $150 to $300 per hour. Monthly retainer amounts range from $8,000 to $18,000 per month for admin retainers, increasing to $20,000 to $45,000 per month for architect-level retainers covering org strategy and full-stack development.
How should Salesforce retainer hours be logged?
Work log entries should capture the advisory category (admin configuration, Apex development, LWC development, integration architecture, org design), the specific object or system, the task, and the finding or deliverable. Example: “Apex Development — Lead trigger refactoring. Consolidated three conflicting Lead triggers into a single bulk-safe trigger dispatcher. Identified SOQL-in-loop violation producing 200 queries per bulk transaction (was hitting governor limit at 101-record batches); redesigned as TriggerHandler with Set-based SOQL outside loop; moved future method call to queueable job accepting List<Id>. Deployed to sandbox, 200-record bulk insert test: 0 governor limit exceptions (was 47). 13 hours.”