💾 SFDX Data Import
This repository implements a simple GitHub composite action for uploading records to any kind of Salesforce org from within CI/CD automations based on CSV (Bulk API 2.0) or JSON (sObject Tree) format.
Usage
After installing the SF CLI and authorizing the relevant org in your GitHub workflow, data can be imported using this action as follows:
jobs:
validation:
name: Validation
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout
uses: actions/checkout@v7.0.1
with:
persist-credentials: false
- name: Select Node Version
uses: svierk/get-node-version@v1.5.2
- name: Install Dependencies
run: npm ci
- name: Install SF CLI
uses: svierk/sfdx-cli-setup@v1.2.0
- name: Salesforce Org Login
uses: svierk/sfdx-login@v1.4.3
with:
sfdx-url: ${{ secrets.SFDX_AUTH_URL }}
alias: awesome-org
- name: CSV Data Import
uses: svierk/sfdx-data-import@v1.4.0
with:
file-path: './data/accounts.csv'
object-type: 'Account'
external-id: 'Id'
target-org: awesome-org
- name: JSON Data Import
uses: svierk/sfdx-data-import@v1.4.0
with:
file-path: './data/accounts.json,./data/contacts.json'
api-version: '59.0'The following actions were also used in the example workflow to create the prerequisites for the data import:
- Get Node Version | Pulls Node.js version to be used from the package.json of the project
- SFDX CLI Setup | Installs the Salesforce CLI and related plugins
- SFDX Login | Handles Salesforce login using a Salesforce DX authorization URL
The file format is detected automatically from the file extension:
.csvfiles are uploaded via Bulk API 2.0 and require theobject-typeinput (theexternal-iddefaults toId)..jsonfiles are imported via the sObject Tree API and may be passed as an in-order list of files (see below).
Any other extension, a mix of extensions, more than one CSV file, or a CSV upload without object-type fails the step with a clear error instead of silently doing nothing.
Of course, the data import action can be used flexibly and the respective approach can vary.
List input (comma-separated or multi-line)
The file-path input accepts a comma-separated string as well as a multi-line block, and the two notations can be mixed freely within one step. A comma-separated string keeps short lists on a single line, a block stays readable once a list grows:
- name: JSON Data Import
uses: svierk/sfdx-data-import@v1.4.0
with:
file-path: | # multi-line block
./data/accounts.json
./data/contacts.json
./data/opportunities.jsonThe files are imported in the given order, so list parent records before the child records that reference them. Surrounding whitespace and blank lines are ignored, so './data/accounts.json, ./data/contacts.json' is read exactly like the tightly packed './data/accounts.json,./data/contacts.json'. Whitespace inside a path is kept, e.g. for ./my data/accounts.json.
Inputs
| Name | Required | Default | Description |
|---|---|---|---|
file-path | yes | Path to the CSV or JSON file(s) to upload. CSV supports a single file; JSON supports an in-order list, comma-separated or multi-line. | |
object-type | no | API name of the Salesforce object. Required for CSV (Bulk API 2.0) uploads. | |
external-id | no | Id | Name of the external ID field (or Id). Used for CSV (Bulk API 2.0) uploads. |
target-org | no | Username or alias of the target org. Not required if the default org is set. | |
api-version | no | Override the api version used for api requests, e.g. 59.0. | |
step-summary | no | true | Write a result section to the GitHub Actions job summary. Set to false to avoid collisions with a custom workflow summary. |
Security & versioning
Every uses: reference in the snippet above is pinned to an exact release tag, e.g. svierk/sfdx-data-import@v1.4.0. Do the same in your own pipelines:
- Never reference a mutable ref such as
@mainor@v1. It runs whatever code sits on that branch/tag at run time - with access to your org credentials - so a compromised or rewritten ref would run unnoticed. - Good - pin to an exact release tag (
@v1.4.0). Readable, concrete, and bumped through reviewed pull requests. - Strictest - pin to a full-length commit SHA (
@a1b2c3d…) with the version as a trailing comment. A SHA can never be re-pointed by the publisher; the cost is readability. Worth it for actions from publishers you don't control. - Enable Dependabot for
github-actionsin the repository that hosts the workflow, so those pins are bumped for you instead of silently ageing.
This applies to all actions your workflow references - this action as well as actions/* and any other third-party action.
Beyond pinning, a few rules are worth following in the workflow that calls this action:
- Secrets travel as secrets - hand the SFDX Auth URL straight into the
sfdx-urlinput of sfdx-login as shown above. Never interpolate a secret into arun:script via${{ ... }}- that allows command injection and can leak the value into the log. This action follows the same rule internally: every input is exposed to the shell as an environment variable and referenced as"$FILE_PATH","$TARGET_ORG"and so on. - Least-privilege
GITHUB_TOKEN- declare apermissions:block granting only what the job needs. A data import needs no write access at all, socontents: readis enough. persist-credentials: falseon checkout - the token is not written to.git/config, so later steps (SF CLI, third-party actions) cannot reuse it.- Validate pull requests with
pull_request, neverpull_request_target- the latter runs with the base repository's secrets, which would let a fork import its own data into your org.
References
The data import options supported by this GitHub composite action can be found in the Salesforce CLI Command Reference here:
- data import tree (JSON format)
- data upsert bulk (CSV format)
Releases
Latest release notes can be found on the release page.
License
The scripts and documentation in this project are released under the MIT License.
➡️ Full source & releases: svierk/sfdx-data-import
