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

# Overview

> Promote dashboards between environments with encrypted .ucf files

The **Dashboard Sync** endpoints let you move dashboards (and the charts they
render) from one Upsolve environment to another — for example, from a
**staging** deployment where your users build and refine dashboards to a
**production** deployment that serves them.

This is designed for self-hosted (on-prem) deployments where both environments
were originally seeded from the **same `.ucf` file** (via the `execute-patches`
command). Because the seed is identical, every dashboard, chart, filter, and
theme already shares the same id across environments — so importing is a true
**upsert** rather than a copy that risks duplicates.

## Workflow

<Steps>
  <Step title="Mark dashboards as exportable">
    Call [Mark Dashboards Exportable](/api-reference/endpoint/set-dashboards-exportable)
    on the source (e.g. staging) environment to flag the dashboards you want to
    promote. Both global and tenant-scoped dashboards can be marked.
  </Step>

  <Step title="Export to an encrypted .ucf file">
    Call [Export Dashboards](/api-reference/endpoint/export-dashboards-ucf) to
    download an encrypted `.ucf` file containing every exportable dashboard, the
    charts they reference, and their filters and themes.
  </Step>

  <Step title="Import into the target environment">
    Send the file's contents to
    [Import Dashboards](/api-reference/endpoint/import-dashboards-ucf) on the
    target (e.g. production) environment. Definitions are upserted in place,
    preserving ids and versions. Re-importing the same file is idempotent.
    The import also propagates the imported dashboards' presentation settings
    down to any copies your end users forked from them — see below.
  </Step>
</Steps>

## Reaching dashboards your users forked

When an end user customizes a dashboard, they get their own copy of it. That
copy keeps its own timezone, selected tables and theme, so an import that only
upserted what the `.ucf` carried would update the original and leave every
forked copy showing the old styling.

To prevent that, the import pushes these settings from each imported dashboard
down onto the copies forked from it:

| Setting                                     | Notes                                                                                                      |
| ------------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
| Timezone (`tz`) and the local-timezone flag | Applied to every version of the copy, matching what already happens when a user changes their own timezone |
| Selected tables                             | Applied to every version of the copy                                                                       |
| Theme, and whether it is the default theme  | Applied to the copy's current theme — the one it renders with                                              |

**What is never overwritten:** the copy's own name and its dashboard config —
its layout, which charts it shows, and its filters. That's the user's work, and
it stays theirs.

The import response includes a `propagation` object reporting how many copies
and rows were touched.

<Note>
  Chart *versions* are not propagated. A forked copy pins the chart versions it
  was created with, so edits you make to a chart's definition reach the original
  dashboard but not copies that pinned an earlier version.
</Note>

### Re-running propagation on its own

[Propagate to Child Dashboards](/api-reference/endpoint/propagate-dashboards-ucf)
runs the same step without an import. Use it to:

* back-fill an environment that was seeded with the `execute-patches` command
  rather than the import endpoint;
* re-run after a `.ucf` that was imported before this behaviour existed;
* preview the effect first — pass `dryRun: true` to get the same counts back
  without writing anything.

Omit `dashboardIds` to target every dashboard in the organization that has at
least one forked copy. The operation is idempotent, so running it twice is
harmless.

## Requirements & notes

* **Authentication:** all three endpoints require an Upsolve **admin API key**.
* **Encryption:** the `.ucf` file is AES-256-CBC encrypted with your
  deployment's `FILES_KEY`. The source and target environments must share the
  same `FILES_KEY`, or the import will fail to decrypt.
* **Scope:** the import rejects any payload (or row) whose organization does not
  match the authenticated organization, preventing cross-tenant writes.
* **What travels:** chart and dashboard definitions plus their filters and
  themes. Connections and data models are **not** included — they are assumed to
  already match from the original shared seed.
* **Forked copies:** the import reaches copies your end users made of the
  imported dashboards, but only their presentation settings — never their
  layout or content. See
  [Reaching dashboards your users forked](#reaching-dashboards-your-users-forked).
