Promote a Data Cloud data kit from dev to production with Lifecycle Center

A tested, step-by-step process: commit the data kit with a script, promote it through the pipeline, then deploy its components in each org.

Tested end to end in October 2026 on Winter '27 (264.7.5), through a Development → Staging → Production pipeline.
Lifecycle Center is the new name for DevOps Center; the API names are unchanged.
Use ← → to move between slides. Click a screenshot to enlarge it.
Runbook, scripts and sample metadata: github.com/congmingwudi/data360-lifecycle-center-devops

Two things to know before you start

1. DX Inspector can't commit a data kit

What happens: the data kit's components stage, then the commit fails at the last step with Commit failed during processing. Nothing reaches the work item's branch.

What works: commit-datakit-to-work-item.sh makes that commit for you. Lifecycle Center inspects it and the work item is reviewed and promoted as usual.

2. Promoting installs the data kit; it doesn't deploy it

What happens: the promotion is a Metadata API deploy. It brings the data kit's definition, templates and publishing sequence. No data stream, DLO, mapping or insight is created.

What works: after each install, run deploy-datakit-components.sh in that org. It runs the data kit's Deploy action, which creates them.

Everything else in Lifecycle Center (work items, review, Promote Selected, Promote Stage) works for data kits unchanged.

How the pieces fit

flowchart LR
  DEV["Development sandbox
afd360-dcdev1
build the data kit"] C["commit-datakit-to-
work-item.sh"] subgraph GH["GitHub: branches = stages"] WI["WI-00000N"] ST["dcstaging1"] M["main"] end LC["Hub org
Lifecycle Center"] STG["Staging sandbox afd360-dcstaging1
6 then: deploy-datakit-components.sh"] PRD["Production afd360-prod
9 then: deploy-datakit-components.sh"] DEV -->|"1 manifest + retrieve"| C C -->|"2 commit + push"| WI WI -.->|"3 inspects"| LC WI ==>|"4 Promote Selected"| ST ST -->|"5 install"| STG ST ==>|"7 Promote Stage"| M M -->|"8 install"| PRD classDef dev fill:#E2EDF5,stroke:#2F6F9F,stroke-width:2px,color:#1D2A30 classDef stg fill:#F6ECDC,stroke:#B7791F,stroke-width:2px,color:#1D2A30 classDef prd fill:#E0F0E8,stroke:#2E7D5B,stroke-width:2px,color:#1D2A30 classDef tool fill:#FFFFFF,stroke:#1D2A30,stroke-width:1.5px,color:#1D2A30 classDef hub fill:#E9EDEA,stroke:#5B6770,stroke-width:2px,color:#1D2A30 class DEV dev class STG,ST stg class PRD,M prd class C,WI tool class LC hub click C href "https://github.com/congmingwudi/data360-lifecycle-center-devops/blob/main/scripts/commit-datakit-to-work-item.sh" "Open the script on GitHub" _blank click STG href "https://github.com/congmingwudi/data360-lifecycle-center-devops/blob/main/scripts/deploy-datakit-components.sh" "Open deploy-datakit-components.sh on GitHub" _blank click PRD href "https://github.com/congmingwudi/data360-lifecycle-center-devops/blob/main/scripts/deploy-datakit-components.sh" "Open deploy-datakit-components.sh on GitHub" _blank

Numbers follow the order you do things in. Thick arrows are merges Lifecycle Center makes when you promote; each install is followed by a component deploy in that org. The Hub is the production org: it holds Lifecycle Center and is also the Production stage.

Branches are the pipeline's stages

gitGraph LR:
  commit id: "pipeline created"
  branch dcstaging1
  checkout dcstaging1
  branch WI-000008
  checkout WI-000008
  commit id: "data kit (script)"
  checkout dcstaging1
  merge WI-000008 id: "Promote Selected"
  checkout main
  merge dcstaging1 id: "Promote Stage"
  checkout dcstaging1
  branch WI-000009
  checkout WI-000009
  commit id: "updated data kit (3 files)"
  checkout dcstaging1
  merge WI-000009 id: "Promote Selected "
  checkout main
  merge dcstaging1 id: "Promote Stage "
  • The last stage owns main: Production's branch is main, the top line. Staging gets its own branch below it, dcstaging1, cut from main.
  • Each work item gets a branch WI-00000N cut from dcstaging1 when it goes In Progress. The script commits there.
  • Promote Selected merges a work item into Staging. Promote Stage merges all of Staging into main.
  • Lifecycle Center does the merges. Don't merge the pull requests on GitHub yourself.

What the promotion carries, and what you do in each org

Installed by the promotion (data kit metadata)Done in each target after the install
Data stream template and bundleDeploy the data kit's components with deploy-datakit-components.sh. This creates the stream, DLO and mappings.
DLO schema, DMO and its field mapsActivate the file connection, only if it's inactive. It was inactive in Staging and already active in Production.
Connection information (DevOps data kits carry it)First time only: Update File on the stream (upload the CSV). This activates the stream.
Calculated insights added to the data kitRun each new insight once (create-calculated-insight.sh --run-only, or Run Now).
Publishing sequence (deploy order)Make sure the data kit's data space exists. Building in default means it always does.

Never carried: the uploaded file, ingested records, and one system field map (cdp_sys_SourceVersion__c, so 10 of 11 fields map). All rows still reach the DMO.

One-time setup

Prerequisites, the pipeline, and building the data kit in the development sandbox.

Prerequisites

  • Data Cloud provisioned in production and in each sandbox (sandbox Data Cloud needs it in production first).
  • A data space with the same name in every org. Build in default and there's nothing to create.
  • Lifecycle Center permission sets on the Hub (Admin, User, Deployment Manager).
  • A GitHub repo connected to the pipeline, and push access to it.
  • On your workstation: the sf CLI logged in to every org, plus jq, git and bash, and this project's scripts/.
Hub: assign the permission sets and verify./scripts/setup-devops-center-hub.sh --target-org afd360-prod
Read-only: Data Cloud provisioned, data space ACTIVE./scripts/verify-datacloud-prereqs.sh -o afd360-dcdev1 -o afd360-dcstaging1 -o afd360-prod
Alias in this deckRole
afd360-prodHub (Lifecycle Center) and Production stage
afd360-dcstaging1Staging sandbox
afd360-dcdev1Development sandbox

Substitute your own org aliases.

The pipeline: Development → Staging → Production

  • One project, one pipeline, three stages.
  • Development (the sandbox you build in) has no branch of its own.
  • Staging deploys to the staging sandbox from dcstaging1.
  • Production deploys to the production org from main.
  • Activate the pipeline before you create work items. Otherwise moving one to In Progress fails with An unexpected error occurred.
Pipeline activated with Development, Staging and Production stages
The activated pipeline in the Hub.

Build the data in the dev sandbox

  • A File Upload data stream from a CSV, which creates its DLO.
  • Map the DLO to a DMO.
  • Build it in the default data space, which exists in every org.

The example: 50 branch offices, CSV stream → branch_offices_seedcsv__dll → custom DMO Branch_Office__dlm.

Data stream deployed in dev
DLO to DMO field mapping

Package it as a DevOps data kit

  • Data kit type: DevOps, never Standard. Only a DevOps data kit can be built in a sandbox, moves by Metadata API, and carries its connector information. You can't switch types later.
  • Add the data stream bundle. Its DLO, DMO and mappings come with it.
  • Check the Publishing Sequence: connection, then bundle.

A "You haven't defined the publishing sequence" banner may stay after you save it. It's cosmetic: the order still travels and is used in every target.

New data kit with DevOps type
Publishing sequence: connection then data stream bundle

Each change: dev to Staging

Work item, scripted commit, review, promotion, then the post-install steps in Staging.

1Create a work item and mark it In Progress

  • In the Hub: Lifecycle Center → Work Items → New. Pick the project, and the dev sandbox as the Development Environment.
  • Click Mark as In Progress. Lifecycle Center creates the branch WI-00000N from dcstaging1.
  • Note the work item's name; the script needs it.
New Work Item dialog
Work item In Progress with its WI-000009 branch
In Progress: the Branch field shows WI-000009.

Don't commit the data kit with DX Inspector

DX Inspector stages every component, then the commit fails at finalize. Retrying doesn't help. It fails the same way for any data kit, large or small.

  • Committing the data kit's components yourself (next step) is the only step that changes.
  • Ordinary metadata (flows, permission sets, fields) still commits through DX Inspector. Put it in a separate work item.
  • No failed DX Inspector attempt is needed before running the script.
DX Inspector commit failed during processing
The DX Inspector result for a data kit: Commit failed during processing.

2Commit the data kit with the script

sequenceDiagram
  autonumber
  actor You
  participant S as commit-datakit-to-work-item.sh
  link S: Open on GitHub @ https://github.com/congmingwudi/data360-lifecycle-center-devops/blob/main/scripts/commit-datakit-to-work-item.sh
  participant Dev as Dev sandbox
  participant Stg as Staging (check-only)
  participant Git as GitHub WI-00000N
  participant LC as Lifecycle Center (Hub)
  You->>S: data kit, work item, orgs
  S->>LC: Work item In Progress? Branch exists?
  S->>Dev: GET the data kit's manifest
  S->>Dev: Retrieve exactly those members
  Note over S: Drop the KQ_* key qualifier field
Raise sourceApiVersion to 64.0 S->>Stg: Check-only deploy (nothing changes) S->>Git: Commit as you, push fast-forward only Git-->>LC: Lifecycle Center inspects the push LC-->>S: Work item's Change List S-->>You: OK, the Change List matches the commit

2Commit the data kit: commands and result

Dry run: builds and validates the commit, pushes nothing./scripts/commit-datakit-to-work-item.sh \
  -k branch_offices_datakit -s afd360-dcdev1 \
  --hub afd360-prod -w WI-000009 \
  --validate-org afd360-dcstaging1 --dry-run
Real run: commit, push, wait for the inspection./scripts/commit-datakit-to-work-item.sh \
  -k branch_offices_datakit -s afd360-dcdev1 \
  --hub afd360-prod -w WI-000009 \
  --validate-org afd360-dcstaging1
  • The data kit's own manifest decides what's committed, so nothing is missed and nothing extra goes in.
  • It works in a separate git worktree under tmp-cli-validation/. Your checkout isn't touched.
  • Check the data kit's contents in Data Cloud Setup first: the manifest only lists what's in the data kit.
Work item Change List with 3 changed components
The Change List Lifecycle Center built from the pushed commit.
Activity History: commit started, components, commit completed
Activity History records it as a normal, successful commit.

3Create the review, then mark it Ready to Promote

  • In DX Inspector in the dev sandbox, on the work item, click Create Review. Lifecycle Center opens a pull request from WI-00000N to dcstaging1.
  • The work item moves to In Review. Review the pull request as your process requires.
  • Click Mark as Ready to Promote. Don't merge the pull request on GitHub.
Review for WI-000009 was created
Work item In Review with Mark as Ready to Promote

4Promote Selected to Staging

  • Open the pipeline. The work item is under Approved Work Items.
  • Select it and click Promote Selected.
  • Options: Only changes missing from Staging, No tests (a data kit has no Apex).
  • Lifecycle Center merges into dcstaging1 and deploys to the staging sandbox.

This only installs the data kit. Continue with the post-install steps.

Pipeline with WI-000009 in Approved Work Items
Promotion Successful, WI-000009 in Staging

After each install: what happens in the target org

sequenceDiagram
  autonumber
  participant LC as Lifecycle Center
  participant T as Target org (Staging, then Production)
  actor You
  LC->>T: Metadata API deploy: data kit definition, templates, publishing sequence
  Note over T: Installed. No stream, DLO, mapping or insight yet
  You->>T: Activate the UploadedFiles connection (only if inactive)
  You->>T: deploy-datakit-components.sh (Connect API: deploy the data kit)
  T-->>You: Job Complete: stream (inactive), DLO, mappings, insights
  You->>T: Update File: upload the CSV, Deploy (first time only)
  Note over T: Stream active, rows flow to the DMO
  You->>T: Run each new calculated insight once

Scripts: deploy-datakit-components.sh, create-calculated-insight.sh.

5Activate the file connection, if it's inactive

Data Cloud Setup → Other Connectors → UploadedFiles (File Upload). An inactive connection makes the component deploy fail.

  • Staging: it was inactive; activate it.
  • Production: it was already active, and the data kit left it alone. Skip the step.
Check the connection's statesf data query -o afd360-dcstaging1 --query "SELECT DeveloperName, ConnectionState FROM MktDataConnection WHERE DeveloperName = 'UploadedFiles'"
UploadedFiles connector Active
An active UploadedFiles connection (shown here in the dev sandbox; it looks the same in each target).

6Deploy the data kit's components

Dry run: what's installed, what's deployed, what's pending./scripts/deploy-datakit-components.sh -k branch_offices_datakit -o afd360-dcstaging1 --dry-run
Deploy, wait for the job, verify./scripts/deploy-datakit-components.sh -k branch_offices_datakit -o afd360-dcstaging1
  • It runs the data kit's Deploy action through the Connect API, then polls the job.
  • It compares the publishing sequence with the data kit's deployment log, and deploys only if something was never deployed.
  • It checks every item and ends with one RESULT line.

Never run two deploys of one data kit at once. Both try to create the DLO, and one fails with already exists.

==> Publishing sequence vs. what's deployed in afd360-dcstaging1:
      1. DataConnection: UploadedFiles — connection (redeploys harmlessly)
      2. DataStreamBundle: branch_offices_bundle — NOT DEPLOYED
==> Deploying branch_offices_datakit components in afd360-dcstaging1 ...
    job status: InProgress
    job status: Complete
==> Deployment log for job 08P…:
      21:51:05  (kit)  Successful
      21:51:07  UploadedFiles  Successful
      21:51:41  branch_offices_seedcsv  Successful
==> Streams in afd360-dcstaging1: 1 of 1
      branch_offices_seedcsv: INACTIVE
==> RESULT: SUCCESS. Job 08P… deployed every item.

The stream arrives inactive. That's expected; the next step activates it.

7Upload the file to activate the stream

  • Data Streams → the stream → Update File.
  • Keep Full Refresh, upload the CSV, wait for File Upload Complete, click Deploy.
  • The stream turns Active and runs once. Rows reach the DLO and the DMO.

Needed once per org, because a data kit carries the stream's configuration but never the uploaded file. Later component deploys keep the stream and its data.

Inactive stream with Update File button
Update Data Stream from a File dialog

Staging to Production

Promote the whole stage, then repeat the post-install steps in production.

8Promote Stage to Production

  • In the Staging column, click Promote Stage. It promotes every work item in Staging together, by merging dcstaging1 into main.
  • Keep the defaults: Promote Now, Only changes missing from Production, No tests.

"Can't validate promotion… source control is checking the pull request" is temporary. GitHub is still checking the merge. Wait a minute and click Promote Stage again.

Pipeline with WI-000009 in Staging and Promote Stage enabled
Can't validate promotion message

9Repeat the post-install steps in production

Connection already active? (it was, in our production org)sf data query -o afd360-prod --query "SELECT DeveloperName, ConnectionState FROM MktDataConnection WHERE DeveloperName = 'UploadedFiles'"
Deploy the components./scripts/deploy-datakit-components.sh -k branch_offices_datakit -o afd360-prod --dry-run
./scripts/deploy-datakit-components.sh -k branch_offices_datakit -o afd360-prod
  • Then Update File on the stream, the first time (the row menu in the Data Streams list works too).
  • Result: the stream is Active, its last run succeeded, and the DLO and DMO each hold all 50 rows.
Data Streams list row menu with Update File
Production stream Active, Success, 50 records

Updating a data kit

Tested by adding a calculated insight to the deployed data kit and promoting it to both targets.

Add the component in dev, then commit the change

  1. Create the calculated insight in the dev sandbox (the UI, or the example script below).
  2. Data Kits → the data kit → add the insight. Check the Publishing Sequence lists it after the bundle.
  3. New work item, In Progress, then the same commit script.
Example insight, dev sandbox only./scripts/create-calculated-insight.sh -o afd360-dcdev1 --run

The commit carried only the change: 3 files (the insight template, its data kit membership, and the data kit definition's new deploy order). The same data kit is updated; no new data kit is needed.

Add Calculated Insights to the data kit
Calculated insight created in dev

In each target: promote, deploy the components, run the insight

The promotion again only installs. The dry run shows the new insight as NOT DEPLOYED. The component deploy replays the whole sequence:

Log rowResult
(kit)Successful
UploadedFilesSuccessful (redeployed)
branch_offices_seedcsvSuccessful (redeployed in place, data kept)
Branch Footprint by RegionSuccessful (new)
Run the insight the data kit deployed (target orgs: never create one)./scripts/create-calculated-insight.sh -o afd360-prod --run-only

No re-upload needed: the stream stayed Active with its 50 rows. A new insight arrives active but never run, so run it once.

Calculated insight in staging, Run Now
Query Editor in production returning the insight's 24 rows
Production: the insight returns the same 24 region and country rows as dev.

Command cheat sheet

Once

./scripts/setup-devops-center-hub.sh --target-org afd360-prod
./scripts/verify-datacloud-prereqs.sh -o afd360-dcdev1 -o afd360-dcstaging1 -o afd360-prod

Each change: commit (after Mark as In Progress)

./scripts/commit-datakit-to-work-item.sh -k branch_offices_datakit -s afd360-dcdev1 \
  --hub afd360-prod -w WI-00000N --validate-org afd360-dcstaging1 --dry-run
./scripts/commit-datakit-to-work-item.sh -k branch_offices_datakit -s afd360-dcdev1 \
  --hub afd360-prod -w WI-00000N --validate-org afd360-dcstaging1

Then in the UI: Create Review, Ready to Promote, Promote Selected.

After Promote Selected: Staging

./scripts/deploy-datakit-components.sh -k branch_offices_datakit -o afd360-dcstaging1 --dry-run
./scripts/deploy-datakit-components.sh -k branch_offices_datakit -o afd360-dcstaging1
./scripts/create-calculated-insight.sh -o afd360-dcstaging1 --run-only

After Promote Stage: Production

./scripts/deploy-datakit-components.sh -k branch_offices_datakit -o afd360-prod --dry-run
./scripts/deploy-datakit-components.sh -k branch_offices_datakit -o afd360-prod
./scripts/create-calculated-insight.sh -o afd360-prod --run-only

Before the first deploy in an org: activate the connection if it's inactive. After it: Update File on the stream.

Gotchas we hit, and what to do

  • DX Inspector commit fails for any data kit. Use the commit script; keep other metadata in a separate work item.
  • Key qualifier field (KQ_*) can't be deployed. The commit script removes it; the component deploy recreates it.
  • API 62.0 fails on the data kit definition (useDeterministicNaming). The script raises sourceApiVersion to 64.0.
  • The component deploy API exists from v64.0, takes an empty {} body for a DevOps data kit, and ends Complete. The script handles all three.
  • Two deploys at once fail with a data lake object … already exists. Wait for one to finish.
  • "Can't validate promotion" on Promote Stage is temporary. Retry after a minute.
  • Don't create a calculated insight by hand in a target. It isn't owned by the data kit, and no data kit can update it later. Use --run-only.
  • The data space must exist in the target under the same name. default always does.
  • The stream arrives inactive and needs Update File once. The uploaded file never travels.
  • One system field map (cdp_sys_SourceVersion__c) doesn't cross. Map it by hand if you need it.
  • The publishing-sequence banner can stay after you save. It's cosmetic.

Salesforce sources

The runbook, scripts and sample kit metadata are in github.com/congmingwudi/data360-lifecycle-center-devops. The scripts are bash and run against any orgs you're logged in to with the sf CLI. Each takes the org alias, is safe to re-run, and checks its own result. Run the dry run first.