npm package: @jterrats/profiler
Description: The profiler command is an essential addition to the Salesforce CLI, engineered to guarantee the complete retrieval of Profile metadata along with all its required dependencies.
Author: Jaime Terrats
Latest version: 3.0.0

# Profiler - Salesforce CLI Plugin

[![npm version](https://img.shields.io/npm/v/@jterrats/profiler.svg?logo=npm)](https://www.npmjs.com/package/@jterrats/profiler)
[![EDD CI Pipeline](https://github.com/jterrats/profiler/actions/workflows/edd-ci.yml/badge.svg)](https://github.com/jterrats/profiler/actions/workflows/edd-ci.yml)
[![License](https://img.shields.io/github/license/jterrats/profiler)](https://raw.githubusercontent.com/jterrats/profiler/main/LICENSE)
[![Node.js Version](https://img.shields.io/node/v/@jterrats/profiler?logo=node.js)](https://nodejs.org)

## About

The Profiler plugin is an essential Salesforce CLI extension engineered to guarantee complete retrieval and comparison of Profile metadata with all required dependencies. This plugin automates profile operations including:

**Supported Operations**:

- 🔄 Retrieve profiles with all dependencies
- 🔍 Compare local vs org profile versions
- 🌍 Compare profiles across multiple environments
- 📊 Line-by-line difference analysis

**Retrieved Metadata Types**:

- Apex Classes
- Custom Applications
- Custom Objects
- Custom Permissions
- Custom Tabs
- Flows
- Layouts
- Profiles

**Key Features**:

- ✅ **Safe retrieval** - Uses temporary directories, never overwrites local changes
- ⚡ **Incremental retrieve** (v2.4.0) - 10x faster when no changes (~3s vs ~30s)
- 🌍 **Multi-source comparison** (v2.4.0) - Compare profiles across multiple environments in parallel
- 🔒 Field Level Security (FLS) control
- 🚀 No git operations required
- 🔄 Parallel metadata processing
- 🛡️ Comprehensive error handling

## ⚠️ Important Context: Profiles vs Permission Sets

Yes, I'm fully aware of the current Salesforce best practice that recommends migrating away from using Profiles to manage Field-Level Security (FLS) and other permissions, favoring Permission Sets (PS) and Permission Set Groups (PSG) instead.

However, this tool has been developed specifically for environments with significant **Technical Debt** and strong legacy dependencies on Profiles.

For many enterprise organizations, Profiles remain the cornerstone of security configuration. While teams are actively working on reducing their reliance on them—treating Profiles as read-only or touching them as little as possible—the need for robust tooling to manage and accurately retrieve these legacy assets remains critical.

**`sf profiler` is the necessary bridge** to stabilize existing profile configurations in high-debt orgs while long-term migration strategies are executed.

## 📚 Documentation

Complete documentation is available in the [`docs/`](docs/) directory:

- **[Quick Start Guide](docs/user-guide/quick-start.md)** - Get started in 5 minutes
- **[Usage Guide](docs/user-guide/usage.md)** - Complete command documentation
- **[Performance Guide](docs/PERFORMANCE.md)** - Performance flags, warnings, and best practices
- **[Developer Guide](docs/development/testing-and-publishing.md)** - Local testing and publishing
- **[Contributing](CONTRIBUTING.md)** - How to contribute
- **[Full Documentation Index](docs/README.md)** - Complete documentation map

### Quick Links

- [Installation Guide](docs/user-guide/quick-start.md#1-build--link-the-plugin)
- [Command Examples](docs/user-guide/usage.md#examples)
- [Performance Flags](docs/PERFORMANCE.md#-performance-flags)
- [Testing Locally](docs/development/testing-and-publishing.md#-local-testing-before-publishing)
- [Publishing to npm](docs/development/testing-and-publishing.md#-publishing-to-npm)

## Install

```bash
# Install latest version
sf plugins install @jterrats/profiler

# Or install a specific version
sf plugins install @jterrats/profiler@2.0.0
```

> **⚠️ Unsigned Plugin Notice:** This is a third-party plugin not officially signed by Salesforce. During installation, you'll see a confirmation prompt.
>
> **Installation Options:**
>
> ```bash
> # Option 1: Accept the prompt manually during installation
> sf plugins install @jterrats/profiler
>
> # Option 2: Skip the prompt with --force flag
> sf plugins install @jterrats/profiler --force
>
> # Option 3: Trust the plugin permanently (recommended)
> sf plugins trust allow @jterrats/profiler
> sf plugins install @jterrats/profiler
> ```

## Issues

Please report any issues at https://github.com/jterrats/profiler/issues

## Contributing

Contributions are welcome! Please follow these steps:

1. **Read the [Code of Conduct](CODE_OF_CONDUCT.md)**
2. **Create an issue** before starting work to discuss your proposed changes
3. **Fork this repository**
4. **Create a feature branch** from `main`
5. **Make your changes** with appropriate tests (aim for 95% code coverage)
6. **Ensure all tests pass**: `yarn test`
7. **Ensure linting passes**: `yarn lint`
8. **Submit a pull request** with a clear description of your changes

For detailed development instructions, see [CONTRIBUTING.md](CONTRIBUTING.md)

## Build

To build the plugin locally, make sure to have yarn installed and run the following commands:

```bash
# Clone the repository
git clone git@github.com:jterrats/profiler.git
cd profiler

# Install dependencies and compile
yarn install
yarn build
```

### Local Development

You can link the plugin to your Salesforce CLI for local testing:

```bash
# Link your plugin to the sf CLI
sf plugins link .

# Verify the plugin is linked
sf plugins | grep profiler

# Test commands
sf profiler --help
sf profiler retrieve --help
```

### Running Tests

```bash
# Run all tests with coverage
yarn test

# Run tests only (no coverage)
yarn test:only

# Run linting
yarn lint
```

For more details, see [Testing and Publishing Guide](docs/development/testing-and-publishing.md)

## Commands

<!-- commands -->

- [`sf profiler compare`](#sf-profiler-compare)
- [`sf profiler docs`](#sf-profiler-docs)
- [`sf profiler retrieve`](#sf-profiler-retrieve)

## `sf profiler compare`

Compare local Profile metadata with the version in Salesforce org.

```
USAGE
  $ sf profiler compare [--json] [--flags-dir <value>] [-o <value>] [-n <value>] [--api-version <value>]
    [--exclude-managed] [--sources <value>] [-O|--output-file <value>] [-F|--output-format table|json|html] [--max-profiles
    <value>] [--max-api-calls <value>] [--max-memory <value>] [--operation-timeout <value>] [--concurrent-workers
    <value>] [--verbose-performance]

FLAGS
  -n, --name=<value>                The name of a specific profile or comma-separated list of profiles to compare.
  -o, --target-org=<value>          The target org to compare profiles against.
      --api-version=<value>         Override the API version used for metadata operations.
      --concurrent-workers=<value>  Number of concurrent workers for parallel operations
      --exclude-managed             Exclude metadata from managed packages (with namespace prefixes).
      --max-api-calls=<value>       Maximum API calls per minute
      --max-memory=<value>          Maximum memory usage in MB
      --max-profiles=<value>        Maximum number of profiles to process in a single operation
      --operation-timeout=<value>   Operation timeout in milliseconds
      -O, --output-file=<value>     Export comparison results to a file.
      -F, --output-format=<option>  [default: table] Output format for comparison results (table, json, html).
                                    <options: table|json|html>
      --sources=<value>             Compare profiles across multiple Salesforce environments (comma-separated org
                                    aliases).
      --verbose-performance         Show detailed performance metrics

GLOBAL FLAGS
  --flags-dir=<value>  Import flag values from a directory.
  --json               Format output as json.

DESCRIPTION
  Compare local Profile metadata with the version in Salesforce org.

  The profiler compare command compares a local profile file with its version in the target org, showing the differences
  line by line. This is useful for identifying what has changed between your local version and the org version before
  committing or deploying changes.

EXAMPLES
  Compare a specific profile:

    $ sf profiler compare --target-org myOrg --name "Admin"

  Compare all profiles:

    $ sf profiler compare --target-org myOrg

  Compare with specific API version:

    $ sf profiler compare --target-org myOrg --name "Sales" --api-version 60.0

  Compare excluding managed package metadata:

    $ sf profiler compare --target-org myOrg --name "Admin" --exclude-managed

  Compare profiles across multiple environments:

    $ sf profiler compare --name "Admin" --sources "dev,qa,prod"

  Multi-source comparison with multiple profiles:

    $ sf profiler compare --name "Admin,Sales Profile" --sources "dev,qa,uat,prod"

  Export comparison matrix to HTML file:

    $ sf profiler compare --name "Admin" --sources "dev,qa,prod" -F html -O \
      "./comparison-report.html"

  Get comparison results as JSON:

    $ sf profiler compare --name "Admin" --sources "dev,qa,prod" -F json

FLAG DESCRIPTIONS
  -n, --name=<value>  The name of a specific profile or comma-separated list of profiles to compare.

    Specify one or more profile names (without the .profile-meta.xml extension). You can provide a single profile or
    multiple profiles separated by commas. If not provided, all local profiles will be compared. Examples: "Admin",
    "Admin,Sales Profile,Custom".

  --api-version=<value>  Override the API version used for metadata operations.

    Specify the API version to use for the comparison. Defaults to the org's API version.

  --concurrent-workers=<value>  Number of concurrent workers for parallel operations

    Overrides the auto-detected worker count. Max recommended: 5 for metadata operations, 10 for API operations.

  --exclude-managed  Exclude metadata from managed packages (with namespace prefixes).

    When enabled, filters out all metadata components that belong to managed packages (identified by namespace prefixes
    like "namespace\_\_ComponentName"). This helps avoid errors when comparing profiles that reference components from
    uninstalled or inaccessible managed packages.

  --max-api-calls=<value>  Maximum API calls per minute

    Overrides the default limit of 100 API calls per minute. Ensure your Salesforce org can handle the increased load.

  --max-memory=<value>  Maximum memory usage in MB

    Overrides the default limit of 512MB. Ensure your system has enough available memory.

  --max-profiles=<value>  Maximum number of profiles to process in a single operation

    Overrides the default limit of 50 profiles. Use with caution as higher values may result in longer processing times
    and more API calls.

  --operation-timeout=<value>  Operation timeout in milliseconds

    Overrides the default timeout of 300000ms (5 minutes).

  -O, --output-file=<value>  Export comparison results to a file.

    Specify a file path to export the comparison matrix results. The output format is determined by the --output-format
    flag. Example: "./comparison-report.html". Useful for documentation, reports, or sharing results with team members.

  -F, --output-format=table|json|html  Output format for comparison results (table, json, html).

    Choose the output format for displaying or exporting comparison matrices. Options: "table" (ASCII table for
    terminal), "json" (machine-readable structured data), "html" (web-friendly formatted output with styling). Default
    is "table" for terminal display. Use "json" for automation or "html" for reports.

  --sources=<value>  Compare profiles across multiple Salesforce environments (comma-separated org aliases).

    Enables multi-source comparison by specifying a comma-separated list of org aliases. Instead of comparing local vs.
    org, this compares the same profile across multiple environments. Example: "dev,qa,uat,prod". Requires authenticated
    orgs. Retrieves profiles in parallel for performance.

  --verbose-performance  Show detailed performance metrics

    Displays detailed information about worker pool configuration, API calls, memory usage, and operation timings.
```

_See code: [src/commands/profiler/compare.ts](https://github.com/jterrats/profiler/blob/v2.4.0/src/commands/profiler/compare.ts)_

## `sf profiler docs`

Generate comprehensive documentation for Profile metadata in Markdown format.

```
USAGE
  $ sf profiler docs [--json] [--flags-dir <value>] [-n <value>] [-d <value>] [--exclude-managed]

FLAGS
  -d, --output-dir=<value>  [default: profile-docs] Directory where the documentation files will be created.
  -n, --name=<value>        Name of a specific profile or comma-separated list of profiles to document.
      --exclude-managed     Exclude metadata from managed packages in documentation.

GLOBAL FLAGS
  --flags-dir=<value>  Import flag values from a directory.
  --json               Format output as json.

DESCRIPTION
  Generate comprehensive documentation for Profile metadata in Markdown format.

  The profiler docs command generates detailed documentation for Salesforce Profile metadata files in Markdown format.
  It creates tables/matrices for all permission types including user permissions, object permissions, field-level
  security, application visibilities, and more.

  Use the --name flag to generate documentation for a specific profile, or omit it to generate documentation for all
  profiles in the project.

  The generated documentation includes:

  - Profile description and metadata
  - User permissions matrix
  - Object permissions (CRUD + View/Modify All)
  - Field-level security (FLS) permissions
  - Application visibilities
  - Apex class accesses
  - Visualforce page accesses
  - Tab visibilities
  - Record type visibilities
  - Layout assignments
  - Summary statistics

EXAMPLES
  Generate documentation for all profiles in the project:

    $ sf profiler docs

  Generate documentation for a specific profile:

    $ sf profiler docs --name Admin

  Generate documentation with a custom output directory:

    $ sf profiler docs --output-dir docs/profiles

  Generate documentation for a specific profile in a custom directory:

    $ sf profiler docs --name "Sales User" --output-dir salesforce-docs

  Generate documentation excluding managed package metadata:

    $ sf profiler docs --name Admin --exclude-managed

FLAG DESCRIPTIONS
  -d, --output-dir=<value>  Directory where the documentation files will be created.

    Specify the output directory for the generated Markdown documentation files. Defaults to 'profile-docs' in the
    project root.

  -n, --name=<value>  Name of a specific profile or comma-separated list of profiles to document.

    Specify one or more profile names (without the .profile-meta.xml extension). You can provide a single profile or
    multiple profiles separated by commas. If not provided, documentation will be generated for all profiles found in
    the project. Examples: "Admin", "Admin,Sales Profile,Custom".

  --exclude-managed  Exclude metadata from managed packages in documentation.

    When enabled, filters out metadata components that belong to managed packages (identified by namespace prefixes like
    "namespace\_\_ComponentName") from the generated documentation. This makes documentation cleaner by hiding managed
    package permissions that may not be relevant to your implementation.
```

_See code: [src/commands/profiler/docs.ts](https://github.com/jterrats/profiler/blob/v2.4.0/src/commands/profiler/docs.ts)_

## `sf profiler retrieve`

Retrieve Profile metadata with all required dependencies.

```
USAGE
  $ sf profiler retrieve -o <value> [--json] [--flags-dir <value>] [-n <value>] [--all-fields] [--api-version <value>]
    [-f] [--exclude-managed] [--force] [--dry-run] [--max-profiles <value>] [--max-api-calls <value>] [--max-memory
    <value>] [--operation-timeout <value>] [--concurrent-workers <value>] [--verbose-performance]

FLAGS
  -p, --from-project                Use local project metadata to build the package.xml instead of listing from org.
  -n, --name=<value>                The name of a specific profile or comma-separated list of profiles to retrieve.
  -o, --target-org=<value>          (required) The target org to retrieve profiles from.
      --all-fields                  Include Field Level Security (FLS) in the retrieved profiles.
      --api-version=<value>         Override the API version used for metadata operations.
      --concurrent-workers=<value>  Number of concurrent workers for parallel operations
      --dry-run                     Preview what would be retrieved without executing the retrieve.
      --exclude-managed             Exclude metadata from managed packages (with namespace prefixes).
      --force                       Force full retrieve, bypassing incremental optimization.
      --max-api-calls=<value>       Maximum API calls per minute
      --max-memory=<value>          Maximum memory usage in MB
      --max-profiles=<value>        Maximum number of profiles to process in a single operation
      --operation-timeout=<value>   Operation timeout in milliseconds
      --verbose-performance         Show detailed performance metrics

GLOBAL FLAGS
  --flags-dir=<value>  Import flag values from a directory.
  --json               Format output as json.

DESCRIPTION
  Retrieve Profile metadata with all required dependencies.

  The profiler retrieve command safely retrieves Profile metadata along with all its dependencies from the target org,
  including Apex Classes, Apex Pages (Visualforce), Connected Apps, Custom Applications, Custom Objects (with Record
  Types), Custom Permissions, Custom Tabs, Flows, and Layouts. Use the --all-fields flag to include Field Level Security
  (FLS) permissions.

  IMPORTANT: This command uses system temporary directories (outside your project) for all retrieval operations,
  ensuring your local uncommitted changes are NEVER overwritten. Only profile files are copied to your project - all
  other metadata remains untouched. No git operations are required and no temporary files are created in your project
  directory.

EXAMPLES
  Retrieve all profiles with metadata (without FLS):

    $ sf profiler retrieve --target-org myOrg

  Retrieve a specific profile:

    $ sf profiler retrieve --target-org myOrg --name Admin

  Retrieve multiple profiles:

    $ sf profiler retrieve --target-org myOrg --name "Admin,Custom Profile,Sales Profile"

  Retrieve all profiles with all fields including FLS:

    $ sf profiler retrieve --target-org myOrg --all-fields

  Retrieve specific profiles with FLS:

    $ sf profiler retrieve --target-org myOrg --name "Admin,Standard User" --all-fields

  Retrieve profiles with a specific API version:

    $ sf profiler retrieve --target-org myOrg --all-fields --api-version 60.0

  Retrieve profiles using local project metadata:

    $ sf profiler retrieve --target-org myOrg --from-project

  Retrieve specific profiles using local metadata:

    $ sf profiler retrieve --target-org myOrg --name "Admin,Sales Profile" --from-project

  Retrieve profiles excluding managed package metadata:

    $ sf profiler retrieve --target-org myOrg --exclude-managed

  Retrieve specific profiles excluding managed packages:

    $ sf profiler retrieve --target-org myOrg --name Admin --exclude-managed

  Force full retrieve (bypass incremental optimization):

    $ sf profiler retrieve --target-org myOrg --force

  Preview what would be retrieved (dry run):

    $ sf profiler retrieve --target-org myOrg --dry-run

  Combine dry run with specific profile:

    $ sf profiler retrieve --target-org myOrg --name Admin --dry-run

FLAG DESCRIPTIONS
  -p, --from-project  Use local project metadata to build the package.xml instead of listing from org.

    When enabled, reads metadata component names from the local project directories (classes, objects, flows, etc.) to
    build the package.xml, instead of querying the org. This is faster and useful when you want to retrieve only what
    exists in your project.

  -n, --name=<value>  The name of a specific profile or comma-separated list of profiles to retrieve.

    When specified, only retrieves the named profile(s) instead of all profiles. You can specify a single profile or
    multiple profiles separated by commas. Profile names should match exactly (e.g., "Admin", "Standard User",
    "Admin,Custom Profile,Sales").

  --all-fields  Include Field Level Security (FLS) in the retrieved profiles.

    When enabled, retrieves complete profile metadata including Field Level Security settings for all objects and
    fields.

  --api-version=<value>  Override the API version used for metadata operations.

    Specify the API version to use for the retrieve operation. Defaults to the org's API version.

  --concurrent-workers=<value>  Number of concurrent workers for parallel operations

    Overrides the auto-detected worker count. Max recommended: 5 for metadata operations, 10 for API operations.

  --dry-run  Preview what would be retrieved without executing the retrieve.

    When enabled, shows a detailed preview of what metadata would be retrieved without actually executing the retrieve
    operation. Useful for verifying the scope of a retrieve before making changes. Combines well with incremental
    retrieve to see what has changed.

  --exclude-managed  Exclude metadata from managed packages (with namespace prefixes).

    When enabled, filters out all metadata components that belong to managed packages (identified by namespace prefixes
    like "namespace**ComponentName"). This helps avoid errors when retrieving profiles that reference components from
    uninstalled or inaccessible managed packages. Custom objects ending in "**c" are always included even with this
    flag.

  --force  Force full retrieve, bypassing incremental optimization.

    When enabled, skips the incremental retrieve optimization and always performs a full retrieve of all specified
    metadata. Use this flag if you suspect local metadata is out of sync or if incremental retrieve is causing issues.

  --max-api-calls=<value>  Maximum API calls per minute

    Overrides the default limit of 100 API calls per minute. Ensure your Salesforce org can handle the increased load.

  --max-memory=<value>  Maximum memory usage in MB

    Overrides the default limit of 512MB. Ensure your system has enough available memory.

  --max-profiles=<value>  Maximum number of profiles to process in a single operation

    Overrides the default limit of 50 profiles. Use with caution as higher values may result in longer processing times
    and more API calls.

  --operation-timeout=<value>  Operation timeout in milliseconds

    Overrides the default timeout of 300000ms (5 minutes).

  --verbose-performance  Show detailed performance metrics

    Displays detailed information about worker pool configuration, API calls, memory usage, and operation timings.
```

_See code: [src/commands/profiler/retrieve.ts](https://github.com/jterrats/profiler/blob/v2.4.0/src/commands/profiler/retrieve.ts)_

<!-- commandsstop -->