# Quickstart

**Goal:** get one working [component](/start-here/glossary/#component) from your terminal into your [site](/start-here/glossary/#site)'s [Drupal Canvas](/start-here/glossary/#drupal-canvas) component library.

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

- A local component project scaffolded from the **Nebula** template: Canvas Workbench (a Storybook-style local preview on a Vite dev server that auto-configures the [JSON:API](/start-here/glossary/#jsonapi) client), the Canvas CLI, an ESLint config that validates components against Canvas requirements, and AI-agent rules in `.agents/skills/`.
- One minimal component, validated and built locally.
- That component pushed to your site and visible in Canvas.

## Prerequisites

- A Source CMS site you can administer: the `Edit` button (top right on any page of the site) opens the Canvas visual editor. (No site? A self-serve <a href="https://www.acquia.com/products/acquia-cloud-platform/trial" target="_blank" rel="noopener">Cloud Platform free trial</a> gets you building on Acquia the same day, though its Drupal 11 application is the Cloud Platform path, not a Source CMS site; for one of those, <a href="https://www.acquia.com/request-a-demo/acquia-source" target="_blank" rel="noopener">request a Source demo</a>.)
- [Node.js](https://nodejs.org/) 22 (the scaffold pins it in `.nvmrc`; the dev server requires 20.19+ or 22.12+). npm ships with Node.
- [git](https://git-scm.com/downloads)

## Steps

<Steps>

1. ### Scaffold the project from the Nebula template

   ```bash
   npx @drupal-canvas/create@latest my-components \
     --template acquia-nebula \
     --agents none
   ```

   `--agents none` skips generating extra per-agent rule files (for Cursor, Copilot, and similar); the template's own `.agents/skills/` rules are included regardless, and you can generate agent-specific files later if you want them.

   The tool fetches the template, installs dependencies with npm, and initializes a git repository:

   ```text
   ┌  Drupal Canvas Create
   │
   ◇  Fetched template
   │
   ●  No additional agents selected. Skipping compatibility setup.
   │
   ◇  Installed dependencies with npm
   │
   ◇  Initialized Git repository on main with initial commit
   │
   ◇  Get started ────────────────────────╮
   │                                      │
   │  Created project in ./my-components  │
   │                                      │
   │  Next steps:                         │
   │    cd my-components                  │
   │    npm run dev                       │
   │                                      │
   ├──────────────────────────────────────╯
   │
   └  Canvas project created successfully.
   ```

   The scaffolded tree (trimmed):

   ```text
   my-components/
   ├── .agents/skills/        # AI rules: canvas-*, nebula-*
   ├── .claude/skills/        # symlinked for Claude
   ├── .env.example           # Canvas CLI credentials
   ├── .github/workflows/     # lint-pr.yml, tests.yml
   ├── .nvmrc                 # 22
   ├── AGENTS.md
   ├── canvas.config.json     # component/page dirs, CSS, sync
   ├── eslint.config.js       # @drupal-canvas/eslint-config
   ├── examples/
   │   ├── components/        # 25 examples to copy from
   │   ├── pages/homepage.json
   │   └── regions/           # header.json, footer.json
   ├── package.json           # "dev": "canvas-workbench"
   └── src/
       ├── global.css         # Tailwind CSS entry point
       └── layout.jsx
   ```

2. ### Start the local preview

   ```bash
   cd my-components
   npm run dev
   ```

   ```text
   > my-components@0.0.0 dev
   > canvas-workbench

     VITE v7.3.2  ready in 336 ms

     ➜  Local:   http://localhost:5173/
   ```

   Open `http://localhost:5173/`. Canvas Workbench scans `src/components/` for components and renders live previews. It's empty right now; your first component appears here in a moment. (The `examples/components/` directory is reference material to copy from, not part of the scanned library.) Leave it running.

3. ### Scaffold one minimal component

   In a second terminal, from the project root:

   ```bash
   npx canvas scaffold --name my-hero
   ```

   ```text
   ┌  Drupal Canvas scaffold
   │
   ◇  Created component
   │
   │  Created: my-hero
   │  Directory: src/components/my-hero
   │  Component metadata: src/components/my-hero/component.yml
   │  Source file: src/components/my-hero/index.jsx
   │  CSS file: src/components/my-hero/index.css
   │
   └  Scaffold completed
   ```

   `index.jsx` is the component itself: ordinary React, a default export, [props](/start-here/glossary/#prop) with default values, and a `content` [slot](/start-here/glossary/#slot) the editor fills with other components.

   ```jsx
   // src/components/my-hero/index.jsx
   /**
    * MyHero example component
    */
   const MyHero = ({
     greeting = 'Hello world!',
     ctaDisplayText = 'Click me!',
     ctaLink = 'https://example.com',
     content,
   }) => {
     return (
       <div className="my-hero-component">
         <h2 className="greeting">{greeting}</h2>
         <div className="content">{content}</div>
         <button type="button" className="cta">
           <a href={ctaLink}>{ctaDisplayText}</a>
         </button>
       </div>
     );
   };

   export default MyHero;
   ```

   Open `src/components/my-hero/component.yml` and change the second line from `machineName: hello-world` to `machineName: my-hero`. The scaffold writes a placeholder [machine name](/start-here/glossary/#machine-name), and it must match the directory name.

4. ### Validate the component

   ```bash
   npx canvas validate
   ```

   ```text
   ┌  Drupal Canvas validate
   │
   ◇  Validated components
   │
   │  Valid: my-hero
   │
   └  Validation completed
   ```

   The new component also appears in Workbench, rendered with the example values from `component.yml`.

5. ### Create Canvas CLI credentials on your site

   In your site's admin UI, go to `API > API clients` and select `Add API client` to create an [API client](/start-here/glossary/#api-client). Enter a name, select the `Client Credentials` checkbox, add `canvas:asset_library` and `canvas:js_component` as [scopes](/start-here/glossary/#scope), and set a `User` (not the anonymous user) to serve as the author of the client's actions. Save to generate the credentials. (Same flow as the [auth quickstart](/source-cms/authenticate/quickstart/), with Canvas scopes.)

   Copy `.env.example` to `.env` and fill in the values. The Canvas CLI reads these exact variable names, a separate OAuth client from the `DRUPAL_*` credentials the Content API uses, since it pushes components rather than reading content:

   ```bash
   # .env
   CANVAS_SITE_URL=https://your-site.example.com
   CANVAS_CLIENT_ID=your-client-id
   CANVAS_CLIENT_SECRET=your-client-secret
   ```

6. ### Push the component to your site

   ```bash
   npx canvas push
   ```

   The CLI plans the change (`Components: 1 create`) and asks `Push these changes to https://your-site.example.com?`; confirm with `Yes`. It then builds `my-hero` together with the global Tailwind CSS assets and uploads everything:

   ```text
   ◇  Pushed components
   │
   │  Created: my-hero
   │
   ◇  Prepared assets
   │
   ◇  Pushed assets
   │
   │  Global CSS (Tailwind CSS build)
   │
   └  ✓ Push completed
   ```

7. ### Enable the component

   `canvas scaffold` wrote `status: false` into `component.yml`, and the flag survived the push: `my-hero` is on the site but disabled, and a disabled component cannot be placed on a page. Change `status: false` to `status: true` in `src/components/my-hero/component.yml`, then push again and confirm:

   ```bash
   npx canvas push
   ```

8. ### Confirm the component is in the site's component library

   Open any page of your site (the homepage works), click `Edit` (top right) to open Canvas, then click the `Code (</>)` icon in the left toolbar. `My Hero` is listed among the code-based components; select it to open it in the code editor with its `Preview` and `Component data` panels. It is now available to drag onto pages from the component library.

</Steps>

## What just happened

The Nebula template gave you a complete authoring environment. Canvas Workbench previews components locally on a Vite dev server that auto-configures the JSON:API client for requests against your Drupal site (mirroring the in-browser code editor). ESLint enforces the rules a component must satisfy to run in Canvas, and `.agents/skills/` carries rules that teach AI coding agents the same conventions. `canvas push` compiled your React source, then uploaded the component (scope `canvas:js_component`) and the built CSS assets (scope `canvas:asset_library`) to your site, where it joined the component library alongside components created in the browser editor. (To remove a pushed component later, delete its directory from `src/components/` and run `npx canvas push` again: the plan lists it as a delete.)

Your site's library was empty, which is the one case where a push cannot take anything away. Against a site that already has components and pages, `push` reconciles the two sides and can plan deletes: read [push to a live site](/source-cms/canvas-components/push-to-a-live-site/) before the next one.

This page was verified against `@drupal-canvas/create` 1.5.0 and `@drupal-canvas/cli` 0.20.1. The current template ships Canvas Workbench (its Storybook-style successor) and agent skills in `.agents/skills/`; older descriptions of the Nebula scaffold naming Storybook and a `ruler` AI-rules folder are out of date.

## When something goes wrong

**`You are using Node.js 18.20.4. Vite requires Node.js version 20.19+ or 22.12+. Please upgrade your Node.js version.`**: `npm run dev` was started with an unsupported Node version. The project pins Node 22 in `.nvmrc`; run `nvm use` (or install Node 22) and start again.

**`Authentication Error: Client authentication failed` (from `canvas push`)**: the client ID or secret in `.env` is wrong, or the API client isn't set up for this flow. Re-copy both values into `.env` from the client at `API > API clients`, and confirm the client has the `Client Credentials` checkbox selected with both `canvas:asset_library` and `canvas:js_component` scopes. If it still fails after that, the secret was likely lost or regenerated: create a fresh client as in step 5 and put its new ID and secret in `.env`.

**`API endpoint not found: /oauth/token` with "Canvas module is not enabled"**: the CLI reached a server, but not a Canvas-enabled site. Check `CANVAS_SITE_URL` points at your Source CMS site (no trailing slash, no path); the usual cause is a URL for some other server entirely.

**`Line 2, Column 14: Directory name "my-hero" does not match machineName "hello-world". (drupal-canvas/component-dir-name)`** (from `canvas validate`): the scaffold's placeholder machine name was left in place. Edit `component.yml` so `machineName` matches the component's directory name.

**`✗ Push incomplete`** (from `canvas push`): the site already had components or pages that aren't in your project's `src/components/`. `canvas push` syncs the site to match your project exactly, including deleting anything it doesn't find locally; if one of those items is placed on a page or referenced by other configuration, Drupal refuses to delete it and the push fails. The push is not rolled back: whatever the run already applied stays applied, so read its `Created:` / `Updated:` / `Deleted:` lines to see what landed. To avoid the conflict, pull the site's existing components into your project before pushing ([push to a live site](/source-cms/canvas-components/push-to-a-live-site/)).

**`canvas push` prompts `Enter the site URL` instead of pushing**: the `.env` file is missing or not in the project root. Copy `.env.example` to `.env` in the directory you run the command from.

## Next steps

- [Push to a live site](/source-cms/canvas-components/push-to-a-live-site/): what the next push does to a site that already has pages on it, and how to get back if one goes wrong.
- [Component development](/source-cms/canvas-components/guide/): props, slots, Tailwind styling, composition patterns, and AI-assisted authoring.
- [Render CMS content with content templates](/source-cms/canvas-components/content-templates/): make components display entity fields instead of typed-in values.
- [Version pages and global regions](/source-cms/canvas-components/pages-and-regions/): pull the site's structure into this same project.
- [Canvas CLI & schema reference](/source-cms/reference/canvas-cli/): every command and the full component schema.
