Stackable hosts the marketplace, the proxy, and the runtime — but **you host your extension's bundle/runtime**. Deployment is three steps: build for production, upload to a host of your choice, then point your extension's **Bundle URL** at the result.

## 1. Build the production bundle

From the project root:

```bash
pnpm build
```

This runs Vite in production mode and writes the static bundle to
`packages/extension/dist/` — a small set of JS/CSS files plus your
`manifest.json`. That's the artifact you ship.

> **Tip:** Validate the build before you upload it. Run through the
> [Validate guide](/docs/guides/validate) (or ask your AI client to call the
> `validate_manifest` MCP tool) so manifest typos and missing permissions are
> caught before they reach the marketplace.

## 2. Upload to a hosting provider

Stackable doesn't care where the bundle lives — only that it's served over
HTTPS with permissive CORS so the host runtime can fetch it. Anything that
serves static files works. The most common options:

| Provider | Notes |
|----------|-------|
| **Netlify** | Drop `packages/extension/dist/` into a site, or wire up Git auto-deploys. CORS is already permissive. |
| **Vercel** | Same idea — link the repo and let Vercel build/deploy on push. Set the build output to `packages/extension/dist`. |
| **Cloudflare Pages** | Connect the repo, set the output directory, deploys land on the edge globally. |
| **AWS S3 + CloudFront** | Sync `dist/` to an S3 bucket, front it with a CloudFront distribution. Make sure the CloudFront response headers include `Access-Control-Allow-Origin: *` (or your host origin). |
| **Your own CDN / object storage** | Anything that returns `200 OK` with the right `Content-Type` and CORS headers will work. |

Whichever you pick, the only requirements are:

- Bundle is reachable over **HTTPS**
- CORS allows the host application's origin (most providers do this by default; S3+CloudFront is the one that usually needs explicit configuration)
- The URL is **stable** — every Instance running your extension fetches from this URL on load

> **Need help with setup or deployment?** Reach out at [developers@stackablelabs.com](mailto:developers@stackablelabs.com) or open an issue / discussion on [GitHub](https://github.com/stackable-labs).

## 3. Register your Bundle URL with Stackable

Once your extension bundle is deployed/live, tell Stackable where to find it. You have two options:

- **Admin dashboard** — open your extension at [admin.stackablelabs.com](https://admin.stackablelabs.com), edit the **Bundle URL** field, and save. Existing Instances pick up the new bundle the next time they load.
- **CLI** — from the project directory:

  ```bash
  pnpm --config.dlx-cache-max-age=0 dlx @stackable-labs/cli-app-extension@latest update --bundle-url https://your-host.example.com/manifest.json
  ```

  Or, with an explicit extension ID (handy for CI/CD):

  ```bash
  pnpm --config.dlx-cache-max-age=0 dlx @stackable-labs/cli-app-extension@latest update ext_xxx --bundle-url https://your-host.example.com/manifest.json
  ```

Point the URL at your bundle's `manifest.json` — that's the entrypoint the
runtime fetches first; everything else is loaded relative to it.

## 4. Roll out and iterate

That's the entire deploy loop. Subsequent updates follow the same path: bump
`version` in `manifest.json`, run `pnpm build`, re-upload, and (only if the
URL changed) re-register. Most teams wire steps 1–3 into a single CI/CD job
that runs on every merge to `main`.

## Next: list it on the Marketplace

Deploying makes your extension **runnable** at a stable URL. To make it
**installable** by other organizations, fill in the marketplace listing (icon, screenshots, description, visibility) and submit for review. See [Marketplace Listing](/docs/reference/marketplace-listing).
