This article is part of the Salesforce Admin Git & sf CLI series, a complete guide to version control and metadata management for Salesforce admins. Articles are standalone; no need to read in order.
TL;DR
- Retrieve all Apex classes with
sf project retrieve start --metadata ApexClass --target-org myorg: this fetches every class including test classes - For Lightning Web Components:
sf project retrieve start --metadata LightningComponentBundle --target-org myorg. Each LWC component retrieves as a folder of files - List components before retrieving to get exact API names:
sf org list metadata --metadata-type ApexClass --target-org myorg - This article is for admins who oversee developers (you don't need to understand the code to retrieve, version-control, and deploy it)
What You'll Learn
- How to retrieve ApexClass and ApexTrigger metadata
- How to retrieve LightningComponentBundle (LWC) and AuraDefinitionBundle (Aura) metadata
- How to list code components in your org before retrieving
- Source format vs MDAPI format for code metadata
- How to use
package.xmlfor repeatable code retrieves - What code files look like on disk
The Problem
Your org has Apex classes and Lightning Web Components written by developers. As an admin, you may not write code, but you still need to retrieve it, version-control it, and deploy it between orgs. Developers write code in a sandbox; that code needs to get to production. You're the one responsible for managing that process. This article shows you how.
Common questions this article answers:
- How do I retrieve all Apex classes using sf CLI?
- How do I get a specific LWC component?
- What files does an LWC component produce on disk?
- Can I retrieve Aura components (old-style Lightning components)?
- How do I retrieve Apex triggers?
Quick Answer
If you just need the commands now:
# List all Apex classes
sf org list metadata --metadata-type ApexClass --target-org myorg
# Retrieve all Apex classes
sf project retrieve start --metadata ApexClass --target-org myorg
# Retrieve a specific LWC component
sf project retrieve start --metadata "LightningComponentBundle:myComponentName" --target-org myorg
Always list before you retrieve. LWC component API names are camelCase (e.g., myAccountCard, opportunityList), not the human-readable labels you see in the Experience Builder or Setup UI. The list command shows you the exact name sf CLI needs. For ApexClass, the API name is the class name exactly as it appears in Setup → Apex Classes. Retrieving all Apex classes at once is safe and practical: Apex files are small compared to Profile XML, so retrieving the full set rarely causes performance issues.
The rest of this article covers each metadata type in detail, explains what files are produced on disk, and shows how to use package.xml for repeatable retrieves.
Section 1: List Code Components First
Before retrieving, list what's in your org to get the exact API names sf CLI needs. The display name you see in Setup is often different from the API name used in retrieve commands.
# List all Apex classes
sf org list metadata --metadata-type ApexClass --target-org myorg
# List all Apex triggers
sf org list metadata --metadata-type ApexTrigger --target-org myorg
# List all Lightning Web Components
sf org list metadata --metadata-type LightningComponentBundle --target-org myorg
# List all Aura components
sf org list metadata --metadata-type AuraDefinitionBundle --target-org myorg
# Preview what WOULD be retrieved without actually retrieving
sf project retrieve preview --target-org myorg
Run this before a large retrieve to see which files would be added or updated locally.
The fullName value in the output is what you use in your retrieve commands. For ApexClass, fullName matches the class name as it appears in Setup → Apex Classes. For LightningComponentBundle, fullName is the camelCase API name of the component, not the label you'd see in a page builder.
Section 2: Retrieve ApexClass and ApexTrigger
Apex classes and triggers are retrieved as a pair of files each: the code file itself and a companion metadata XML file.
# Retrieve ALL Apex classes
sf project retrieve start --metadata ApexClass --target-org myorg
# Retrieve a specific Apex class
sf project retrieve start --metadata "ApexClass:MyClassName" --target-org myorg
# Retrieve ALL Apex triggers
sf project retrieve start --metadata ApexTrigger --target-org myorg
# Retrieve a specific Apex trigger
sf project retrieve start --metadata "ApexTrigger:AccountTrigger" --target-org myorg
# Retrieve Apex classes and triggers together
sf project retrieve start --metadata ApexClass ApexTrigger --target-org myorg
The ApexClass API name is the class name exactly as it appears in Setup → Apex Classes. Test classes are Apex classes with the @isTest annotation. They're retrieved by --metadata ApexClass like any other class. There is no separate metadata type for test classes.
The
--metadataflag accepts the formatMetadataType:ApiNamefor retrieving a single named component, or justMetadataTypeto retrieve all components of that type.
Section 3: Retrieve LightningComponentBundle (LWC)
Lightning Web Components are the modern Lightning framework. Each LWC component is stored as a folder containing multiple files: HTML, JavaScript, CSS, and a metadata XML.
# Retrieve ALL LWC components
sf project retrieve start --metadata LightningComponentBundle --target-org myorg
# Retrieve a specific LWC component
sf project retrieve start --metadata "LightningComponentBundle:myComponentName" --target-org myorg
# Retrieve into a custom directory (source format)
sf project retrieve start --metadata LightningComponentBundle --target-org myorg --output-dir ./lwc-backup
LWC component API names are camelCase, for example myAccountCard, opportunityList, contactQuickAction. Run sf org list metadata --metadata-type LightningComponentBundle --target-org myorg to see the exact names. The name displayed in the Experience Builder or page editor is the component's label, which can differ from its API name.
Section 4: Retrieve AuraDefinitionBundle (Aura)
Aura is the older Lightning component framework. If your org was built before LWC became the standard (roughly 2019 and earlier), it likely has Aura components. Both frameworks can coexist in the same org.
# Retrieve ALL Aura components
sf project retrieve start --metadata AuraDefinitionBundle --target-org myorg
# Retrieve a specific Aura component
sf project retrieve start --metadata "AuraDefinitionBundle:MyAuraComponent" --target-org myorg
Aura component names typically use PascalCase (e.g., MyAuraComponent, AccountDetail). Salesforce recommends LWC for all new development, but existing Aura components continue to work and need to be version-controlled if you're managing them. If your org has both Aura and LWC, retrieve both types to ensure complete coverage.
Section 5: Retrieve in MDAPI Format
Source format is the default when you run sf project retrieve start and is better for version control. MDAPI format produces a ZIP file using the older file extensions the Metadata API has always used. You may need MDAPI format for legacy deployment tooling.
# Retrieve ApexClass in MDAPI format
sf project retrieve start \
--metadata ApexClass \
--target-org myorg \
--target-metadata-dir mdapi-output \
--unzip
# Retrieve LWC in MDAPI format
sf project retrieve start \
--metadata LightningComponentBundle \
--target-org myorg \
--target-metadata-dir mdapi-output \
--unzip
--target-metadata-dir tells sf CLI to produce a ZIP in MDAPI format. --unzip extracts it automatically. For LWC especially, source format is the better choice: LWC's multi-file structure (HTML, JS, CSS, metadata XML) is preserved as individual files in source format, making diffs in git readable. In MDAPI format, LWC is still a folder structure, but it lacks the source format's precise per-file tracking.
| Format | Apex extension | LWC structure |
|---|---|---|
| Source format | .cls-meta.xml |
Folder with individual .html, .js, .css, .js-meta.xml |
| MDAPI format | .cls |
Folder with same files but no -meta.xml suffix on the folder |
For new projects and git-based workflows, stay with source format.
Section 6: Retrieve Using package.xml
package.xml gives you a repeatable, version-controlled retrieve specification. Commit it alongside your code metadata so anyone can reproduce the same retrieve without typing out all the flags.
sf project retrieve start --manifest package.xml --target-org myorg
Full package.xml for all code metadata types:
<?xml version="1.0" encoding="UTF-8"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
<types>
<members>*</members>
<name>ApexClass</name>
</types>
<types>
<members>*</members>
<name>ApexTrigger</name>
</types>
<types>
<members>*</members>
<name>LightningComponentBundle</name>
</types>
<types>
<members>*</members>
<name>AuraDefinitionBundle</name>
</types>
<version>62.0</version>
</Package>
Using * as <members> retrieves all components of that type. For code metadata, this is safe and practical (unlike Profiles, Apex and LWC files are small enough that retrieving all of them at once is fast). If you only want specific components tracked, replace * with named <members> entries, one per component.
Section 7: What Files Look Like on Disk
After a retrieve, your project directory will contain:
force-app/
└── main/
└── default/
├── classes/
│ ├── MyClassName.cls ← the Apex code
│ └── MyClassName.cls-meta.xml ← metadata (API version, status)
├── triggers/
│ ├── AccountTrigger.trigger ← the trigger code
│ └── AccountTrigger.trigger-meta.xml
├── lwc/
│ └── myComponentName/
│ ├── myComponentName.html ← component template
│ ├── myComponentName.js ← JavaScript logic
│ ├── myComponentName.css ← styles (optional)
│ └── myComponentName.js-meta.xml ← metadata (targets, API version)
└── aura/
└── MyAuraComponent/
├── MyAuraComponent.cmp ← component markup
├── MyAuraComponentController.js ← controller JS
├── MyAuraComponentHelper.js ← helper JS
└── MyAuraComponent.cmp-meta.xml ← metadata
Each Apex class produces exactly two files: the .cls (the code itself) and the .cls-meta.xml (metadata including API version and whether the class is active). Both files are required when you deploy. sf CLI won't deploy a .cls without its companion metadata file.
LWC components produce a folder with multiple files. When you deploy, sf CLI sends the whole folder for an LWC component, not individual files. This means if you need to deploy a change to the JavaScript in one LWC, sf CLI packages and sends the entire component folder. You don't need to know which files changed. sf CLI handles it.
Section 8: Managed Package Code (Read-Only)
If your org has installed managed packages, those classes and components will appear in sf org list metadata output with a namespace prefix, for example mypkg__MyClass or mypkg__myComponent. You can retrieve namespace-prefixed code to inspect it locally, but managed package code is read-only. You cannot modify it or deploy it back to any org.
Do not commit namespace-prefixed code metadata to your version-controlled source as if it were your own customisation. When using * as <members> in package.xml, namespace-prefixed components are included in the retrieve. Filter them out of your git commits, or use named <members> entries to retrieve only your custom code without package code.
Troubleshooting
"No such metadata type: ApexClass"
Type names are case-sensitive. The correct name is ApexClass, not apexclass or apex_class. Run sf org list metadata-types --target-org myorg to see the complete list of valid metadata type names if you're unsure.
LWC component name not found
LWC names are camelCase API names, not the display labels you see in Setup or Experience Builder. Run sf org list metadata --metadata-type LightningComponentBundle --target-org myorg. The fullName column shows the exact name to use in your retrieve command.
Apex class retrieved but test classes missing
Test classes are Apex classes. They're retrieved by --metadata ApexClass the same as any other class. If a test class isn't appearing, verify it exists in the org by running sf org list metadata --metadata-type ApexClass --target-org myorg and checking whether the class name appears in the output.
"Apex class is in a package and cannot be retrieved" Managed package classes with a namespace prefix are locked and cannot be retrieved for editing. Only your custom classes without a namespace prefix are retrievable. If you need to inspect managed package code, you can sometimes view it in Setup → Apex Classes, but sf CLI will not allow you to retrieve and redeploy it.
LWC folder retrieved but appears incomplete If an LWC component was created directly in the org through a declarative tool (e.g., Experience Builder) rather than deployed via sf CLI, it may have an incomplete source format mapping. Check the component in Setup → Lightning Components to confirm it exists, then verify the component's API version and targets are set correctly.
Frequently Asked Questions
Do I need to understand the code to retrieve and deploy it?
No. sf CLI treats code metadata like any other metadata type: it retrieves files to your local machine and deploys them back. You don't need to read or understand the Apex or JavaScript to manage it through sf CLI. The developer writes the code; you retrieve it, commit it to git, and deploy it to another org.
What's the difference between ApexClass and ApexTrigger?
Both are Apex code. ApexClass is the standard class type used for business logic, utilities, controllers, and test classes. ApexTrigger is specifically for trigger code that runs before or after database operations on records (e.g., before a Contact is saved). They are separate metadata types and must be retrieved with separate --metadata flags, or together using --metadata ApexClass ApexTrigger.
What's the difference between LWC and Aura?
LightningComponentBundle (LWC) is the modern Lightning framework, using standard JavaScript and HTML. AuraDefinitionBundle is the older framework with its own markup language and controller pattern. Most new components are LWC. Your org may have both. Retrieve both types to ensure complete coverage when setting up version control.
Can I retrieve ApexClass test results or code coverage data?
No. Code coverage percentages and test run results are runtime data, not metadata. You retrieve the Apex source code itself; test results exist only in the org's runtime state and cannot be retrieved as files. To run tests and view results, use sf apex run test --target-org myorg.
What API version does the retrieved Apex use?
Each Apex class has an API version stored in its .cls-meta.xml file. This is the Salesforce API version the class was last saved against, not your org's current API version. You can see it in the <apiVersion> element of the meta file. When you redeploy, the class uses the API version from that meta file, which is why keeping it in version control matters.
Key Takeaways
- Apex = two files per class: every
.clsfile has a companion.cls-meta.xml. Both are required for deploy; sf CLI will not deploy one without the other - LWC = one folder per component: the folder contains HTML, JS, CSS, and a meta XML. All files are needed together and sf CLI deploys the whole folder as a unit
- Managed package code is read-only: namespace-prefixed classes can be retrieved to inspect but cannot be modified or deployed back
--target-metadata-dirfor MDAPI format: produces a ZIP; source format is better for version control because LWC's multi-file structure is preserved as individual trackable files- List first:
sf org list metadata --metadata-type LightningComponentBundle --target-org myorggives you exact component API names in camelCase before you retrieve
What's Next?
Recommended Reading:
- Article 8: Fetching OmniStudio Metadata: OmniScript, DataRaptor, FlexCard
- Article 6: Fetching Security Metadata: Profile, PermissionSet
- Article 10: Git Basics for Salesforce Admins: commit code metadata to version control
- Article 11: Deploying Metadata Back to Salesforce: deploy Apex and LWC between orgs
Action Items:
- Run
sf org list metadata --metadata-type ApexClass --target-org myorgto see all classes in your org - Retrieve one class:
sf project retrieve start --metadata "ApexClass:YourClassName" --target-org myorg - Open the
.cls-meta.xmlfile and find the<apiVersion>element to see what API version it was last saved against
Resources & References
- Salesforce Metadata API: ApexClass
- Salesforce Metadata API: LightningComponentBundle
- Lightning Web Components Developer Guide
- Salesforce Metadata Coverage Report
About This Guide: Part of the Salesforce Admin Git & sf CLI series.
Tags: #salesforce #sfcli #apex #lwc #metadata #versioncontrol