---
schema_version: "1"
id: 8afcc3e083a4cbd2a4b9493e960d2df2c64a39bf824460ba0e244f7719b67cb7
title: Use Development and Application Lifecycle Workflow
collection: developer
version: current
locale: en-us
portal_url: https://docs.salesforce.com/developer/current/en-us/salesforce-functions/functions/guide/dev-guide/dev-alm-workflow.md
canonical_url: https://developer.salesforce.com/docs/platform/functions/guide/dev-alm-workflow.html
source_site: developer.salesforce.com
content_type: documentation
content_hash: c6bc5c86ae96bef7e3554a677e8aa9b8dc1d36da984fdce25e5caaf0a8d63cf4
products:
  - Salesforce Functions
---
# Use Development and Application Lifecycle Workflow

As you develop with Salesforce Functions, integrate your function code into your development and application lifecycle workflow. This process can include tasks like:

- Collaborating on function development with other developers on your team
- Adding Salesforce Functions to your application lifecycle management process to ensure your functions are properly verified in a sandbox environment before being deployed to production
- Automating parts of your workflow, such as using automated testing and deployment for your functions

Because Salesforce Functions code is not stored in your org, you must use additional DX tools and commands to integrate Salesforce Functions in your workflow.

## Maintain and Share Function Source Code

Because Salesforce Functions code isn't saved to your org, save your functions project in a source code control system. You can use git repos on GitHub to save your project code along with the rest of your DX project. After your functions project is in GitHub, you can use git branches, merges, and pull requests to track and safely merge development changes across your team.

To add an existing Salesforce Functions project to GitHub, see [Add Project to GitHub](https://developer.salesforce.com/docs/platform/functions/guide/develop.md#add-project-to-github).

When making Salesforce Functions project changes, always start by creating a branch in your git repo. Work in this branch as you change your function code, or org-side changes like permission set changes. After you're ready to test in a scratch or sandbox org, be sure to commit first. After you've verified your changes, push your project commit to GitHub, create a pull request for review, and merge your reviewed changes to the main branch of your rep.

## Apply Functions and Application Lifecycle Management

To integrate your Salesforce Functions development and deployment in your application lifecycle management (ALM) process:

1. Plan your Salesforce Functions development. Understand what compute work your function is doing, what permissions your function needs, and where a user invokes your function from. Determine what language-specific packages beyond the Salesforce SDKs your function needs and include them. Determine which development, test, and integration orgs to create.
2. Develop your function. Develop and debug functions locally using the Salesforce CLI. Use git and GitHub to track function project changes and coordinate changes across your development team. Develop your Apex code and any org-side changes needed to invoke the function.
3. Test your function in a development org. Test your function locally and then deploy and test in your development (scratch or sandbox) orgs. Use scratch orgs to test just your changes, or use development sandbox orgs to coordinate testing with others on your team.
4. Deploy your function to your integration sandbox orgs. Create compute environments based on your preferred set of sandbox orgs used for testing.
5. Test your function in your integration sandbox orgs.
6. Release (deploy) your function to your production org.

Here's a simplified example walkthrough of some of the previous steps for a developer on a team developing with Salesforce Functions. This walkthrough assumes that the development team already has a DevHub org with Salesforce Functions enabled, and each team member has the appropriate DX tools installed.

1. For initial planning, the team determines that they need a new development sandbox and integration sandbox. The developer creates the sandboxes, either via the Salesforce UI or via CLI commands like the following:

```sh
sf org create sandbox --definition-file config/dev-sandbox-def.json --wait 90 --target-org DevHubOrgAlias --alias Dev_SB # Dev Sandbox
sf org create sandbox --definition-file config/int-sandbox-def.json --wait 90 --target-org DevHubOrgAlias --alias Int_SB # Integration Sandbox
```

2. The developer logs into the Dev Hub and dev and integration sandbox orgs. The developer also authenticates the Salesforce CLI to Salesforce Functions:

```sh
sf org login web --alias DevHubOrgAlias --set-default-dev-hub
sf org login web --alias Dev_SB --instance-url https://cs45.salesforce.com
sf org login web --alias Int_SB --instance-url https://cs45.salesforce.com
sf login functions
```

The developer creates a project and commits it to git for everyone to work on:

```sh
sf project generate --name BillingProj
cd BillingProj
git init
git add .
git commit -m "Initial project commit after project creation"
git remote add github https://github.com/exampleco/billingproj.git
```

Now, the developer can create a branch and develop function code, Apex code, and any other code required for the project:

```sh
git checkout -b calc-and-send
sf generate function -n calculateTax -l javascript
sf generate function -n sendInvoice -l javascript
cd force-app/main/default/classes
sf apex generate class --name calculateTax
sf apex generate class --name sendInvoice
```

At this point the developer can also run the function locally using a scratch org.

1. The developer has done some local testing using scratch orgs and wants to test in the development sandbox. They must first ensure they've done a git commit for their project:

```sh
git add -A
git commit -m "Add tax calculation and invoice sending features"
```

Next they must create a compute environment for their developer sandbox. The compute environment only needs to be created one time and other developers on the team can deploy to the same compute environment:

```sh
sf env create compute -o Dev_SB -a BillingDev_SB
```

The developer can then deploy the Salesforce Functions project to the compute environment connected to the development sandbox for testing:

```sh
sf deploy functions -o Dev_SB
```

And finally the developer deploys whatever project-side changes, such as Apex classes, to the development sandbox directly:

```sh
sf project deploy start --target-org Dev_SB
```

At this point the developer can test the function and org-side changes in the development sandbox.

4. After testing has been completed, the developer wants to deploy and test in the integration sandbox. First, the developer pushes their git branch to GitHub:

```sh
git push -u github calc-and-send
```

The developer uses the GitHub web UI to create a pull request and get a review from someone on the team before merging into the integration branch. After the changes are merged, the developer pulls the integration branch to make sure he has all the latest changes for that branch before he deploys:

```sh
git pull github integration
```

Next the developer creates a compute environment for the integration sandbox that can be used by all developers on the project:

```sh
sf env create compute -o Int_SB -a BillingInt_SB
```

The developer is ready to deploy his functions to the integration sandbox compute environment, and any project changes to the integration sandbox:

```sh
sf deploy functions -o Int_SB
sf project deploy start --target-org Int_SB
```

The developer can now test and validate the functions and org-side changes in the integration sandbox.

After all the testing and validation is complete, a user with production access can deploy this function to a production org:

1. Clone the GitHub project and switch to the correct branch.
2. Navigate to the correct branch.
3. Log in to the production org.
4. Log in to Salesforce Functions.
5. Create a compute environment for the production org.
6. Deploy your function to the compute environment and deploy source files to the production org.
7. Invoke your function as needed by your workflow.

See [Deploy a Function](https://developer.salesforce.com/docs/platform/functions/guide/deploy.md) for details.

## Add Continuous Integration/Continuous Deployment Authorization With JWT

Use JavaScript web token authorization (JWT) to set up your Salesforce Functions code to run on a Continuous Integration/Continuous Deployment (CI/CD) service. Use this process to authenticate your testing and production flow with Salesforce Functions.

### Enable Functions For Production

If you haven't done so already, enable Salesforce Functions in your production org. In **Setup**, search for **Functions** and toggle on **Enable Production Space**. Enabling Salesforce Functions allows the CI/CD service to deploy your functions code. For more information, see [Configure Orgs for Functions](https://developer.salesforce.com/docs/platform/functions/configure_your_org.md).

### Create Private Key and Certificate

If you don't have one already, [use OpenSSL to create a private key and a self-signed certificate](https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_auth_key_and_cert.htm) to use with a Connected App. The key and certificate allows your CI/CD tool to authenticate with Salesforce CLI and Salesforce Functions. Run the following commands in the root of your Salesforce Functions project:

```bash
mkdir jwt-auth && cd jwt-auth

# create key
export PASS="$(openssl rand -hex 20)"
openssl genrsa -aes256 \
  -passout "pass:$PASS" \
  -out connected-app.pass.key \
  4096
openssl rsa -passin "pass:$PASS" \
  -in connected-app.pass.key \
  -out connected-app.key
rm connected-app.pass.key

# use key to create certificate
# fill in values when prompted and set name to CI
openssl req -new \
  -key connected-app.key \
  -out connected-app.csr

openssl x509 -req -sha256 -days 365 \
  -in connected-app.csr \
  -signkey connected-app.key
  -out connected-app.crt
base64 connected-app.key > connected-app.key.base64
```

This process creates two files: `connected-app.key` and `connected-app.key.base64`. These files contain secret information that you must use to set up your CI/CD tool. Don't commit these files or push them to GitHub.

### Create a Connected App

[Create a Connected App](https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_auth_connected_app.htm) and use your key and certificate to authorize the app for use with your CI/CD tool.

In your production org's Dev Hub, click **Setup** and search for **App Manager**. Click **New Connected App** and fill in the following values:

- Name: `CI`
- Contact Email: the org admin's email
- Enable OAuth Settings: yes
- Callback URL: `https://localhost:1717/OauthRedirect`
- Use Digital Signatures: yes; select `jwt-auth/connected-app.crt` created in the previous step
- Selected OAuth Scopes:
  - Manage user data via APIs (api)
  - Manage user data via Web browsers (web)
  - Perform requests at any time (refresh_token, offline_access)
- Save the app

After you create the app, click **Edit Policies** and then **Permitted Users**. Select "Admin approved users are pre-authorized" and save the app.

Finally, in the Profiles section of the page, click **Manage Profiles**. Select "System Administrator" and save the profile assignment.

Note the **Consumer Key** in the Connected App as you use it when you set up your CI/CD service.

### Set Up Your CI/CD Service

When you set up a CI/CD project to run your Salesforce Functions code, set environment variables and configure the tool.

#### Create Environment Variables

Use the information from previous steps to set the following environment variables:

- `SFDX_CONSUMER_KEY`: the Consumer Key displayed in your Connected App
- `SFDX_JWT_KEY`: the contents of `jwt-auth/connected-app.key`
- `SFDX_USERNAME`: the Salesforce username of a System Administrator

#### Set Up Functions Project in CI/CD

In your CI/CD tool, set up a project to run your Salesforce Functions code. This process matches your existing CI/CD configuration for any other Salesforce app, except for authenticating your CLI. To authenticate in your CI/CD app, use `sf login functions jwt` to log in to both Salesforce CLI and Salesforce Functions with one command:

```bash
sf login functions jwt -u user@example.com \
  -f jwt-auth/connected-app.key \
  -i ######
```

## Run CI/CD With Every Code Commit

After running through the setup steps above, every commit to the main branch of your GitHub project will trigger CI/CD to automatically run your functions project.

For an example project that uses CircleCI and GitHub to automate testing of a function, see this [CircleCI and Salesforce Functions example](https://github.com/heroku-examples/evergreen-function-circleci).

For more information on continuous integration, see [Continuous Integration in the _Salesforce DX Developer Guide_](https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_ci.htm).
