# Push to a live site

**Goal:** change [components](/start-here/glossary/#component) on a [site](/start-here/glossary/#site) that editors are already using, without removing something that is on a page.

The [quickstart](/source-cms/canvas-components/quickstart/) pushed one component to an empty library. A site with real pages on it is a different problem: `npx canvas push` is a one-way sync, not an upload, and the thing it syncs is your whole component directory against the site's whole component library.

## What you'll have when you're done

- A project whose `src/components/` matches the site, so no push plans a delete you did not intend.
- The habit of reading the plan and cancelling a push that does not match it.
- A component pushed to the site disabled, checked in [Drupal Canvas](/start-here/glossary/#drupal-canvas), then enabled.
- A known-good commit, and a push that puts the site back on it.

## Prerequisites

- A component project connected to your site with working Canvas CLI credentials ([Canvas quickstart](/source-cms/canvas-components/quickstart/))
- A site that already has components, and at least one Canvas page built from them
- [git](https://git-scm.com/downloads), with the component project committed

## Steps

<Steps>

1. ### Know what push compares

   Before it changes anything, `canvas push` asks the site for its component list and compares that list against your `src/components/` directory. The comparison is by [machine name](/start-here/glossary/#machine-name), and it decides the operation:

   | In `src/components/` | On the site | Planned operation |
   |---|---|---|
   | yes | no | `create` |
   | yes | yes | `update`: your local source replaces the site's copy in full |
   | no | yes | `delete` |

   The last row deletes components you never touched. A component your teammate created in the browser, or one an earlier project shipped, is a `delete` the moment you push from a directory that does not contain it. This is why a partial checkout is dangerous and a `--yes` push from one is worse.

   Two behaviors soften it, both worth knowing exactly:

   - **Pages are not deleted by absence.** Removing a page spec from `pages/` and pushing left the site's page in place, and no page delete appeared in the plan. Only components are removed by being missing.
   - **An empty component directory deletes nothing.** With no discoverable components locally, the CLI skips the component stage rather than treating the site's whole library as unwanted:

     ```text
     ┌   Drupal Canvas  push
     │
     ●  No components found. Skipping component and global CSS push.
     │
     │  Plan
     │  Pages: 1 update
     ```

   [Global regions](/start-here/glossary/#global-region) go through the same reconcile when the project has a `regions/` directory, so give a region you are not pushing the same care as a component. [Version pages and regions as code](/source-cms/canvas-components/pages-and-regions/) covers what those specs contain.

2. ### Reconcile your project with the site before you push

   The safe order is always pull, then push. Pulling brings down everything the site has, so the next push plans no deletes:

   ```bash
   npx canvas pull --skip-overwrite
   ```

   ```text
   │  Plan
   │  Components: 2 pull (1 new, 1 existing)
   │
   ◇  Pulled components
   │
   │  Succeeded: alpha-card
   │  Skipped (already exists): beta-banner
   │
   └  Pull completed
   ```

   `--skip-overwrite` is the flag that makes this safe to run mid-change: without it, pull writes over local files that already exist, including the component you are in the middle of editing. Commit before pulling either way.

3. ### Read the plan, then confirm or cancel

   There is no `--dry-run`. The confirmation prompt is the preview, and it is the only one:

   ```bash
   npx canvas push
   ```

   ```text
   ┌   Drupal Canvas  push
   │
   │  Plan
   │  Components: 1 create, 2 delete
   │  Pages: 1 update
   │
   ◆  Push these changes to https://your-site.example.com?
   │  ● Yes / ○ No
   └
   ```

   Answering `No` ends the run before any write reaches the site:

   ```text
   ◇  Push these changes to https://your-site.example.com?
   │  No
   └  Operation cancelled
   ```

   Nothing was created, updated, or deleted; the plan step only reads. Two limits to read the plan with:

   - **It counts, it does not name.** `2 delete` does not say which two. To find out, run the pull in step 2 and see which component directories appear that you did not have.
   - **It does not diff.** An `update` is planned for every component that exists on both sides, whether the source differs or not, so `1 update` tells you nothing about what that update will change.

   `--yes` skips the prompt. That is what CI wants and what your first push against a live site does not.

4. ### Push a new component disabled first

   `canvas scaffold` writes `status: false` into `component.yml`, and the push keeps that flag. The component is created on the site, built the way the site builds it, and disabled, so nothing can place it on a page:

   ```yaml
   # src/components/alpha-card/component.yml
   name: Alpha Card
   machineName: alpha-card
   status: false
   ```

   ```bash
   npx canvas push
   ```

   Until you set `status: true` and push again, anything that references the component is rejected, including a page spec of your own:

   ```text
   │  Failed
   │    ✗ Landing (pages/landing.json)
   │      elements.aaaaaaaa-1111-4111-8111-aaaaaaaaaaaa.type:
   │      Component "js.alpha-card" is disabled. Set "status: true" in its component.yml to enable it.
   ```

   This is the closest thing to a staging step the CLI has. It does not give you a second site, but it does separate "the push worked against the real site" from "editors can now use this", which is the part that is hard to take back.

5. ### Change a component that is already on pages

   An `update` replaces the site's stored component wholesale, and that stored component is the same record the browser code editor writes to. So a push overwrites whatever changed on the site since your last pull, silently. A component whose source had been changed on the site came back from the next push with that change gone, and the plan for that push read only `Components: 1 update`.

   The update path therefore has one rule: pull before you edit, commit before you push. That commit is what step 7 rolls back to.

   Existing [props](/start-here/glossary/#prop) and [slots](/start-here/glossary/#slot) carry their own constraints across an update (a prop's type cannot change, a slot cannot be renamed without orphaning what editors put in it); those are in the [Canvas CLI and schema reference](/source-cms/reference/canvas-cli/).

6. ### Delete a component on purpose

   Delete the directory from `src/components/`, then push. The site, not the CLI, decides whether the delete is allowed:

   ```bash
   rm -rf src/components/alpha-card
   npx canvas push
   ```

   ```text
   ┌   Drupal Canvas  push
   │
   │  Plan
   │  Components: 1 create, 2 delete
   │  Pages: 1 update
   │
   ▲  Pushed components
   │
   │  Deleted: epsilon-strip
   │  Created: zeta-strip
   │
   │  Failed
   │    ✗ alpha-card
   │      This code component is in use in a default revision and cannot be deleted.
   │
   └  ✗ Push failed
   ```

   Read that transcript carefully, because it answers the two questions that matter most on a live site.

   **A component an editor has placed cannot be deleted.** The site refuses, and the message names which kind of use is blocking it: `in a default revision` (it is on a published page), `in a Canvas auto-save` (someone has an unsaved draft holding it), or `in the latest revision` (a pending revision holds it). Remove the component from the pages that use it first, in Canvas or in the page specs, then push the delete again.

   **A push is not all-or-nothing.** In that same run one component was created and another deleted, and both stuck, even though the run ended `✗ Push failed`. The planned page update never ran. `✗ Push failed` and `✗ Push incomplete` both mean *some* of the plan may already be live, so treat a failed push as a state to inspect, not a change to ignore. (A failure in the local build or lint stage is different: that happens before anything uploads, so nothing reaches the site.)

7. ### Get back to a known-good state

   There is no undo command. Recovery is the two directions of the sync you already have.

   To put the site back after a bad push, check out the commit whose source was good and push it:

   ```bash
   git checkout -- src/components/alpha-card
   npx canvas push
   ```

   The next `update` overwrites the site's copy with the restored source, which is exactly the behavior that made the bad push dangerous, now working for you. The round trip holds: a change pushed to the site was gone from the site again after checking out the previous source and pushing a second time.

   To recover a component you deleted locally but have not yet pushed, take it back from the site:

   ```bash
   npx canvas pull --skip-overwrite
   ```

   That rewrites the component's directory (`component.yml`, the source file, and its CSS) from the site's copy, and leaves everything else alone. It only works while the component is still on the site: once a push has deleted it there, git is the only copy left, which is the reason for the commit in the prerequisites.

</Steps>

## When something goes wrong

**`This code component is in use in a default revision and cannot be deleted.`**: the component you removed from `src/components/` is on a published page. The site blocks the delete on purpose, so the pages that use it keep rendering. Either put the directory back (`git checkout -- src/components/<name>`, or `npx canvas pull --skip-overwrite`) if the delete was accidental, or remove the component from those pages first, in Canvas or in the page specs under `pages/`, and push again.

**`This code component is in use in a Canvas auto-save and cannot be deleted.`**: same block, different holder. Somebody has unsaved editor changes that still place the component; a draft counts as a use. Ask them to publish or discard, then push again.

**`This code component is in use in the latest revision and cannot be deleted.`**: a pending revision that has not been published yet still places the component. Publishing that revision must not render a gap, so the delete is refused until the revision no longer uses it.

**The plan shows deletes you did not ask for**: your `src/components/` does not have everything the site has, and push treats absence as deletion. Cancel at the prompt (nothing has been written yet), run `npx canvas pull --skip-overwrite`, and look at which directories appeared. Those are the components the plan was about to remove.

**`Component "js.<name>" is disabled. Set "status: true" in its component.yml to enable it.`**: a page or region spec places a component that is on the site but not enabled. `canvas scaffold` writes `status: false`, and it is easy to push the component and forget the flag. Set `status: true` in that component's `component.yml` and push again.

**`✗ Push failed` or `✗ Push incomplete`, and the site changed anyway**: expected. The component, asset, page, and region stages run in order and each applies as it goes, so a failure in one stage leaves the earlier ones live. Re-read the run's `Deleted:` / `Created:` / `Updated:` lines to see what landed, fix the reported failure, and push again; whatever already succeeded plans as an ordinary update the second time and is safe to re-apply.

**`No components found. Skipping component and global CSS push.`**: the CLI discovered nothing to build in `componentDir`. On a live site this is a safe outcome rather than a destructive one (it plans no component deletes), but the push you wanted did not happen. Check you are in the project root, that `componentDir` in `canvas.config.json` matches where your components are, and that each directory has both a `component.yml` and its source file.

**A pushed change is not visible on the site**: confirm the push reported the component under `Updated:` and not just in the plan, then reload the page rather than the editor. If the component looks stale in Canvas specifically, the built assets are the thing to re-check: a push uploads the component and the global CSS build together, and a `--no-pages`-style flag never excludes those.

## Next steps

- [Version pages and regions as code](/source-cms/canvas-components/pages-and-regions/): what a page spec is, and how to edit one.
- [Render CMS content with content templates](/source-cms/canvas-components/content-templates/): bind component props to entity fields instead of typed-in values.
- [Canvas CLI and schema reference](/source-cms/reference/canvas-cli/): every flag on `push` and `pull`, and the full component schema.
