$npx -y skills add butterbase-ai/butterbase-skills --skill deploy-frontendUse when deploying a frontend (React, Next.js, or static HTML) to a live URL on Butterbase, or when troubleshooting deployment issues like MIME type errors or blank pages
| 1 | ## Overview |
| 2 | |
| 3 | 7-step workflow for deploying static frontends to Butterbase. Covers building, CORS, zipping, uploading, and verification. |
| 4 | |
| 5 | --- |
| 6 | |
| 7 | ## Framework Reference Table |
| 8 | |
| 9 | | Framework | Build command | Output dir | Env prefix | Framework flag | |
| 10 | |-----------------|-----------------|--------------|-----------------|-----------------| |
| 11 | | React (Vite) | `npm run build` | `dist/` | `VITE_` | `react-vite` | |
| 12 | | Next.js (static)| `next build` | `out/` | `NEXT_PUBLIC_` | `nextjs-static` | |
| 13 | | Plain HTML | (none) | project root | N/A | `static` | |
| 14 | |
| 15 | > **Note:** Next.js requires `output: 'export'` in `next.config.js` to produce a static export. |
| 16 | |
| 17 | --- |
| 18 | |
| 19 | ## Step 1: Set Environment Variables |
| 20 | |
| 21 | Use `manage_frontend` with `action: "set_env"` to configure the API URL and app ID before building. These variables are injected at build time by the framework. |
| 22 | |
| 23 | ```json |
| 24 | { |
| 25 | "app_id": "app_abc123", |
| 26 | "action": "set_env", |
| 27 | "vars": { |
| 28 | "VITE_API_URL": "https://api.butterbase.ai/v1/app_abc123", |
| 29 | "VITE_APP_ID": "app_abc123" |
| 30 | } |
| 31 | } |
| 32 | ``` |
| 33 | |
| 34 | - For Vite, prefix all public variables with `VITE_` |
| 35 | - For Next.js, prefix with `NEXT_PUBLIC_` |
| 36 | - For Create React App, prefix with `REACT_APP_` |
| 37 | |
| 38 | `set_env` upserts; you can call it again to add or change variables. |
| 39 | |
| 40 | --- |
| 41 | |
| 42 | ## Step 2: Build |
| 43 | |
| 44 | Run the framework-specific build command to produce the static output directory. |
| 45 | |
| 46 | | Framework | Command | |
| 47 | |------------------|-------------------| |
| 48 | | React (Vite) | `npm run build` | |
| 49 | | Next.js (static) | `next build` | |
| 50 | | Plain HTML | (no build needed) | |
| 51 | |
| 52 | After building, verify the output directory contains `index.html` at its root: |
| 53 | |
| 54 | ```bash |
| 55 | # For Vite |
| 56 | ls dist/index.html |
| 57 | |
| 58 | # For Next.js static export |
| 59 | ls out/index.html |
| 60 | ``` |
| 61 | |
| 62 | If `index.html` is missing, check that the build completed without errors and that the framework is configured for static output. |
| 63 | |
| 64 | --- |
| 65 | |
| 66 | ## Step 3: Configure CORS |
| 67 | |
| 68 | Before deploying, configure CORS so the browser can make API requests from the deployment URL. |
| 69 | |
| 70 | Call `manage_app` with `action: "update_cors"`. Pass the deployment URL (use the Butterbase Pages URL pattern) and any local dev origins: |
| 71 | |
| 72 | ```json |
| 73 | { |
| 74 | "app_id": "app_abc123", |
| 75 | "action": "update_cors", |
| 76 | "allowed_origins": [ |
| 77 | "https://your-app.pages.dev", |
| 78 | "http://localhost:5173" |
| 79 | ] |
| 80 | } |
| 81 | ``` |
| 82 | |
| 83 | - Always include `http://localhost:5173` (Vite dev server default) for local development |
| 84 | - Include `http://localhost:3000` if using Next.js or Create React App locally |
| 85 | - Origins must include the protocol (`https://` or `http://`) and must not have trailing slashes |
| 86 | - If you don't yet know the exact deployment URL, you can update CORS again after Step 7 |
| 87 | |
| 88 | --- |
| 89 | |
| 90 | ## Step 4: Create Deployment |
| 91 | |
| 92 | Call `create_frontend_deployment` with the `app_id` and the correct `framework` flag from the reference table above. |
| 93 | |
| 94 | ```json |
| 95 | { |
| 96 | "app_id": "app_abc123", |
| 97 | "framework": "react-vite" |
| 98 | } |
| 99 | ``` |
| 100 | |
| 101 | The response contains: |
| 102 | - `deployment_id` — save this for Step 7 |
| 103 | - `uploadUrl` — the presigned S3 URL for uploading the zip (expires in 15 minutes) |
| 104 | |
| 105 | > **Free plan:** 1 deployment per app. Deploying again automatically replaces the previous deployment — no need to delete first. |
| 106 | |
| 107 | --- |
| 108 | |
| 109 | ## Step 5: Create Zip (Node `archiver` — the only supported method) |
| 110 | |
| 111 | > ⚠️ **Do not use `Compress-Archive`, File Explorer, or `zip -r` from outside the build dir.** Windows built-in tools write backslash (`\`) path separators, which makes the platform serve every file as `text/html` and breaks JS/CSS with MIME errors. Zipping from the parent dir nests `dist/` inside the archive and ships a blank page. |
| 112 | |
| 113 | Butterbase's recommended cross-platform method is the [`archiver`](https://www.npmjs.com/package/archiver) Node package. It always writes POSIX `/` separators (works identically on macOS, Linux, Windows PowerShell, cmd, Git Bash, WSL) and zips from *inside* the source dir so `index.html` lands at the zip root. |
| 114 | |
| 115 | **One-time setup in the project being deployed:** |
| 116 | |
| 117 | ```bash |
| 118 | npm install --save-dev archiver |
| 119 | mkdir -p scripts |
| 120 | ``` |
| 121 | |
| 122 | **Then save this as `scripts/make-zip.mjs` (copy verbatim):** |
| 123 | |
| 124 | ```js |
| 125 | #!/usr/bin/env node |
| 126 | /** |
| 127 | * Butterbase frontend zipper — the only supported way to compress a build |
| 128 | * for `create_frontend_deployment` / `create_from_source`. |
| 129 | * |
| 130 | * Usage: |
| 131 | * node scripts/make-zip.mjs <sourceDir> <outZip> [--exclude=glob,glob,...] |
| 132 | * |
| 133 | * Examples: |
| 134 | * node scripts/make-zip.mjs dist frontend.zip # Vite |
| 135 | * node scripts/make-zip.mjs out frontend.zip # Next.js static export |
| 136 | * node scripts/make-zip.mjs . source.zip \ # source-build flow |
| 137 | * --exclude=node_modules,.next,dist,out,.git,.turbo,.cache |
| 138 | */ |
| 139 | import { createWriteStream } from "node:fs"; |
| 140 | import { stat } from "node:fs/promises"; |
| 141 | import { r |