> ## Documentation Index
> Fetch the complete documentation index at: https://docs.elementum.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Deploy Apps between Environments

> Deploy apps from one organization environment to another, configure post-deployment data connections, and review deployment history

<Warning>
  **Labs feature.** Deployments depend on Environments, which is marked with the **Labs** badge in the Elementum UI because the feature is still being validated. Behavior, scope, and availability may change before the feature reaches General Availability, and not all Elementum customers have access yet. See [Upcoming Features](/release-notes/upcoming-features#labs-tag-in-the-platform) for what the Labs tag means.
</Warning>

**Deployment** copies an app and its configuration from a source environment to a target environment. Before deploying, make sure both environments exist and have CloudLink configured. See [Understand and Configure Environments](/administration/understand-organization-environments) for the prerequisites.

<Callout icon="shield-halved" color="#8B5CF6" iconType="solid">
  **Required Permission:** You must hold the **DEPLOY\_APPS** permission for the target environment to deploy an app to it. See [Who can deploy](#who-can-deploy) below.
</Callout>

## How deployment works

You can deploy in any direction: from a non-production environment to Production, from Production into another environment to test changes, or between non-production environments.

**What is included in a deployment**

Automations; record layouts, related views, and form builder configuration; Flow definitions; approval processes; assignment rules; and report and analytics configuration for that app. In addition, any other objects your app depends on are included, recursively — see [Related objects included in deployment](#related-objects-included-in-deployment) below.

**What is not included in a deployment**

Role membership — which users and groups are assigned to a role — is **not** part of deployment. Elementum never modifies role membership during any deployment — initial or subsequent. When you deploy an app, element, or task into an environment for the first time, role membership from the source does not carry over. The owner of the deployed object is responsible for configuring role membership in the target environment after the first deploy, directly on the object's **Roles & Permissions** page in that environment. No future redeployment of that object will ever overwrite membership settings that have been configured in the target environment.

**Phone numbers** are environment-specific and do not transfer with a deployment. A deployment copies the phone service configuration but leaves the target environment's copy without a live number, so each environment keeps its own phone number — see [Phone services](#phone-services).

<Note>
  Deployment is different from environment creation. When an environment is first created, roles and role membership are cloned from Production into the new environment as its starting state. After that, deploying an app, element, or task into the environment does not carry membership with it — see [Environment-specific role membership](/administration/understand-organization-environments#environment-specific-role-membership).
</Note>

<Info>
  Deployment controls **what** an app does (configuration, automations, flows). **Who** can access it in each environment is always managed separately through [environment-specific role membership](/administration/understand-organization-environments#environment-specific-role-membership).
</Info>

<Warning>
  Role membership is **not** part of the post-deployment **Configure** prompt. That prompt only handles Snowflake field mapping for Tables and Elements (see [Post-deployment configuration](#post-deployment-configuration)). Configure role membership separately on each object's **Roles & Permissions** page in the target environment.
</Warning>

The deployment is tracked with status and history on the app's **Deployments** page.

## Related objects included in deployment

When you deploy an app, you're not just deploying that app — you're deploying **everything the app needs to work**. If your app relies on another object for updates or information (another app, element, task, table, or similar), that object is included in the deployment and overwrites whatever version currently exists in the target environment.

### How dependencies are followed

The system looks at your app and finds every object it references. Then it looks at *each of those* objects and finds *their* references. It keeps going — layer after layer — until no new objects are discovered. This is why deploying one app can bring in dozens or hundreds of objects: you're getting the app's dependencies, its dependencies' dependencies, and so on.

For example, deploying a **Purchase Orders** app might pull in:

```
Purchase Orders  →  Vendors app (referenced by a dropdown)
                     →  Audit Log app (written to by a Vendors automation)
                          →  Compliance report (draws from Audit Log)
```

You deployed one app; four moved.

Dependencies are directional. Deploying an app that depends on another object brings that object along, but the reverse is not true — deploying a shared object on its own does not automatically pull in the apps that reference it.

### What creates a dependency

Anywhere one object points at another, that connection is followed during deployment. The most common sources of dependencies are:

| Category                        | Examples                                                                                                                                               |
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Connections between objects** | Relationships and related fields; dynamic dropdowns sourced from another object; calculated or lookup fields that read another object's data           |
| **Automations**                 | Actions that read or write another object (for example, create record, search records, search table); a datamine trigger pulls in its underlying table |
| **Flows**                       | Any object referenced in a flow                                                                                                                        |
| **Views and layouts**           | Related views embedded in the app                                                                                                                      |
| **Reports and analytics**       | Reports that draw from another object                                                                                                                  |
| **Agents' tools and skills**    | Tools or skills that reference another object                                                                                                          |
| **Tables and their sources**    | A table brought in via a Search Table action or datamine also brings the objects that table is built from                                              |

<Info>
  This table covers the most common sources of dependencies but is not exhaustive. As new features are added to Elementum, new kinds of references between objects can also become dependencies. The rule is the same in every case: any reference from one object to another is followed during deployment.
</Info>

### In-progress work on shared objects is deployed too

Because deployment always uses the **source environment's current version** of every dependent object, and always overwrites the target, in-progress work on a shared object can be promoted unintentionally.

<Warning>
  If a teammate has been editing an object your app depends on — for example, a shared Vendors app, a table used by a dropdown, or an automation your flow calls — the version they have in the source environment (including any work in progress) is what gets deployed to the target. Deploying your app can promote their changes even if that was not your intent.
</Warning>

Before deploying an app that has dependencies, coordinate with the owners of any shared objects to confirm what's in source is ready to promote.

### Review dependencies before promoting

Because dependencies are followed recursively, review the full set of objects that will move before you promote — especially to Production. Open each dependency in the source environment and confirm its current state is what you want in the target.

<Tip>
  To prevent a related object from deploying alongside your app, delete the reference that creates the dependency or edit it so the two objects no longer reference each other. Deactivating an automation or other configuration is not enough — the dependency still exists as long as the reference is in place.
</Tip>

## Who can deploy

Promotion to each environment is gated by the **DEPLOY\_APPS** permission for **that environment**. Edit or admin rights on an app no longer imply the right to deploy it; users must hold DEPLOY\_APPS in the target environment to push an app there.

| Behavior                           | What it means                                                                                                                                                                                                                                                             |
| ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Per-environment**                | DEPLOY\_APPS is granted independently in each environment. A user with DEPLOY\_APPS in Staging cannot promote to Production unless they also hold it in Production.                                                                                                       |
| **Decoupled from app edit rights** | Granting someone the ability to update an app's configuration does not give them the ability to promote that app. Configure who can build apps and who can release them as separate decisions.                                                                            |
| **Granted through roles**          | Admins assign DEPLOY\_APPS through a role (managed or custom) in the target environment. Role membership is environment-specific — see [Environment-specific role membership](/administration/understand-organization-environments#environment-specific-role-membership). |

<Info>
  A user typically needs DEPLOY\_APPS in every environment they release to. For a `Dev → Stage → Prod` pipeline, the same release engineer commonly holds DEPLOY\_APPS in both Stage and Prod, while developers hold it only in Dev.
</Info>

### Initial vs. subsequent deployments

The first time you deploy an app to a target environment, settings are copied from the source. On later deployments to the same target, most configuration is updated to match the source, but the following **destination** values are left as you set them in that environment:

| Configuration            | Initial deployment                                                             | Later deployments                                                      |
| ------------------------ | ------------------------------------------------------------------------------ | ---------------------------------------------------------------------- |
| **AI Search target lag** | Copied from source                                                             | Target environment's value is kept                                     |
| **Access policies**      | Copied from source — only when the object does not already exist in the target | Target environment's policies are kept; deployment does not touch them |
| **Role membership**      | Not copied — must be configured manually                                       | Never overwritten by Elementum                                         |

<Info>
  After the first deployment, you can set AI Search target lag and access policies per environment; later deployments will not overwrite those choices. Role membership is never part of any deployment and must always be set up independently in each environment.
</Info>

### Access policy changes outside of a deployment

Changes you make to a Data Access policy (outside of a deployment) are scoped to the environment you are signed in to. They do **not** propagate to other environments.

* Removing a group's access to an app in one environment does not remove that group's access in any other environment.
* To remove or change access across all environments, repeat the change in each environment separately.

This is the same model used for role membership: the [environment indicator](/administration/understand-organization-environments#environment-categories) always shows which environment your change will apply to.

## Deploy an app

<Steps>
  <Step title="Navigate to the App">
    Open the <img src="https://mintcdn.com/elementum/qCzryjcKPIeW4b77/images/icons/apps.png?fit=max&auto=format&n=qCzryjcKPIeW4b77&q=85&s=c9636b6549744cccd29646e3723a299f" alt="Apps icon" className="inline-ui-icon" width="24" height="24" data-path="images/icons/apps.png" /> **app** you want to deploy in its **source environment** (the environment where the app currently exists).

    For example, to deploy an app from Development to Production, open the app in the Development environment.
  </Step>

  <Step title="Open Deployments">
    In the app's left navigation, under the **Configuration** section, click **Deployments**.

    The Deployments page shows all available environments with their deployment status.
  </Step>

  <Step title="View Environment Status">
    Each environment is displayed as a card showing:

    * **Environment name** and description
    * **Status indicator**: Deployed (green), Deploying (yellow), Failed (red), or Not Deployed (gray)
    * **Deploy button** to initiate deployment

    The right panel shows **Deployment History**. For what each record includes, see [Deployment history](#deployment-history) below.
  </Step>

  <Step title="Initiate Deployment">
    Find the target environment (where you want to deploy the app) and click the **Deploy** button on its card.

    A confirmation modal appears:

    * Title: "Deploy App To Environment"
    * Message: "Deployment will copy all app configurations and associated objects to the target environment."
    * Visual showing the deployment flow from source to target
    * Summary: "Deploy App from \[Source] to \[Target]"
  </Step>

  <Step title="Confirm and Deploy">
    Review the deployment details and click **Deploy** to proceed.

    The deployment process begins:

    * Status changes to "Deploying" (yellow)
    * Progress bar shows deployment progress
    * Upon completion, status changes to "Deployed" (green)

    <Info>
      Initial vs. subsequent deployments behave differently for some settings (for example AI Search target lag and Access Policies). See [Initial vs. subsequent deployments](#initial-vs-subsequent-deployments).
    </Info>
  </Step>

  <Step title="Monitor Deployment">
    Track deployment progress:

    | Status           | Description                                   |
    | ---------------- | --------------------------------------------- |
    | **Deploying**    | Deployment is in progress                     |
    | **Deployed**     | Deployment completed successfully             |
    | **Failed**       | Deployment encountered an error               |
    | **Not Deployed** | App has not been deployed to this environment |

    View the **Deployment History** panel for the full deployment log, including outcome and any error details for failed deployments.
  </Step>
</Steps>

## Post-deployment configuration

Apps whose <img src="https://mintcdn.com/elementum/qCzryjcKPIeW4b77/images/icons/tables.png?fit=max&auto=format&n=qCzryjcKPIeW4b77&q=85&s=30d253ecbf5bf015a9fa5def7cb769bc" alt="Tables icon" className="inline-ui-icon" width="24" height="24" data-path="images/icons/tables.png" /> **Tables** or <img src="https://mintcdn.com/elementum/qCzryjcKPIeW4b77/images/icons/elements.png?fit=max&auto=format&n=qCzryjcKPIeW4b77&q=85&s=1f6ffd07425e91ffc9c17b5885e300dd" alt="Elements icon" className="inline-ui-icon" width="24" height="24" data-path="images/icons/elements.png" /> **Elements** use Snowflake need extra steps in the **target** environment after deployment: pick database, schema, and table in that environment's CloudLink, and map fields. Apps with no Snowflake dependencies are ready once deployment finishes.

### Apps without external dependencies

For apps that don't connect to Snowflake data:

* Deployment completes immediately
* Environment card shows green "Deployed" status
* No additional configuration required
* App is ready to use in the target environment

### Apps with Snowflake dependencies

For apps with <img src="https://mintcdn.com/elementum/qCzryjcKPIeW4b77/images/icons/tables.png?fit=max&auto=format&n=qCzryjcKPIeW4b77&q=85&s=30d253ecbf5bf015a9fa5def7cb769bc" alt="Tables icon" className="inline-ui-icon" width="24" height="24" data-path="images/icons/tables.png" /> **Tables** or <img src="https://mintcdn.com/elementum/qCzryjcKPIeW4b77/images/icons/elements.png?fit=max&auto=format&n=qCzryjcKPIeW4b77&q=85&s=1f6ffd07425e91ffc9c17b5885e300dd" alt="Elements icon" className="inline-ui-icon" width="24" height="24" data-path="images/icons/elements.png" /> **Elements** linked to Snowflake, configure the data connections in the new environment.

<Steps>
  <Step title="Open configuration">
    After deployment completes, the **Deploy** button changes to **Configure**.

    The card shows:

    * Green "Deployed" status pill
    * "Complete" progress indicator
    * **Configure** button

    Click **Configure** to open the target environment.
  </Step>

  <Step title="Review Items Needing Configuration">
    The **Resolve Issues** modal appears with the message: "Review and resolve configuration issues before proceeding with deployment."

    The left panel lists all **Datasets** (Tables and Elements) that need configuration, each showing:

    * Dataset name
    * Configuration status ("Not configured")
    * Error count indicating fields needing mapping
  </Step>

  <Step title="Select a Dataset">
    Click on a Dataset in the left panel to configure it.

    The right panel shows:

    * Dataset name and error count
    * "Configure data source connection and field mappings"
    * Valid fields count and errors count
  </Step>

  <Step title="Configure Data Connection">
    The CloudLink is pre-selected. Configure the data source:

    1. **Database** - Select the database from the dropdown
    2. **Schema** - Select the schema containing your data
    3. **Table** - Select the table that corresponds to this dataset
  </Step>

  <Step title="Map Fields">
    After selecting the table, map each field:

    | Target Field                | Action                                                                     |
    | --------------------------- | -------------------------------------------------------------------------- |
    | Field from the deployed app | Select the corresponding **Source Field** from the new environment's table |

    For each Target Field listed:

    * Use the dropdown to select the matching Source Field
    * Ensure data types align (TEXT to TEXT, NUMBER to NUMBER, etc.)
    * Repeat for all fields in the dataset
  </Step>

  <Step title="Save Configuration">
    After mapping all fields for all datasets:

    1. Click **Configure Dataset** to save the configurations
    2. Configured items are removed from the list
    3. Continue until all items are configured
    4. When the list is empty, the modal closes

    The app is now fully configured and ready to use in the target environment.
  </Step>
</Steps>

### Phone services

Phone numbers are **environment-specific** and are **not** carried over by a deployment. A deployment copies the phone service itself — including its assigned agent and language settings — but the target environment's copy arrives **unconfigured**, without a live phone number. The source environment is untouched and keeps its existing number.

This is by design: a phone number can only route calls to a single destination. If the same number were active in two environments (for example, QA and Production), there would be no way to determine which one should receive an incoming call. For that reason, each environment uses its own number, and dev and production numbers are different by default.

After deploying, configure the phone service in the **target** environment before it can take calls:

<Steps>
  <Step title="Open the deployed phone service">
    In the target environment, open the app and go to **App Details** → **Phone Services**. Edit the phone service that was deployed in an unconfigured state.
  </Step>

  <Step title="Provision or import a number">
    Either provision a new number by area code or import an existing Twilio number for this environment. See [Configure a phone number in your app](/ai-agents/agents-phone-integration#configure-a-phone-number-in-your-app) for the full configuration steps.
  </Step>

  <Step title="Save the service">
    Save the phone service. The number is now live in the target environment only.
  </Step>
</Steps>

<Note>
  To reuse the same number in a different environment, you must move it rather than copy it: release the number from the source environment first, then import it into the target environment. Removing a phone service in Elementum does **not** release the number from your Twilio account — release it in Twilio if you need to re-import it elsewhere. A single number cannot be active in two environments at the same time.
</Note>

<Tip>
  Reserve your public-facing phone numbers for Production, and use separate test numbers in lower environments such as Development, QA, and Staging. This keeps live traffic from reaching a non-production build, avoids the need to move a number back and forth between environments, and lets you validate phone services safely before promoting an app to Production.
</Tip>

## Deployment history

Each app keeps a log of deployments: who ran them, source and target environment, time, outcome (**Success** or **Failure**), and error details on failed runs. Error details stay on the record even after related background work is removed.

Any user who can open the app can open **Deployments** and read this history. It is paginated and includes the full history, not only recent entries.

| Field                  | Description                           |
| ---------------------- | ------------------------------------- |
| **Source environment** | Where the app was deployed from       |
| **Target environment** | Where it was deployed to              |
| **Initiated by**       | User who started the deployment       |
| **Timestamp**          | When the deployment started           |
| **Outcome**            | **Success** or **Failure**            |
| **Error details**      | On failures, shown on the same record |

## Example workflows

<AccordionGroup>
  <Accordion title="Develop, then release">
    1. Add a Development environment from Production.
    2. Deploy an app into Development and change it there.
    3. When satisfied, deploy from Development to Production.
  </Accordion>

  <Accordion title="Staging before production">
    1. Add Staging (and optionally Development).
    2. Move apps Development → Staging for review, then Staging → Production when approved.
  </Accordion>

  <Accordion title="Training">
    1. Add a Training environment and deploy the apps users will see in Production so they can practice without touching live data.
  </Accordion>
</AccordionGroup>

## Troubleshooting

<AccordionGroup>
  <Accordion title="Deployment Fails Immediately">
    **Possible Causes:**

    * CloudLink not configured in target environment
    * CloudLink credentials invalid or expired
    * Network connectivity issues

    **Solutions:**

    1. Verify CloudLink is configured in the target environment
    2. Test CloudLink connection in <img src="https://mintcdn.com/elementum/TFCVHNVI8zhq54sg/images/icons/settings.svg?fit=max&auto=format&n=TFCVHNVI8zhq54sg&q=85&s=3ffc43e8a0875412cc27335241aeb4c8" alt="Settings icon" className="inline-ui-icon" width="24" height="24" data-path="images/icons/settings.svg" /> **Organization Settings**
    3. Check Snowflake service account permissions
  </Accordion>

  <Accordion title="Cannot See Target Environment">
    **Possible Causes:**

    * Environment not yet created
    * Insufficient permissions to view environments

    **Solutions:**

    1. Verify the environment exists in <img src="https://mintcdn.com/elementum/TFCVHNVI8zhq54sg/images/icons/settings.svg?fit=max&auto=format&n=TFCVHNVI8zhq54sg&q=85&s=3ffc43e8a0875412cc27335241aeb4c8" alt="Settings icon" className="inline-ui-icon" width="24" height="24" data-path="images/icons/settings.svg" /> Organization Settings > Environments
    2. Contact your administrator to check access permissions
  </Accordion>

  <Accordion title="Field Mapping Errors">
    **Possible Causes:**

    * Table structure differs between environments
    * Missing columns in target environment's table
    * Data type mismatches

    **Solutions:**

    1. Verify the target table exists and has the expected columns
    2. Check that column names match or can be mapped correctly
    3. Ensure data types are compatible between source and target
  </Accordion>

  <Accordion title="Configure Button Not Appearing">
    **Possible Causes:**

    * Deployment still in progress
    * App has no external dependencies (no configuration needed)

    **Solutions:**

    1. Wait for deployment to complete (status shows "Deployed")
    2. If no Configure button appears after deployment, the app has no Snowflake dependencies and is ready to use
  </Accordion>

  <Accordion title="Using the Same Snowflake User Across Environments in Different Organizations">
    **Scenario:**
    You need to use the same Snowflake user account with key-pair authentication for CloudLinks in environments that belong to **different organizations**.

    **Solution:**
    Snowflake supports key-pair rotation, which allows you to configure a second public key for the same user account. This enables environments in both organizations to authenticate simultaneously without disrupting existing connections.

    <Info>
      **Important:** Key-pair rotation is only required when using the same Snowflake user across environments in **different organizations**. If you are using the same Snowflake user across multiple environments within the **same organization**, key-pair rotation is not necessary because they share the same public key.
    </Info>

    **Steps:**

    1. **Obtain the Public Key from the Organization You Are Adding the CloudLink To:**
       * Navigate to <img src="https://mintcdn.com/elementum/TFCVHNVI8zhq54sg/images/icons/settings.svg?fit=max&auto=format&n=TFCVHNVI8zhq54sg&q=85&s=3ffc43e8a0875412cc27335241aeb4c8" alt="Settings icon" className="inline-ui-icon" width="24" height="24" data-path="images/icons/settings.svg" /> **Organization Settings** > **CloudLinks** in the organization where you want to add the CloudLink
       * Start creating a new Snowflake CloudLink
       * Select **Key-pair authentication** as the authentication method
       * Copy the public key displayed

    2. **Configure Key-Pair Rotation in Snowflake:**
       * Contact your Snowflake administrator to set the `RSA_PUBLIC_KEY_2` property for the Snowflake user
       * Provide the public key copied from the organization where you're adding the CloudLink
       * The Snowflake admin should run:
         ```sql theme={null}
         ALTER USER <username> SET RSA_PUBLIC_KEY_2='<public_key>';
         ```

    3. **Complete CloudLink Setup:**
       * After the second public key is configured in Snowflake, complete the CloudLink setup in the organization
       * Both organizations will now be able to authenticate with the same Snowflake user
       * The existing CloudLink in the other organization continues to work without interruption

    For detailed information on configuring key-pair rotation in Snowflake, see [Snowflake's key-pair authentication documentation](https://docs.snowflake.com/en/user-guide/key-pair-auth#configuring-key-pair-rotation).
  </Accordion>
</AccordionGroup>

## Deployment practices

* **Validate before Production** — Deploy and test changes in non-production environments before deploying to Production.
* **Deploy one app at a time** when practical so failures are easier to trace.
* **Use deployment history** to confirm what ran, when, and by whom.
* **Restrict who can deploy to Production** — Grant **DEPLOY\_APPS** in Production only to release-managers; review that role membership periodically. Because role membership is environment-specific, removing DEPLOY\_APPS in Production does not affect a user's ability to deploy in Development or Staging.

## Next steps

<CardGroup cols={2}>
  <Card title="Understand and Configure Environments" icon="sitemap" href="/administration/understand-organization-environments">
    Environment concepts, categories, CloudLink requirements, and setup steps
  </Card>

  <Card title="CloudLink Overview" icon="cloud" href="/administration/cloudlink-overview">
    Detailed CloudLink configuration options
  </Card>

  <Card title="Snowflake Connection" icon="snowflake" href="/administration/connect-snowflake-to-elementum">
    Complete Snowflake setup guide with scripts
  </Card>

  <Card title="Apps Overview" icon="grid-2" href="/getting-started/fundamentals/core-concepts#processes--apps">
    Understanding apps and their components
  </Card>
</CardGroup>
