Skip to content

Salesforce Development Fundamentals: Part 1 - The Developer Mindset & Toolkit

Updated 24/04/2026

Salesforce Dev Hero Image

You’ve built a strong foundation. You understand the Salesforce data model, security, automation with Flow, approval processes, custom metadata, and sandbox governance. You can configure an org to support real business processes, and you know how to move those changes safely through environments. It has been a deliberate move to guide you through the fundamentals and administration first, giving you a broad and deep understanding of the platform before you ever write a line of code. The best Salesforce developers are those who know when not to write code, relying on their administrative knowledge to avoid building costly, hard-to-maintain custom solutions for problems that declarative tools can solve out of the box.

Now comes the question every capable admin eventually asks: what happens when clicks aren’t enough?

This article is the bridge. It won’t turn you into a developer overnight, but it will shift your mental model from “configuration only” to “configuration AND code,” give you a working local development environment, and walk you through the professional workflow that Salesforce developers use every day. By the end, you’ll understand when to reach for code, how your tools fit together, and what the development lifecycle actually looks like from the inside.


🧭 Reframing “Development” on Salesforce

Section titled “🧭 Reframing “Development” on Salesforce”

For many, the word “developer” conjures images of complex code, command-line interfaces, and a world far removed from the familiar point-and-click interface of Salesforce. But on the Salesforce platform, the journey from administrator to developer is more of an evolution than a binary jump. It’s about shifting your mental model from “clicks only” to “clicks AND code.”

Salesforce development isn’t about abandoning everything you know; it’s about extending it. The same data model, the same security settings, the same business processes you’ve configured as an admin are the foundation upon which developers build. We use new tools and languages to express logic and create user experiences that are simply not possible with declarative tools alone. Many of the most effective Salesforce developers started their careers as administrators, bringing invaluable business context and platform understanding to their coding endeavors.

The most important skill in Salesforce development isn’t writing code: it’s knowing when to write it. Salesforce invests heavily in declarative tools, and for good reason. Flow, validation rules, formula fields, and approval processes handle a huge range of business requirements without code. Code should be the exception, not the default.

Use declarative tools (Flow, validation rules, formula fields) when:

  • The logic is straightforward and well supported by the tool (field updates, record creation, simple branching, scheduled actions)
  • Non-developers need to understand and maintain the automation
  • The requirement maps cleanly to a standard Flow pattern (screen flows, record-triggered flows, scheduled flows)
  • You need rapid iteration and the logic may change frequently

Reach for Apex when:

  • The logic involves complex cross-object operations that would result in a deeply nested or fragile Flow (e.g., recalculating rollup values across multiple relationship levels based on conditional criteria)
  • You need to call external APIs or web services (HTTP callouts, REST/SOAP integrations)
  • Performance is critical and you need fine-grained control over query patterns and data processing
  • You’re processing large data volumes in batch (thousands or millions of records)
  • The business logic requires transaction control that Flow doesn’t support (partial commits, savepoints, custom error handling)
  • You need a custom user interface that goes beyond what standard Lightning pages and screen flows can deliver

Reach for Lightning Web Components (LWC) when:

  • You need a custom UI component that doesn’t exist in the standard Lightning component library
  • The user experience requires real-time interactivity, dynamic rendering, or client-side logic
  • You require highly reusable components with layers that will appear on multiple pages or apps

In practice, most Salesforce solutions use a mix of declarative and programmatic tools. Understanding how they interact is just as important as knowing how to use each one individually.

Common patterns include:

  • Flow calls Apex: A Flow handles the user-facing orchestration (screen inputs, branching logic, record creation) but invokes an Apex action for a specific step that needs code, like a complex calculation, an API callout, or a bulk data operation. This is done via Invocable Apex methods.
  • Apex fires, Flow reacts: An Apex trigger modifies data, and a record-triggered Flow picks up the change and handles downstream automation. Both execute within the same transaction.
  • LWC calls Apex: A Lightning Web Component provides the user interface, and Apex methods (exposed via @AuraEnabled) serve as the backend, handling data queries, business logic, and DML operations.
  • Apex enriches configuration: Custom metadata and custom settings (which you covered in Administration Part 4) store configuration that Apex reads at runtime. The admin controls the values; the code controls the behaviour.

This hybrid approach lets each tool do what it’s best at. Declarative tools handle orchestration and simple logic; code handles complexity, integrations, and performance-sensitive operations.


Every craft requires its tools. As an admin, your primary tool has been the browser: Setup pages, Flow Builder, the Lightning App Builder. As a developer, you’ll add a local development environment to your workflow. The browser doesn’t go away, but most of your coding work happens locally, with changes deployed to Salesforce when they’re ready.

Three tools form the foundation of every Salesforce developer’s setup:

The Salesforce CLI is your command centre. It’s a command-line tool that lets you interact with Salesforce orgs from your local machine. You’ll use it to:

  • Authenticate to sandboxes, scratch orgs, and production orgs
  • Retrieve metadata (your configurations, Apex classes, and components) from an org to your local machine
  • Deploy code and metadata from your local machine back to an org
  • Run Apex tests
  • Create scratch orgs for isolated development
  • Execute anonymous Apex for quick scripts and debugging
  • Execute SOQL queries and manipulate records directly from your terminal

The CLI replaces the browser for many tasks that admins traditionally do in Setup. Instead of clicking through menus to deploy a change, you run a command. This might feel unfamiliar at first, but it becomes faster and more repeatable than the UI for most development tasks.

VS Code is your code editor and the central hub of your Salesforce development workflow. It matters because it gives you a consistent, extensible environment for writing, testing, and version‑controlling all your Salesforce code. Instead of bouncing between the Developer Console, browser tabs, and external tools, you keep everything in one place—making it easier to navigate, debug, and collaborate on real projects.

While Salesforce has a built-in Developer Console (accessible from Setup), professional development happens in VS Code. It provides:

  • Syntax highlighting and intelligent autocomplete for Apex, SOQL, HTML, JavaScript, and CSS
  • An integrated terminal for running CLI commands without leaving the editor
  • A file explorer for navigating your project structure
  • Debugging tools for stepping through Apex code
  • Git integration for version control
  • Extensions for almost anything else you might need

Think of VS Code as the equivalent of Flow Builder, but for code. It’s where you spend most of your working day.

To help get up to speed with Visual Studio Code, check out the Quick Start: Visual Studio Code for Salesforce Development Trailhead project. This guided module walks you through installing VS Code, setting up the Salesforce Extension Pack, connecting to your Salesforce org, and running your first commands. It’s the perfect hands-on introduction to the editor and tools you’ll use daily as a Salesforce developer.

The Salesforce Extension Pack is what turns VS Code from a generic text editor into a full fledged Salesforce development environment. It matters because it gives you deep, first‑class support for Salesforce languages and tools right inside your editor, so you don’t have to juggle between the UI and your IDE. With this pack installed, almost every core Salesforce development task, from writing Apex to querying data can happen in a single, familiar workspace.

This extension pack is what makes VS Code understand Salesforce. Without it, VS Code is just a generic text editor. With it, you get:

  • Apex language support (autocomplete, error checking, go-to-definition)
  • SOQL language support and an inline query editor
  • Lightning Web Component support (HTML templates, JavaScript controllers)
  • Commands to retrieve and deploy metadata directly from the editor
  • Org Browser to explore your connected org’s metadata without leaving VS Code
  • Apex Replay Debugger for stepping through debug logs

A few more tools you’ll see across professional Salesforce teams. None are required, but knowing they exist will save you time.

  • Salesforce Inspector / Inspector Reloaded: Browser extensions that surface org limits, run inline SOQL, edit records in bulk, and inspect metadata directly from any Salesforce page. Already familiar to many admins; just as useful for developers.
  • Apex Replay Debugger: Bundled with the Extension Pack. Capture a debug log when your code runs, then “replay” it locally with breakpoints, variable inspection, and step-through navigation — without re-running the transaction.
  • Apex PMD / SFDX Scanner: Static-analysis tools that flag bug patterns, security issues (SOQL injection, missing CRUD/FLS checks), and style problems before you commit. Most teams wire them into pre-commit hooks or CI.
  • Prettier (with prettier-plugin-apex): Consistent code formatting across Apex, JavaScript, and HTML so your diffs only show real changes, not whitespace noise.
  • Code Builder: Salesforce’s browser-hosted, fully-configured VS Code environment. Useful when you can’t install software locally (locked-down corporate machines) or need a quick, ephemeral workspace tied to an org.

Salesforce now ships several AI tools targeted at developers:

  • Agentforce Vibes brings agent-driven workflows into VS Code, so you can describe a change and have it scaffold the metadata, classes, and tests.
  • Einstein for Developers offers in-IDE Apex code generation and explanation grounded in your project context.
  • Most general-purpose AI coding assistants also work well against Salesforce projects once the Extension Pack is installed.

These are accelerators, not substitutes for understanding the platform — the chapters that follow are still the foundation you’ll lean on when reviewing what an AI assistant produces. For a deeper look at how AI is changing the developer role, see the companion article: AI & the Salesforce Developer.

Setting up a Salesforce development environment is a one‑time process, but it’s the foundation for everything you’ll build. Once configured, the same toolchain persists across projects and orgs, letting you move quickly from “Hello World” to real features.

  1. Install the Salesforce CLI

    Terminal window
    sf --version
    • You should see a version number (e.g., @salesforce/cli/2.x.x). If you see “command not found,” the installation didn’t complete. Revisit the installer
  2. Install Visual Studio Code

    • Download from code.visualstudio.com
    • Install like any other application. VS Code is free and runs on macOS, Windows, and Linux
  3. Install the Salesforce Extension Pack

    • Open VS Code
    • Open the Extensions panel (click the Extensions icon in the left sidebar, or press Cmd+Shift+X on Mac / Ctrl+Shift+X on Windows)
    • Search for “Salesforce Extension Pack” and click Install
    • This installs several extensions at once: Apex, Apex Replay Debugger, Aura Components, Lightning Web Components, SOQL, and the Salesforce CLI Integration
  4. Authenticate to Your Org

    • Open the VS Code Command Palette (Cmd+Shift+P on Mac / Ctrl+Shift+P on Windows)
    • Type “SFDX: Authorize an Org” and select it
    • Choose the login URL (use https://login.salesforce.com for production/developer orgs, or https://test.salesforce.com for sandboxes)
    • A browser window opens. Log in to your Salesforce org. Once authenticated, VS Code is connected
    • Alternatively, from the terminal:
    Terminal window
    sf org login web --alias my-sandbox --instance-url https://test.salesforce.com
  5. Create a Salesforce Project

    • Open the Command Palette and type “SFDX: Create Project”
    • Choose Standard project type
    • Give it a name (e.g., my-salesforce-project)
    • VS Code creates a project structure with the necessary configuration files
    • Alternatively, from the terminal:
    Terminal window
    sf project generate --name my-salesforce-project
  6. Initialize Source Control (or Clone Existing Repo)

    • If this is a new project, initialize Git in the project directory so changes are tracked from day one:
    Terminal window
    cd my-salesforce-project
    git init
    git add .
    git commit -m "Initial Salesforce DX project setup"
    • If your team already has a repository, clone it instead of running git init:
    Terminal window
    git clone <your-repo-url>
    cd <repo-name>
    • If you initialized a new repo and want to publish it:
    Terminal window
    git branch -M main
    git remote add origin <your-repo-url>
    git push -u origin main
  7. Retrieve Metadata and Validate Your Workflow

    • Pull a small set of metadata from your org to confirm your local setup is working end to end
    • Example:
    Terminal window
    sf project retrieve start --metadata "ApexClass:MyFirstClass"
    • Then deploy a safe test change (or deploy back the retrieved metadata) to verify your auth, project config, and CLI workflow
    • This gives you confidence that your environment is ready before you start real feature work

After these steps, you have a local project connected to a Salesforce org. You can retrieve metadata, write code, and deploy changes, all from VS Code.

For a step-by-step walkthrough, you can also complete the Salesforce CLI Setup Guide Trailhead module, which covers setting up your environment and building your first project. Or use the Quick Start: Salesforce DX trailhead project.

When you create a Salesforce project, the CLI generates a specific directory structure. Understanding this structure is important because it maps directly to the metadata you’ve been working with as an admin in Setup.

my-salesforce-project/
├── force-app/
│ └── main/
│ └── default/
│ ├── classes/ ← Apex classes (.cls + .cls-meta.xml)
│ ├── triggers/ ← Apex triggers (.trigger + .trigger-meta.xml)
│ ├── lwc/ ← Lightning Web Components
│ ├── objects/ ← Custom objects and fields
│ ├── flows/ ← Flow definitions
│ ├── layouts/ ← Page layouts
│ ├── permissionsets/ ← Permission sets
│ └── ... ← Other metadata types
├── sfdx-project.json ← Project configuration
├── .forceignore ← Files to exclude from deployment
└── package.json ← Node.js dependencies (if using LWC)

The key file is sfdx-project.json. It tells the CLI where your source code lives and which API version to use:

{
"packageDirectories": [
{
"path": "force-app",
"default": true
}
],
"namespace": "",
"sfdcLoginUrl": "https://login.salesforce.com",
"sourceApiVersion": "62.0"
}

In a typical unmanaged project, namespace is left blank. The force-app directory is the default location for your source, and sourceApiVersion controls which Salesforce metadata API version the project uses.

The sourceApiVersion field deserves a special mention: it pins your project to a specific Salesforce API release. We cover what that means, plus the broader topic of metadata formats and the package.xml manifest, in Understanding Salesforce Metadata below.

Every piece of metadata in your org has a corresponding file in this structure. The Apex class you see in Setup → Apex Classes is a .cls file in the classes directory. The Flow you built in Flow Builder is an XML file in flows. This is the core insight: everything in Salesforce is metadata, and metadata is just files. When you work locally, you’re editing those files directly instead of clicking through Setup.


As an admin, you’re used to making changes directly in the org. As a developer, the workflow shifts: you pull metadata to your local machine, make changes locally, then push them back. This retrieve‑edit‑deploy cycle is the heartbeat of Salesforce development.

To pull metadata from your org to your local project, you have several options:

Using the Command Line:

Terminal window
# Retrieve a specific Apex class
sf project retrieve start --metadata ApexClass:MyClassName
# Retrieve a specific object and all its fields
sf project retrieve start --metadata CustomObject:Expense_Claim__c
# Retrieve using a manifest (package.xml) file
sf project retrieve start --manifest manifest/package.xml
# Retrieve everything in your project's package directories
sf project retrieve start

Using the VS Code UI:

  • Right-Click Retrieve: If the metadata file already exists in your local project, you can right-click the file (or its parent folder) in the VS Code Explorer and select SFDX: Retrieve Source from Org. This is often the fastest way to pull down changes made directly in Setup.
  • Org Browser: You can use the Org Browser (the cloud icon in the VS Code sidebar) to visually explore all metadata in your connected org and retrieve specific components with a single click.

To push local changes back to your org, you have similar options:

Using the Command Line:

Terminal window
# Deploy everything in your project
sf project deploy start
# Deploy a specific file
sf project deploy start --source-dir force-app/main/default/classes/MyClassName.cls
# Deploy using a manifest (package.xml) file
sf project deploy start --manifest manifest/package.xml
# Deploy and run all tests (required for production deployments)
sf project deploy start --test-level RunAllTestsInOrg

Using the VS Code UI:

  • Right-Click Deploy: Just like retrieving, you can right-click a file (or its parent folder) in the VS Code Explorer and select SFDX: Deploy Source to Org. This is the standard, everyday way to push an individual file you’ve just edited (like a new Apex class) directly up to your sandbox or scratch org.

When working with scratch orgs or sandboxes that have source tracking enabled, the CLI automatically tracks what’s changed on both sides (your local files and the org). This makes it easy to stay in sync:

Terminal window
# See what's changed locally and in the org
sf project deploy preview
sf project retrieve preview
# Push local changes to the org
sf project deploy start
# Pull org changes to your local project
sf project retrieve start

Source tracking is particularly useful when you make some changes locally (Apex code) and some changes in the org (a new field via Setup), and need to keep both sides synchronised.


🏗️ Scratch Orgs vs Sandboxes for Development

Section titled “🏗️ Scratch Orgs vs Sandboxes for Development”

Developers often use sandboxes alongside scratch orgs, but scratch orgs add a second, more source-driven option.

FeatureScratch OrgsDeveloper Sandboxes
Created fromA Dev Hub-enabled orgProduction org
LifespanTemporary; 1–30 days, with a 7-day defaultPersistent until refreshed or deleted
DataNo copied production data by default; seed your own test dataCopies configuration from production; some sandbox types can include data
Source trackingBuilt-inAvailable in some workflows when enabled
CostDoes not consume sandbox entitlementsUses available sandbox entitlement
ConfigurationDefined in a scratch org definition fileBased on the selected sandbox type or clone
Best forFeature development, CI/CD, isolated testingUAT, integration testing, training, longer-lived work

Scratch orgs are disposable, purpose-built environments. You define the features and settings you need in a JSON file, create the org quickly, deploy your source, test, and delete it when you are done. They work especially well for feature branches and CI/CD pipelines because they start in a known, repeatable state.

Sandboxes are still the better choice when you need a longer-lived environment, production-like data, or a place for user acceptance testing and integration testing.

To use scratch orgs, you need a Dev Hub org with the Dev Hub feature enabled. In many setups, this is a production org or a dedicated Partner Business Org.

  1. Enable Dev Hub

    • In your production org: Setup → Development → Dev Hub → Enable
  2. Authenticate to the Dev Hub

    Terminal window
    sf org login web --alias my-devhub --set-default-dev-hub
  3. Create a Scratch Org Definition Create a file called config/project-scratch-def.json in your project:

    {
    "orgName": "My Feature Org",
    "edition": "Developer",
    "features": ["EnableSetPasswordInApi"],
    "settings": {
    "lightningExperienceSettings": {
    "enableS1DesktopEnabled": true
    },
    "mobileSettings": {
    "enableS1EncryptedStoragePref2": false
    }
    }
    }
  4. Create the Scratch Org

    Terminal window
    sf org create scratch --definition-file config/project-scratch-def.json --alias my-feature-org --duration-days 7 --set-default
  5. Push Your Code

    Terminal window
    sf project deploy start
  6. Open the Org

    Terminal window
    sf org open

The scratch org is now running with your code deployed. When you’re done, delete it:

Terminal window
sf org delete scratch --target-org my-feature-org --no-prompt

🛠️ The Development Workflow: End to End

Section titled “🛠️ The Development Workflow: End to End”

Let’s put it all together. Here’s how a typical development task flows from a business requirement to a deployed solution. This isn’t theoretical; it’s the workflow you’ll follow for every piece of code you write.

Imagine this requirement:

“When an Expense Claim is submitted for approval, if the amount exceeds $10,000, automatically create a Compliance Review task assigned to the Finance Compliance team.”

As an admin, you’d evaluate whether Flow can handle this. In this case, Flow probably can: a record-triggered flow on Expense_Claim__c that checks the amount and creates a Task. But imagine the requirement grows: the threshold varies by department, the compliance team assignment depends on the expense category and the submitter’s region, and the task description needs to include data from three related objects. At some point, the Flow becomes unwieldy. That’s when you’d reach for Apex.

Here’s how the development workflow would look:

  1. Create or Switch to a Feature Branch

    Start by creating a Git branch for your work. This isolates your changes from the main codebase:

    Terminal window
    git checkout -b feature/compliance-review-task
  2. Set Up Your Development Environment

    Either create a fresh scratch org or connect to your developer sandbox:

    Terminal window
    # Option A: Create a scratch org
    sf org create scratch --definition-file config/project-scratch-def.json --alias compliance-feature --duration-days 7 --set-default
    sf project deploy start --target-org compliance-feature
    # Option B: Use an existing sandbox
    sf org login web --alias my-dev-sandbox --instance-url https://test.salesforce.com
  3. Write the Code

    Create your Apex class and trigger in VS Code. We’ll cover the actual Apex syntax in Part 2, but the files would live under force-app/main/default:

    • force-app/main/default/classes/ComplianceReviewService.cls
    • force-app/main/default/classes/ComplianceReviewService.cls-meta.xml
    • force-app/main/default/triggers/ExpenseClaimTrigger.trigger
    • force-app/main/default/triggers/ExpenseClaimTrigger.trigger-meta.xml
    • force-app/main/default/classes/ComplianceReviewServiceTest.cls
    • force-app/main/default/classes/ComplianceReviewServiceTest.cls-meta.xml
  4. Deploy and Test Locally

    Deploy your changes to the development org and run tests (explicitly set --target-org so you do not accidentally deploy to the wrong org):

    Terminal window
    sf project deploy start --target-org compliance-feature
    sf apex run test --target-org compliance-feature --test-level RunSpecifiedTests --tests ComplianceReviewServiceTest --result-format human
  5. Commit and Push

    Once your code works and tests pass, commit to your feature branch:

    Terminal window
    git add .
    git commit -m "feat: auto-create compliance review task for high-value expenses"
    git push origin feature/compliance-review-task
  6. Open a Pull Request

    Create a pull request to merge your feature branch into integration. The CI pipeline validates the deployment and runs tests automatically. Your team reviews the code.

  7. Merge and Promote

    After approval, the code follows the release pipeline: integration → release branch → UAT → production (exactly as covered in Administration Part 4’s CI/CD section).

This workflow might seem like a lot of steps compared to building a Flow directly in the org. That’s intentional. Each step adds a layer of safety: version control means you can roll back, CI validation catches errors before they reach production, and code review catches logic issues before they affect users. For simple changes, Flow remains the faster and safer choice. For complex logic, this structured workflow pays for itself many times over.


Before we leave the tooling section, let’s cover the Developer Console. It is best described as a browser-based utility for debugging and ad hoc execution directly in your org. While VS Code is your primary workspace, the Developer Console remains useful for specific tasks.

From any Salesforce org: click the gear icon (⚙️) in the top-right corner → Developer Console. It opens in a new browser window.

Running Anonymous Apex: The “Execute Anonymous” window (Debug → Open Execute Anonymous Window or Ctrl+E) lets you run Apex code without creating a class or trigger. This is invaluable for:

  • Quick data queries during debugging
  • One-off data fixes (carefully)
  • Testing small code snippets before integrating them into a class
// Quick anonymous Apex to check data
List<Expense_Claim__c> highValueClaims = [
SELECT Id, Name, Amount__c, Department__c
FROM Expense_Claim__c
WHERE Amount__c > 10000
AND Status__c = 'Submitted'
];
System.debug('Found ' + highValueClaims.size() + ' high-value claims');
for (Expense_Claim__c claim : highValueClaims) {
System.debug(claim.Name + ': $' + claim.Amount__c + ' (' + claim.Department__c + ')');
}

Viewing Debug Logs: The Logs tab shows real-time debug output. You can filter by log level, search for specific debug statements, and inspect the execution flow of your code.

Checking Test Coverage: Navigate to Test → New Run to execute test classes and view line-by-line coverage results overlaid on your code.

The Developer Console is not a replacement for VS Code for day-to-day development:

  • No Git integration (no version control)
  • Limited autocomplete and error checking
  • No project-level file management
  • Changes are made directly in the org (bypassing your local source of truth)
  • Can be unstable with large files or long sessions

Think of the Developer Console as a debugging tool and scratchpad, not your primary development environment.

To build your skills and explore the features discussed above in more detail, check out the Developer Console Basics Trailhead module. This guide walks you through accessing the Developer Console, executing anonymous Apex, working with debug logs, running tests, and understanding its strengths and limitations.


As a developer, “metadata” will be the most common term you encounter. Understanding the distinction between metadata and data is foundational to mastering the platform.

This is the business information users create and manage every day, such as Account records, Contact details, Opportunity pipeline values, or Case history. Data lives in records in the database and changes constantly as users interact with the system through sales, service, and operations work.

This is the configuration that defines how Salesforce behaves, including structure, automation, security behavior, and user experience. This includes object definitions, field types, page layouts, validation rules, Apex classes, Flow logic, permission models, and Lightning Web Components. In short, metadata is what tells Salesforce how to store, display, secure, and process data.

A useful mental model is:

  • Metadata = the blueprint (how the org is designed to work)
  • Data = the runtime content (the records moving through that design)

When you create a custom field in Setup, you are defining metadata. When a user populates that field on a record, they are creating data. When you write an Apex class, you are creating metadata. When that class executes and inserts a record, it is manipulating data.

The Metadata API is the bridge between your local environment and your Salesforce org. When you run sf project retrieve start, the CLI uses this API to pull metadata into your local Salesforce DX source format. In practice, that local source includes both implementation files (for example .xml, .cls, .trigger, .js, .html) and metadata descriptor files (commonly -meta.xml). When you run sf project deploy start, the CLI converts and packages that local source back into the format Salesforce expects and deploys it to the org.

Every metadata component is represented in local source files, often paired with metadata descriptor XML (or bundled, as with LWC), in your project:

Setup ComponentMetadata TypeLocal File Path
Apex ClassApexClassclasses/MyClass.cls
Custom ObjectCustomObjectobjects/Object__c/Object__c.object-meta.xml
Custom FieldCustomFieldobjects/Object__c/fields/Field__c.field-meta.xml
FlowFlowflows/My_Flow.flow-meta.xml
Permission SetPermissionSetpermissionsets/MyPerm.permissionset-meta.xml
Lightning ComponentLightningComponentBundlelwc/myComponent/myComponent.js (html etc.)

Because everything is just a file, you can treat your entire org configuration like source code. You can track changes in Git, perform code reviews, and deploy updates reliably across your development, test, and production environments.

When you read older Salesforce docs you’ll see two metadata formats mentioned. They describe the same components, just packaged differently:

  • Source format (Salesforce DX) — what your force-app directory uses today. Components are split into one-file-per-thing (one file per custom field, one folder per Lightning Web Component bundle). It’s friendlier to Git, code review, and parallel teamwork.
  • Metadata API format — the older “zip with package.xml” format used by Change Sets, Workbench, and the classic force:mdapi:deploy command. Some legacy tools still emit this format.

The CLI converts between them automatically when needed (sf project convert source and sf project convert mdapi). For new development, stay in source format.

You’ll see package.xml referenced in CLI examples. It’s a small XML file that lists the metadata components you want to retrieve or deploy — essentially a manifest. In source-tracked workflows (scratch orgs, source-tracked sandboxes) you rarely need to touch it because the CLI infers what’s changed. Manifests come back into play when:

  • Working with non-source-tracked sandboxes (e.g. Full Copy)
  • Building deterministic CI/CD packages
  • Deploying to production from a curated set of components

A typical package.xml looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
<types>
<members>AccountTriggerHandler</members>
<members>ExpenseClaimService</members>
<name>ApexClass</name>
</types>
<version>62.0</version>
</Package>

Notice the <version> element — every metadata bundle is tied to a specific API version, which is the topic of the next subsection.

Salesforce releases three times a year (Spring, Summer, Winter), and every release bumps the platform’s API version (62, 63, 64…). Three places carry an API version that needs to stay roughly in sync:

  • sfdx-project.json — the sourceApiVersion your CLI uses by default.
  • <apiVersion> in each -meta.xml — pinned per Apex class, trigger, LWC, etc.
  • <version> in package.xml — pinned per deployment manifest.

Two practical rules:

  • You don’t need to be on the latest version. Older API versions keep working. Most teams pin to a version they’ve validated and bump it deliberately a release or two after a major Salesforce release.
  • You can mix versions per Apex class. Each .cls-meta.xml has its own <apiVersion>, useful when you need a new feature in one class without forcing the whole org to a new version.

📖 Navigating Salesforce Developer Documentation

Section titled “📖 Navigating Salesforce Developer Documentation”

As you start writing code, you’ll spend significant time in Salesforce’s developer documentation. Knowing where to find information saves hours of frustration.

Apex Developer Guide — The definitive reference for Apex syntax, classes, interfaces, and platform features. This is where you go when you need to know exactly how a method works or what parameters it accepts.

Apex Reference — The API reference for all Apex system classes and methods. Use this when you know the class name and need to find the right method.

Lightning Web Components Developer Guide — The guide for building Lightning Web Components. Covers HTML templates, JavaScript controllers, data binding, events, and wire services.

Metadata API Developer Guide — Reference for all metadata types. Useful when you need to understand how a specific metadata type is structured in XML.

Salesforce CLI Command Reference — The full list of CLI commands with options and examples.


You now have a working mental model for Salesforce development: when to use code versus declarative tools, how the core tools (CLI, VS Code, Extension Pack) fit together, what the project structure looks like, and how the retrieve-edit-deploy workflow connects to the CI/CD pipeline you already understand from your admin training.

The most important takeaway isn’t any specific tool or command. It’s this: development on Salesforce is an extension of administration, not a replacement for it. The same platform, the same data model, the same security framework. You’re adding a new set of tools to work with the system you already understand deeply.

In Part 2, we’ll start writing Apex. You’ll learn variables, collections, control flow, classes, SOQL, and DML: the building blocks that let you express business logic in code. The environment you’ve set up today is where that code will live.

Now that your toolchain is in place, it’s time to start writing code. In Part 2 — Apex Fundamentals, you’ll learn the language itself: variables, collections, control flow, classes, SOQL, and DML — the building blocks behind every Salesforce automation, integration, and trigger you’ll write later.