Develop a Function

This section explains the basic developer workflow when developing a new Function. This section also details how to add build and run-time configurations for your Functions.

Once you're done developing your Function, you'll want to deploy your Function to a Salesforce compute environment, and then invoke your Function from your org.

Create a New Function Project

To create a new Function, start by creating a Salesforce DX project.

The DX project name you choose will represent the Salesforce Functions project name, that you'll use when invoking a deployed Function.

Next, use the generate:function command to populate your project with the template source files and the metadata file for your Function. For example, to create a new JavaScript-based Function named “myfunction”, you would use the following command from your DX project root directory:

The Function name must be only lowercase letters or numbers, and must start with a lowercase letter.

For beta, the only supported languages for the -l argument are "javascript", "typescript", and "java".

Creating a new Function adds the <project root>/functions/<function name> directory to your DX project, and creates default source files and build definition files for the Function in that directory. As an example, here’s an example DX project with function-specific files created for a Javascript Function named myfunction:

Create Function Using VS Code

To create a Function using VS Code with Salesforce Extensions for VS Code installed, first create a new DX project using the SFDX: Create a New Project command palette command. Use the "Standard" configuration for Function development.

Next use the SFDX: Create Function palette command to create a new Function in the current DX project open in VS Code. If you're creating a JavaScript Function note that this will also install package.json dependencies for the created Function.

For a step-by-step guide to creating a Functions project, see Developing Salesforce Functions Using Visual Studio Code.

Configure Function Dependencies

Each Function must provide a list of dependencies that the Function needs to build and run. For example, your JavaScript Function might use the Salesforce SDK for Node.js Functions, a testing framework, and various other frameworks. Depending on the language you use to develop your Function, you'll provide Function dependency information in different project configuration files.

JavaScript and TypeScript Dependencies

JavaScript or TypeScript Functions specify dependencies and build configuration information in a Node.js package.json file in the <project root>/functions/<function name>/ directory. This file is required to build and run your JavaScript or TypeScript Function. For details on the format and fields for a Node.js package.json file, see https://nodejs.dev/learn/the-package-json-guide.

Using npm install with this package.json is recommended when you start developing a Function. This installs dependencies to enable things like type support for TypeScript Functions code in VS Code, for example. You can also use npm build to verify you've added the right set of dependencies.

The following example package.json file indicates that the Function requires v1.3.0 or greater of the Salesforce SDK for Node.js Functions:

Java Dependencies

Dependencies are defined in your Function's pom.xml file for use with the Maven build tool. The following pom.xml file includes the Salesforce SDK for Java Functions in the list of dependencies:

For more information on Maven and pom.xml files, see https://maven.apache.org/.

Configure Function Information in project.toml

Each Function must provide a project.toml TOML file that contains Function metadata. This file should be located in your <project root>/functions/<function name> directory. The generate:function command will automatically create a template project.toml file that will look something like this:

Update this TOML file with any Function metadata information you need. For a list of the valid fields for project.toml see Function Metadata TOML Files. For details on the general TOML file format, see toml.io

Include the Appropriate Salesforce SDK

In your Function code, import the Salesforce Functions SDK for your programming language.

JavaScript and TypeScript SDK Import

In JavaScript, use require() to import the Salesforce SDK for Node.js Functions:

In TypeScript, use import to import the Salesforce SDK for Node.js Functions:

Java SDK Import

In Java, import classes that you need from the com.salesforce.functions.jvm.sdk package, for example:

Specify the Function Entry Point

Functions that access Salesforce data will need to have a specific code entry point that can be invoked with the invoking org’s context data and payload.

JavaScript and TypeScript Entry Point

In JavaScript and TypeScript, specify and export a execute entry point. The following JavaScript example provides an execute entry point function:

The following TypeScript example provides an execute entry point function:

Java Entry Point

Java Functions must provide a public class that implements the SalesforceFunction interface, and overrides the public apply() method. The following example provides an implementation of apply() using FunctionInput and FunctionOutput classes defined elsewhere in the Function project code:

The types supported for the input and output for SalesforceFunction are specific to the Java SDK and are described in Java Functions.

Add Project to git

It's good practice to track your project changes in a source code control system like git. When developing Functions, if you want to collaborate with other developers, you'll need to add your project to a github repo and push your Function code changes regularly. Function code, unlike Apex code, doesn't get deployed to your org, so you can't use your orgs as a way to share code.

Function code must be committed to git before you can deploy a Function. However, merging your Function code to a github.com remote repo is not required, although generally a good practice.

To add your project to github, in your browser, navigate to github.com, login to your github.com account, and create a new repository. See Create a Repo for more details on doing this on github.com. Save the git URL for your new repo.

In the DX project root directory, use the following git commands:

Access Salesforce Resources

Your Function may need to access data and resources in the org it was called from. The various Funtions SDKs provide an integrated programming model that you can use to write business logic while orchestrating with your data in the Salesforce Customer 360 platform, without having to configure a web framework or any API authentication yourself.

Use Context and DataApi

The SDKs provide context data for the calling org when your Function is invoked. This is passed as a parameter to your Function entry point. Through this context you can query and do DML on your org data. Record access is controlled using the "Functions" permission set in your org.

Through the context data you can access the DataApi interface to query, insert, and update records.

The following JavaScript example uses context.org.dataApi to make a simple query to the org that invoked the Function:

The following Java example uses the DataApi class from the context data to do a query:

UnitOfWork

For more complex access, such as complex or large transactions, the Salesforce Functions SDKs provide the UnitOfWork class. A UnitOfWork represents a set of one or more Salesforce operations that need to be done as a single atomic operation. This reduces the number of requests back to the org, and is more efficient when working with larger data volumes. UnitOfWork also lets you manage data operations in your own transactions.

The following JavaScript example (from the Context_UnitOfWork_JS sample) uses a UnitOfWork to create an Account record and related records:

For the Salesforce Functions beta, when using the Node.js SDK only, always use a new instance of UnitOfWork for each transaction and never re-use a committed UnitOfWork.

The following Java example (from the Context_UnitOfWork_Java sample) uses the UnitOfWork class from the Salesforce SDK for Java Functions (with Input and Output defined elsewhere in the Function code):

UnitOfWork uses the Composite Graph API for efficient transaction requests with higher record limits. For more details on the Composite Graph API see: REST API Developer Guide : Composite Graphs. Note that the (Composite Graph API limits)[https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/resources_composite_graph_limits.htm], such as a maximum of 15 different nodes/objects in one payload, also apply to UnitOfWork.

Use Salesforce APIs

If the provided SDK classes don't give you the data access you need, you can try making REST API calls directly to the calling org.

In the Salesforce SDK for Node.js Functions, you can use dataApi.accessToken to obtain the API access token for the invoking org, and then use this with your preferred HTTP request framework to make REST API calls back to the invoking org.

In the Salesforce SDK for Java Functions, you can use DataApi.getAccessToken() to obtain the API access token for the invoking org, and then use this with your preferred HTTP request framework to make REST API calls back to the invoking org.

Be Aware of API Limits

Most org access from Functions is similar to an API request to an org through something like the Salesforce REST API, and has similar limits. See Limits for more details on the API limits for Functions.

Function Buildpacks and Runtime Environment

run:function:start and project:deploy use a specific set of buildpacks to build the container image for your Function. If you need to use custom buildpacks with your Function, work with your Salesforce Functions contact to get more details on how to do this.

Deployed Functions currently run in the Heroku-20 environment.