Replace Strings in Code Before Deploying or Packaging
These sample use cases describe scenarios for using string replacement:
- A NamedCredential contains an endpoint that you use for testing. But when you deploy the source to your production org, you want to specify a different endpoint.
- An ExternalDataSource contains a password that you don’t want to store in your repository, but you’re required to deploy the password along with your metadata.
- You deploy near-identical code to multiple orgs. You want to conditionally swap out some values depending on which org you’re deploying to.
For the project deploy start command, string replacement occurs when source-formatted files are converted to metadata API format, and then a ZIP file is created and deployed to the org. It also occurs when you run the package version create command, which converts source files as part of the package creation process. The changes that result from string replacement are never written to your project source; they apply only to the deployed or packaged files.
Configure String Replacement
Configure string replacement by adding a replacements property to your sfdx-project.json file. The property accepts multiple entries that consist of keys that define the:
- Source file or files that contain the string to be replaced.
- The string to be replaced.
- The replacement value.
To see how string replacements work, let’s look at an example; see more examples later in this topic.
{
"packageDirectories": [
{
"path": "force-app",
"default": true
}
],
"name": "myproj",
"replacements": [
{
"filename": "force-app/main/default/classes/myClass.cls",
"stringToReplace": "replaceMe",
"replaceWithEnv": "THE_REPLACEMENT"
}
]
}
You can specify these keys in the replacements property.
- Location of Files
- One of the following properties is required:
- filename: Single file that contains the string to be replaced.
- glob: Collection of files that contain the string to be replaced. Example: **/classes/*.cls.
- String to be Replaced
- One of the following properties is required:
- stringToReplace: The string to be replaced.
- regexToReplace: A regular expression (regex) that specifies a string pattern to be replaced.
- Replacement Value
- One of the following properties is required:
- replaceWithEnv: Specifies that the string is replaced with the value of the specified environment variable.
- replaceWithFile: Specifies that the string is replaced with the contents of the specified file.
- Conditional Processing
- These properties are optional:
- replaceWhenEnv: Specifies that a string replacement occur only when a specific environment variable is set to a specific value. Use the property env to specify the environment variable and the property value to specify the value that triggers the string replacement.
- allowUnsetEnvVariable: Boolean property used with the replaceWithEnv property. When set to true, specifies that if the replaceWithEnv environment variable isn’t set, then remove the replacement string from the file before deploying. In other words, replace it with nothing. When set to false (the default value), you get an error when the replaceWithEnv environment variable isn’t set.
Follow these syntax rules:
- Always use forward slashes for directories (/), even on Windows.
- Both JSON and regular expressions use the backslash (\) as an escape character. As a result, when you use a regular expression to
match a dot, which requires escaping, you must use two backslashes for the regexToReplace
value:
"regexToReplace" : "\\."
Similarly, to match a single backslash, you must specify three of them."regexToReplace" : "\\\"
Examples
"replacements": [
{
"filename": "force-app/main/default/classes/FirstApexClass.cls",
"stringToReplace": "replaceMe",
"replaceWithEnv": "THE_REPLACEMENT"
},
{
"filename": "force-app/main/default/classes/SecondApexClass.cls",
"stringToReplace": "replaceMe",
"replaceWithEnv": "THE_REPLACEMENT"
}
]
This example shows how to specify that the string replacement occur only if an environment variable called DEPLOY_DESTINATION exists and it has a value of PROD.
"replacements": [
{
"filename": "force-app/main/default/classes/myClass.cls",
"stringToReplace": "replaceMe",
"replaceWithEnv": "THE_REPLACEMENT",
"replaceWhenEnv": [{
"env": "DEPLOY_DESTINATION",
"value": "PROD"
}]
}
]
In this example, if the environment variable SOME_ENV_THAT_CAN_BE_BLANK isn’t set, the string myNS__ in the myClass.cls file is removed when the file is deployed. If the environment variable is set to a value, then that value replaces the myNS__ string.
"replacements": [
{
"filename": "/force-app/main/default/classes/myClass.cls",
"stringToReplace": "myNS__",
"replaceWithEnv": "SOME_ENV_THAT_CAN_BE_BLANK",
"allowUnsetEnvVariable": true
}
]
This example specifies that when the Apex class files in the force-app/main/default directory are deployed, all occurrences of the string replaceMe are replaced with the contents of the file replacementFiles/copyright.txt.
"replacements": [
{
"glob": "force-app/main/default/classes/*.cls",
"stringToReplace": "replaceMe",
"replaceWithFile": "replacementFiles/copyright.txt"
}
]
<?xml version="1.0" encoding="UTF-8" ?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>55.0</apiVersion>
<status>Active</status>
</ApexClass>
"replacements": [
{
"glob": "force-app/main/default/classes/*.xml",
"regexToReplace": "<apiVersion>\\d+\\.0</apiVersion>",
"replaceWithFile": "replacementFiles/latest-api-version.txt"
}
]
Tips and Tricks
- (macOS or Linux only) When using the replaceWithEnv
or replaceWhenEnv properties, you can specify that
the environment variables apply to a single command by prepending the variables before the
command execution. For
example:
THE_REPLACEMENT="some text" DEPLOY_DESTINATION=PROD sf project deploy start
- If you’ve configured many string replacements, and are finding it difficult to manage,
check out open-source tools that load the contents of one or more files to your
environment, such as dotenv-cli. In this example, environment variables configured in
two local .env files are loaded before the project deploy start command execution:
dotenv -e .env1 -e .env2 sf project deploy start
- If you specify --json for project deploy start, the JSON output includes a replacements property that lists the affected files and the
string that was replaced. If you specify --json and
--concise, the JSON output doesn’t include the
replacements property.
To view string replacement information in the project deploy start human-readable output, specify --verbose.
Considerations and Limitations
- If you configure multiple string replacements in multiple files, the performance of the
deployment can degrade. Consider using the filename
key when possible, to ensure that you open only one file. If you must use glob, try to limit the number of files that are opened by
specifying a single directory or metadata type.
For example, "glob": "force-app/main/default/classes/*.cls" targets Apex class files in a specific directory, which is better than "glob": "**/classes/**”, which searches for all Apex metadata files in all package directories.
- Be careful using string replacement in static resources. When not doing string replacement, Salesforce CLI simply zips up all static resources when it first encounters their directory and deploys them as-is. If you configure string replacement for a large static resource directory, the CLI must inspect a lot more files than usual, which can degrade performance.
- You can’t use string replacements when deploying in metadata format, such as with the command project deploy start --metadata-dir.
- If your deployment times out, or you specify the --async flag of project deploy start, and then run project deploy resume or project deploy report to see what happened, the deployed files contain string replacements as usual. However, the output of project deploy resume and project deploy report don’t display the same string replacement information as project deploy start --verbose would have.
Test String Replacements
- Set the SF_APPLY_REPLACEMENTS_ON_CONVERT environment variable to true.
-
Run the project convert source command, which converts the
source files into metadata API format. For example:
sf project convert source --output-dir mdapiOut --source-dir force-app
- Inspect the files in the output directory (mdapiOut in our example) for the string replacements and what exactly will be deployed to the org or packaged.