# Free Salesforce Platform Developer I Practice Questions

*Last updated September 2026 · https://www.certifyforce.com/salesforce-platform-developer-1-practice-exam/free-questions*

18 free Platform Developer I practice questions from the CertifyForce bank of 312 reviewed questions, spread across the 4 official exam sections in proportion to their weight. Each has the correct answer, an explanation, and the official documentation it was verified against.

## Developer Fundamentals (27%)

### Question 1

Cloud Kicks must recalculate a field on 8 million Order__c records. A developer's synchronous class fails immediately. What should the developer do?

- A. Use a SOQL for loop inside a synchronous method, since the for loop streams records in batches instead of loading them all into heap at once.
- B. Use a future method instead, because asynchronous Apex receives higher governor limits than a synchronous transaction.
- C. Use Batch Apex with a Database.QueryLocator start method, which can return up to 50 million records processed across separate transactions.
- D. Ask Salesforce Support to manually raise the org's 50,000 record synchronous query limit for this specific batch job.

**Correct answer:** C. Use Batch Apex with a Database.QueryLocator start method, which can return up to 50 million records processed across separate transactions.

**Explanation:** A single transaction may retrieve only 50,000 records with SOQL, so a volume this large has to be split: Batch Apex whose start method returns a Database.QueryLocator can cover up to 50 million records and hands them to execute in chunks, each chunk running as its own transaction with a fresh set of limits. A SOQL for loop protects heap by processing results in chunks of 200 within one transaction, but the 50,000 record retrieval limit still applies. A future method is asynchronous and gets higher limits for some resources, but its retrieval ceiling is still 50,000 records, and it cannot accept sObject arguments. Governor limits are a multitenancy protection, so Support does not raise the query row limit for an org.

**Sources:** [Use Batch Apex | Apex Developer Guide](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_batch_interface.htm), [Execution Governors and Limits | Apex Developer Guide](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_gov_limits.htm)

### Question 2

AW Computing needs the Account record to display the total amount of all related Shipment__c records. Shipment__c is related to Account through a lookup relationship that must stay a lookup because shipments can be created before an account is known. Which two approaches should the developer consider? Choose 2 answers.

- A. Add a roll-up summary field on Account that summarizes the Shipment__c lookup relationship.
- B. Use a record-triggered flow on Shipment__c to recalculate and update the total on the related Account.
- C. Use an Apex trigger on Shipment__c that aggregates shipment amounts and updates the Account.
- D. Add a cross-object formula field on Account that references the related Shipment__c records.
- E. Convert the lookup relationship to a master-detail relationship and add a roll-up summary field.

**Correct answers:** B. Use a record-triggered flow on Shipment__c to recalculate and update the total on the related Account.; C. Use an Apex trigger on Shipment__c that aggregates shipment amounts and updates the Account.

**Explanation:** Roll-up summary fields are only available on the master side of a master-detail relationship, so with a lookup the aggregation must be maintained programmatically or declaratively with automation: a record-triggered flow or an Apex trigger on Shipment__c can recalculate the parent total on insert, update, and delete. Creating a roll-up summary over a lookup relationship is not offered by the platform. A cross-object formula field can only traverse upward to parent records, never aggregate child records. Converting the relationship to master-detail would make the Account value required on every shipment, which the stated requirement explicitly forbids.

**Sources:** [Optimize Roll-Up Summary Fields in Salesforce | Trailhead](https://trailhead.salesforce.com/content/learn/modules/point_click_business_logic/roll_up_summary_fields), [Object Relationships: Create & Manage | Trailhead](https://trailhead.salesforce.com/content/learn/modules/data_modeling/object_relationships)

### Question 3

A developer at Universal Containers is explaining how a page built with a Lightning Web Component and an Apex controller maps to the Model-View-Controller pattern. Which mapping is correct?

- A. sObjects are the model, the HTML template is the view, and the Apex controller mediates between them.
- B. The Apex class is the model, sObjects are the view, and the HTML template acts as the controller.
- C. The HTML template is the model, the JavaScript file is the view, and sObjects act as the controller layer.
- D. Validation rules are the model, page layouts are the view, and flows act as the controller in this pattern.

**Correct answer:** A. sObjects are the model, the HTML template is the view, and the Apex controller mediates between them.

**Explanation:** In the platform's component architecture the data layer is the schema and its sObjects, the presentation layer is the component markup that renders to the user, and server-side Apex methods exposed to the component mediate between them as the controller. Calling the Apex class the model and sObjects the view inverts the data and presentation layers. Treating markup as the model and sObjects as the controller misplaces every layer, since sObjects never contain presentation logic. Validation rules, page layouts, and flows are configuration features rather than a description of the MVC layers in a custom component.

**Sources:** [Introducing Aura Components | Lightning Aura Components Developer Guide](https://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/intro_framework.htm), [Lightning Web Components Developer Guide](https://developer.salesforce.com/docs/platform/lwc/overview)

### Question 4

A developer at Cumulus Financial has a trigger that runs a SOQL query inside a for loop over Trigger.new. The trigger works during manual testing but fails during a data load of 5,000 records. What should the developer do?

- A. Move the trigger logic into an @future method so the query limit no longer applies at all.
- B. Add a check on Limits.getQueries() and exit the loop early once the limit is close.
- C. Query the related records once before the loop into a Map keyed by ID and reuse the map.
- D. Ask the integration team to load the records one at a time instead of in bulk.

**Correct answer:** C. Query the related records once before the loop into a Map keyed by ID and reuse the map.

**Explanation:** Apex allows 100 SOQL queries per synchronous transaction, and a query inside a loop over a 200-record trigger batch exceeds that limit immediately; the bulkified pattern queries the related data once and stores it in a collection such as a Map keyed by ID for lookup inside the loop. An asynchronous method has higher limits but still enforces a query cap, so the same loop would eventually fail while also adding complexity and delay. Exiting the loop early when the limit is approached silently skips records and leaves data inconsistent. Loading records one at a time cripples throughput and does not fix the underlying code, which will fail again with any bulk operation.

**Sources:** [Execution Governors and Limits | Apex Developer Guide](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_gov_limits.htm)

### Question 5

A developer at Ursa Major Solar drafted an Apex class with Dev Assistant and now needs to move it into a sandbox for integration testing. What should the developer use to complete this step?

- A. Ask Dev Assistant to deploy the class directly, because deployment is one of its slash commands.
- B. Ask Dev Assistant to build a change set in the target sandbox org.
- C. Use the Salesforce CLI or the deploy command in the Salesforce extensions to deploy the class.
- D. Paste the code into the Developer Console in production and save it there directly.

**Correct answer:** C. Use the Salesforce CLI or the deploy command in the Salesforce extensions to deploy the class.

**Explanation:** Agentforce for Developers assists with authoring code; moving metadata between orgs is handled by the Salesforce CLI or the equivalent deploy action in the Salesforce extensions for Visual Studio Code. Dev Assistant has no deployment slash command, and it cannot create change sets in a target org. Pasting code into the Developer Console in production would bypass the sandbox testing the scenario requires and is not permitted for Apex classes in production, where code must be deployed with tests.

**Sources:** [Introducing Agentforce for Developers: Now Generally Available](https://developer.salesforce.com/blogs/2024/09/introducing-agentforce-for-developers), [Agentforce | Salesforce Developers](https://developer.salesforce.com/developer-centers/agentforce)

## Process Automation and Logic (28%)

### Question 6

An integration at Universal Containers inserts 500 records at a time. The business requires that valid records still save when a few records fail, and that each failure be logged with its error message. What should the developer implement?

- A. A single insert statement wrapped in a try-catch block that logs the DmlException message before moving to the next batch
- B. A loop that inserts the records one at a time, each insert wrapped in its own try-catch block so failures are isolated
- C. Database.insert with the allOrNone parameter set to true, catching the resulting DmlException and logging its message
- D. Database.insert with allOrNone set to false, then inspecting the returned Database.SaveResult list for failures

**Correct answer:** D. Database.insert with allOrNone set to false, then inspecting the returned Database.SaveResult list for failures

**Explanation:** Partial-success DML through the Database methods with allOrNone set to false saves the records that are valid and returns a result object per record, so the failures and their error messages can be logged while the rest of the batch persists. A plain insert statement is all-or-nothing, so one bad record rolls the whole list back and the caught exception reports only the first error. Inserting one record per iteration consumes one DML statement per record and breaks well before 500 records. Setting allOrNone to true makes the Database method behave like the DML statement, which defeats the partial-success requirement.

**Sources:** [Working with Data | Apex Database Module (DML)](https://trailhead.salesforce.com/content/learn/modules/apex_database/apex_database_dml), [Exceptions in Apex | Apex Developer Guide](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_exception_definition.htm)

### Question 7

Get Cloudy Consulting wants a before insert trigger to block a Contact whose Mailing Country is not on an approved list, and to show the user a message next to the record. What should the developer do?

- A. Call addError on the offending record in Trigger.new with the message to display.
- B. Throw an uncaught custom exception from the trigger whenever an offending record is found.
- C. Write the message with System.debug and return from the trigger.
- D. Insert a Task that describes the problem and let the contact save.

**Correct answer:** A. Call addError on the offending record in Trigger.new with the message to display.

**Explanation:** Calling addError on a specific record in Trigger.new marks only that record as failed, surfaces the message in the user interface, and in a bulk load lets the valid records in the same batch continue to save. Throwing an uncaught exception aborts the entire transaction, so every record in the batch fails and the user sees an unhandled exception rather than a helpful message. A debug statement is written to the log and is invisible to the user, and it does nothing to prevent the save. Creating a follow-up task documents the problem after the fact but still allows the bad data into the database.

**Sources:** [Trigger and Bulk Request Best Practices | Apex Developer Guide](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_triggers_bestpract.htm)

### Question 8

A developer at Universal Containers is writing an Apex action that a record-triggered flow will call when 200 records are saved at once. Which two considerations apply to the invocable method? Choose 2 answers.

- A. The method takes a single List parameter and returns a List, so the flow can pass the whole set of records in one call.
- B. A class can contain only one method annotated with InvocableMethod.
- C. The method must also be annotated as a future method so it does not consume the flow's limits.
- D. The returned List must contain exactly one element no matter how many inputs were passed in.
- E. The method must be declared private so that only Flow can call it.

**Correct answers:** A. The method takes a single List parameter and returns a List, so the flow can pass the whole set of records in one call.; B. A class can contain only one method annotated with InvocableMethod.

**Explanation:** An invocable method is designed for bulk processing: it accepts one list parameter and returns a list, which lets Flow hand it every record in the batch in a single call instead of one call per record, and Apex allows only one method with that annotation per class. Adding the future annotation is not required and would change the method into an asynchronous call that cannot return a value to the flow, while asynchronous transactions have governor limits of their own. When a value is returned, the output list must contain the same number of elements as the input list so Flow can match each result to its input, not a single element. An invocable method must be public or global; a private method is not visible to Flow at all.

**Sources:** [InvocableMethod Annotation | Apex Developer Guide](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_annotation_InvocableMethod.htm)

### Question 9

Cumulus Financial wants an Apex-backed search that finds a user-entered term across text fields on Account, Contact, and Case in a single operation and returns the matches grouped by object. What should the developer write?

- A. Three separate SOQL queries with LIKE filters against each object, with the results merged into a single Map in Apex code
- B. A SOSL search such as FIND 'term' IN ALL FIELDS RETURNING Account(Id, Name), Contact(Id, Name), Case(Id, Subject)
- C. One SOQL query with a WHERE clause that joins Account, Contact, and Case together on their common fields
- D. One SOQL query that combines a LIKE filter with parent-to-child subqueries reaching into all three related objects

**Correct answer:** B. A SOSL search such as FIND 'term' IN ALL FIELDS RETURNING Account(Id, Name), Contact(Id, Name), Case(Id, Subject)

**Explanation:** SOSL is the language designed for text searches that span multiple objects; a single FIND statement returns a list of lists of sObjects, with one inner list per object named in the RETURNING clause, and it counts as one of the 20 SOSL queries allowed per transaction. Running three SOQL queries with LIKE filters costs three queries, does not use the search index, and performs poorly on large data volumes. SOQL has no join syntax that combines unrelated objects in one WHERE clause. Subqueries only traverse defined parent-child relationships and cannot search independent objects such as Account, Contact, and Case together.

**Sources:** [SOQL and SOSL Queries | Apex Developer Guide](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/langCon_apex_SOQL.htm), [Salesforce Object Query Language (SOQL) | SOQL and SOSL Reference](https://developer.salesforce.com/docs/platform/salesforce-soql-sosl/guide/sforce-api-calls-soql.html)

### Question 10

Get Cloudy Consulting must support several discount calculation strategies that each apply different rules but expose the same method signature, and the strategy has to be selected at run time. Which approach should the developer use?

- A. Write one class with a large switch statement that branches to a private method for each discount strategy the business defines.
- B. Write a virtual class whose calculation method contains the default rules, and have each caller instantiate that class directly.
- C. Duplicate the calculation class once per strategy and choose between the copies using if-else logic inside the trigger handler.
- D. Define an Apex interface with the shared method signature, implement it per strategy, and code the caller against the interface.

**Correct answer:** D. Define an Apex interface with the shared method signature, implement it per strategy, and code the caller against the interface.

**Explanation:** An interface declares method signatures without implementations, so each strategy class implements it with its own logic and calling code can hold a reference of the interface type and invoke the right implementation polymorphically, which is the cleanest way to add new strategies without editing the caller. A single class built around a switch statement must be modified and retested every time a strategy is added. A virtual class that carries a default implementation is useful when subclasses share behavior, but it does not by itself let the caller work against a common type without inheritance from that specific base. Duplicating the class and branching with if-else multiplies the code that has to be maintained and tested.

**Sources:** [Interfaces | Apex Developer Guide](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/langCon_apex_interfaces.htm), [Access Modifiers | Apex Developer Guide](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_access_modifiers.htm)

## User Interface (25%)

### Question 11

A Lightning web component at Cumulus Financial must let a user jump from a search result to the full record page and, from another button, open a prefilled new Case creation page. Which two statements about achieving this are correct? Choose 2 answers.

- A. The component's class must extend NavigationMixin applied to LightningElement to call the navigation methods.
- B. Navigation to a record page uses a pageReference whose type is standard__recordPage with the recordId and actionName attributes.
- C. Field defaults for a new record are passed by calling window.open with a URL built from the record type Id and object API name.
- D. The component must import the lightning/navigation module and declare a navigate target in its js-meta.xml file.
- E. Navigation between pages in Lightning Experience requires a Visualforce page to act as an intermediary step in the flow.

**Correct answers:** A. The component's class must extend NavigationMixin applied to LightningElement to call the navigation methods.; B. Navigation to a record page uses a pageReference whose type is standard__recordPage with the recordId and actionName attributes.

**Explanation:** Navigation in a Lightning web component comes from the lightning/navigation module, and the class must be declared as extending NavigationMixin(LightningElement) so that the navigate and generateUrl methods are available. A record page is reached with a pageReference of type standard__recordPage carrying the recordId and an actionName such as view. Prefilled values for a new record are supplied through the state property of a standard__objectPage reference using defaultFieldValues, not by hand-building a URL for window.open. There is no navigate entry in the js-meta.xml file, and no Visualforce intermediary is required for navigation in Lightning Experience.

**Sources:** [Lightning Web Components Overview](https://developer.salesforce.com/docs/platform/lwc/overview)

### Question 12

Northern Trail Outfitters requires that an @AuraEnabled Apex method returning Case records respect the object and field permissions of the running user. Which two approaches accomplish this? Choose 2 answers.

- A. Query the Cases with a SOQL statement that includes WITH USER_MODE.
- B. Declare the Apex class with the with sharing keyword.
- C. Pass the query results to Security.stripInaccessible(AccessType.READABLE, cases) and return the stripped records.
- D. Execute the query through Database.query(queryString, AccessLevel.SYSTEM_MODE).
- E. Wrap the query in System.runAs() so it executes as the current user.

**Correct answers:** A. Query the Cases with a SOQL statement that includes WITH USER_MODE.; C. Pass the query results to Security.stripInaccessible(AccessType.READABLE, cases) and return the stripped records.

**Explanation:** WITH USER_MODE instructs the query engine to enforce the running user's object permissions, field-level security, and sharing rules, throwing a QueryException when access is missing. Security.stripInaccessible with AccessType.READABLE achieves a similar goal without an exception by removing fields and relationships the user cannot read from the returned records. The with sharing keyword addresses record visibility only and leaves object and field permissions unchecked. Database.query with AccessLevel.SYSTEM_MODE deliberately bypasses the user's permissions, which is the opposite of the requirement. System.runAs is a test-context-only construct and cannot be used in a method that runs in production.

**Sources:** [Salesforce Application Security Guide: Apex Security](https://developer.salesforce.com/docs/atlas.en-us.securityImplGuide.meta/securityImplGuide/salesforce_security_guide_apex_security.htm), [Security Overview](https://help.salesforce.com/s/articleView?id=sf.security_overview.htm&type=5)

### Question 13

Universal Containers needs a record-triggered flow to run a complex pricing calculation that cannot be expressed declaratively. What should the developer build so the flow can run the calculation?

- A. An Apex class with an @AuraEnabled method that the flow calls through an action element
- B. An Apex class with a @future method that the flow calls through an action element
- C. An Apex class with a method annotated @InvocableMethod, which appears as an action in the flow
- D. An Apex class that implements the Process.Plugin interface used by the retired Process Builder framework

**Correct answer:** C. An Apex class with a method annotated @InvocableMethod, which appears as an action in the flow

**Explanation:** The @InvocableMethod annotation is what publishes an Apex method to the Flow action palette so a flow can call it and pass data in and out. @AuraEnabled exposes Apex to Lightning components, not to Flow. A @future method can be launched from a flow only indirectly and cannot return values to it, so it cannot supply calculated output. Process.Plugin is the legacy interface associated with the retired Process Builder and is not the current way to expose Apex to Flow.

**Sources:** [InvocableMethod Annotation | Apex Developer Guide](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_annotation_InvocableMethod.htm), [Create Custom Actions Using Apex InvocableMethod (Agentforce Actions)](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-invocablemethod.html)

### Question 14

A developer is designing the events for a reusable Lightning web component that will be distributed to several teams at Cloud Kicks. Which two practices should the developer follow? Choose 2 answers.

- A. Pass primitive values in the event's detail property rather than mutable object references
- B. Set composed: true on the event so ancestor components outside the shadow tree can listen without extra wiring
- C. Handle each event as close as possible to where it is dispatched, re-dispatching only when necessary
- D. Keep the component's state in a shared JavaScript module that consumers import and read directly inside renderedCallback()
- E. Prefix each event name with on when constructing the CustomEvent so template handlers can find it

**Correct answers:** A. Pass primitive values in the event's detail property rather than mutable object references; C. Handle each event as close as possible to where it is dispatched, re-dispatching only when necessary

**Explanation:** Sending primitives in detail avoids leaking a mutable reference, because the receiver can change an object's properties and silently affect the dispatching component's state. Handling an event as near to its source as possible, and re-dispatching from the intermediate component when the data must go further, keeps each component's public event contract explicit. Making every event composed is discouraged since composed events pierce shadow boundaries and destroy encapsulation. Shared mutable module state hides dependencies between components and is not reactive. The on prefix belongs only on the handler attribute in the template, never in the CustomEvent name itself.

**Sources:** [Events Best Practices | Lightning Web Components Developer Guide](https://developer.salesforce.com/docs/platform/lwc/guide/events-best-practices.html), [Create and Dispatch Events | Lightning Web Components Developer Guide](https://developer.salesforce.com/docs/platform/lwc/guide/events-create-dispatch.html)

## Testing, Debugging, and Deployment (20%)

### Question 15

A developer is writing a test for a class that calls System.enqueueJob() and also performs a large number of SOQL queries as part of its setup. The developer needs the setup data creation to be excluded from the code under test's governor limits and needs the queued job to complete before assertions run. What should the developer do?

- A. Annotate the test method with @isTest(SeeAllData=true) so the setup data is read rather than created
- B. Create the setup data before Test.startTest(), then wrap the tested code in startTest() and stopTest(), and assert after
- C. Call Database.executeBatch() inside the test method so the batch job's execute method runs immediately for the assertions
- D. Place the assertions inside the Queueable class's execute method so they run in the same asynchronous transaction

**Correct answer:** B. Create the setup data before Test.startTest(), then wrap the tested code in startTest() and stopTest(), and assert after

**Explanation:** Test.startTest() gives the code under test a fresh set of governor limits, so the queries and DML used to build setup data do not count against it, and Test.stopTest() forces any asynchronous work enqueued since Test.startTest() to run synchronously, so assertions placed after Test.stopTest() see the results. SeeAllData=true makes the test depend on whatever data happens to exist in the org and does not reset limits. Calling Database.executeBatch() runs a different kind of job and still would not execute before Test.stopTest(). Putting assertions inside the Queueable's execute method pollutes production code with test logic and failures there would not be reported as test failures in a useful way.

**Sources:** [Testing Apex | Apex Developer Guide](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_testing.htm), [Apex Testing (Trailhead)](https://trailhead.salesforce.com/content/learn/modules/apex_testing)

### Question 16

A developer needs asynchronous logic that accepts a List of Contact records, can be monitored by its job ID, and must enqueue a follow-up asynchronous job when it completes. Which implementation meets all three requirements?

- A. A method annotated with @future(callout=true) that accepts the List of Contacts and calls a second @future method at the end
- B. A class that implements Queueable, holding the Contacts as a member variable and calling System.enqueueJob() for the follow-up job in execute()
- C. A method annotated with @future that accepts a Set of Contact Ids and returns the job ID to the caller
- D. A Schedulable class that is scheduled one minute in the future and re-schedules itself at the end of its execute method

**Correct answer:** B. A class that implements Queueable, holding the Contacts as a member variable and calling System.enqueueJob() for the follow-up job in execute()

**Explanation:** Queueable Apex is the only one of these that satisfies all three requirements: the class can hold non-primitive members such as a List of sObjects, System.enqueueJob() returns an AsyncApexJob ID that can be queried or viewed on the Apex Jobs page, and a running Queueable can chain one follow-up job by calling System.enqueueJob() from its execute method. Future methods accept only primitive parameters, so they cannot take a List of Contacts, they return void rather than a job ID, and one future method cannot call another. Passing a Set of Ids to a future method satisfies the parameter rule but still returns nothing the caller can monitor and cannot chain. Re-scheduling a Schedulable class is a workaround that provides no direct chaining semantics and is constrained by the org's limit on scheduled Apex jobs.

**Sources:** [Asynchronous Apex | Apex Developer Guide](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_async_processing.htm)

### Question 17

Each developer at Northern Trail Outfitters needs an isolated environment that contains the production configuration but no production records, is inexpensive, and can be refreshed as often as once a day when the developer wants a clean starting point. Which environment matches these requirements?

- A. A Partial Copy sandbox, which is licensed for individual developer use
- B. A Full sandbox, one per developer, refreshed daily
- C. A Developer sandbox, which copies configuration only and refreshes daily
- D. A Developer Edition org linked to production through a deployment connection

**Correct answer:** C. A Developer sandbox, which copies configuration only and refreshes daily

**Explanation:** Developer sandboxes copy the production metadata without production records, carry a small data and file storage allocation, and can be refreshed daily, which is exactly the lightweight per-developer environment described. Partial Copy sandboxes copy sampled production data and have a longer refresh interval, so they are provisioned sparingly rather than one per developer. Full sandboxes carry the longest refresh interval by far and cannot be refreshed daily. A Developer Edition org is a standalone free org; it does not copy the production configuration and cannot be joined to production by a deployment connection the way a sandbox can.

**Sources:** [Deploy Overview](https://help.salesforce.com/s/articleView?id=sf.deploy_overview.htm&type=5)

### Question 18

A contractor joining Northern Trail Outfitters works on a locked-down laptop where the Salesforce CLI and an IDE cannot be installed, but the contractor still needs a full development environment with source control to work on the team's project. What should the developer recommend?

- A. Grant the contractor the System Administrator profile in production, and have them make and test their code changes directly there
- B. Have the contractor email their code changes to a team member, who then applies and tests them in a sandbox environment
- C. Ask the contractor to use the Developer Console, which provides full Git integration and an installable package manager
- D. Recommend Agentforce Vibes IDE, the browser-based IDE with Salesforce Extensions, the CLI, and GitHub built in

**Correct answer:** D. Recommend Agentforce Vibes IDE, the browser-based IDE with Salesforce Extensions, the CLI, and GitHub built in

**Explanation:** Agentforce Vibes IDE (Salesforce's rebrand of Code Builder) is a browser-based development environment available in sandbox orgs that comes preinstalled with Salesforce Extensions, the Salesforce CLI, and GitHub integration, so it gives the contractor the familiar developer tooling and source control workflow without installing anything locally. Editing Apex directly in production is against basic release practice and does not provide source control. Emailing changes for someone else to apply loses history and review and does not scale. The Developer Console has neither Git integration nor a package manager, so it cannot fill the gap.

**Sources:** [Get Started | Agentforce Vibes IDE](https://developer.salesforce.com/docs/platform/code-builder/guide), [Developer Console](https://help.salesforce.com/s/articleView?id=sf.code_dev_console.htm&type=5)

## Related pages

- [Salesforce Platform Developer I practice exam](https://www.certifyforce.com/salesforce-platform-developer-1-practice-exam)
- [Practice exam packs](https://www.certifyforce.com/practice-exams)
- [Official Platform Developer I exam guide](https://help.salesforce.com/s/articleView?language=en_US&id=005298965&type=1)
