Preact apps built with preact-cli or Vite produce static HTML and JavaScript bundles that can be served from a CDN. The build step is simple, but getting from npm run build to a live, production-ready URL involves DNS, SSL certificates, cache invalidation, and rollback workflows. Doing this manually every time you ship a bug fix gets old fast.
The panda CLI condenses the whole flow into a few commands. You create a project, push a deploy, point a domain at it, and monitor traffic — all from the terminal, with no dashboard clicks required.
Install the CLI and authenticate
npm install -g @pandastack/cli
panda loginThe login command opens a browser to authenticate with GitHub. Once complete, the CLI stores a session token locally. Run panda org to verify which organization you are deploying under.
If you deploy from CI or a shared machine, generate a long-lived API token instead: go to the dashboard under Settings → API Tokens, create a psk_live_ token, and set it as PANDASTACK_TOKEN in your environment. The CLI reads that variable and skips the browser login.
Create a project from a Preact repo
Clone your Preact app and navigate into the directory. Make sure it has a package.json with a build script:
{
"scripts": {
"build": "preact build",
"dev": "preact watch"
}
}For Vite-based Preact projects, the build script is typically vite build and the output directory is dist. For preact-cli, it is preact build and the output is build.
Create the project on PandaStack:
panda projects create \
--name preact-landing \
--repo github.com/yourname/preact-landing \
--branch main \
--type static \
--build-cmd "npm run build" \
--output-dir buildThe CLI clones the repo, installs dependencies (auto-detecting npm vs yarn vs pnpm from your lockfile), runs the build command, and uploads the output directory to a CDN. When the deploy finishes, you get a live URL:
✓ Deploy complete
https://preact-landing-abc123.pandastack.appOpen the URL in a browser. The site is live, served over HTTPS, with HTML cached at the edge and hashed assets (like bundle.a1b2c3.js) served with immutable cache headers.
Deploy updates with one command
Make a change to the code, commit it, and deploy:
git commit -am "Update hero copy"
panda projects deploy <project-id>The CLI triggers a new build on PandaStack's servers. It does not read your local files; it clones the latest commit from GitHub and builds there. This ensures the deployed version matches what is in version control, not what is sitting uncommitted on your laptop.
The deploy command streams build progress to the terminal (though as of mid-2026, log streaming is unreliable — if you see a hang, check the dashboard Logs tab instead). When the build succeeds, the CDN cache is purged and the new version goes live.
If the build fails, the old version stays up. There is no downtime from a broken build.
Add a custom domain and SSL
Deploying to *.pandastack.app is fine for staging, but production apps need a real domain. Point your domain at PandaStack by adding a CNAME record in your DNS provider:
www.yoursite.com. CNAME preact-landing-abc123.pandastack.app.Then tell PandaStack to provision an SSL certificate for it:
panda projects domain add <project-id> www.yoursite.comPandaStack uses Let's Encrypt to issue a certificate. This takes 30–60 seconds. Once complete, https://www.yoursite.com serves your app with automatic HTTPS redirect (HTTP requests get 301'd to HTTPS).
If you want to serve both the root domain and www, add two CNAME records (or an ALIAS record for the root, depending on your DNS provider's support) and add both domains to the project. PandaStack will issue certificates for each.
SSL certificates auto-renew 30 days before expiration. You do not have to touch this again.
Roll back a bad deploy
You pushed a broken build to production. The fix will take 20 minutes to code and test, but users are hitting the broken version right now.
List recent deployments:
panda projects list --name preact-landingFind the deployment ID of the last working version (one or two deploys ago) and roll back to it:
panda projects rollback <project-id> --deployment <deployment-id>This swaps the live traffic to the older build instantly. No rebuild required; the old static files are still stored and still cached at the edge. You get the working version back while you fix the bug locally.
When the fix is ready, deploy normally with panda projects deploy and the rollback is overwritten by the new release.
Set environment variables for build-time injection
Preact apps running as static sites cannot read environment variables at runtime — the browser has no process.env. Variables must be compiled into the JavaScript bundle at build time.
If your app needs an API URL or a public key, set them when creating the project:
panda projects create \
--name preact-app \
--repo github.com/yourname/preact-app \
--type static \
--env PREACT_APP_API_URL=https://api.yoursite.com \
--env PREACT_APP_STRIPE_KEY=pk_live_...Or update an existing project:
panda projects env set <project-id> PREACT_APP_API_URL=https://api.yoursite.com
panda projects deploy <project-id>During the build, PandaStack sets these as environment variables. Preact CLI and Vite both read variables prefixed with PREACT_APP_ (or VITE_ for Vite projects) and replace them in the code. In your app, reference them as process.env.PREACT_APP_API_URL (Preact CLI) or import.meta.env.VITE_API_URL (Vite).
When you rotate a secret, update the variable and redeploy. The new build gets the new value, and the old cached assets expire naturally as users refresh.
Monitor traffic without client-side scripts
PandaStack captures server-side analytics for every request to your static site — page views, unique visitors, referrers, geographic distribution, and top paths. This data is collected at the CDN layer and stored in ClickHouse, so you do not need to add Google Analytics or a client-side SDK.
View traffic in the dashboard under Analytics, or query it via the CLI:
panda monitor <project-id>This shows real-time request rate, status codes, and response times. For deeper analysis (like "which pages get the most traffic from Twitter"), use the dashboard's analytics tab to filter by referrer and path.
Because the data is server-side, ad blockers and privacy tools do not affect the counts. You get accurate visitor numbers without tracking individual users or requiring cookie consent banners.
When the build fails: debugging common issues
Output directory not found: The build succeeded but PandaStack cannot find the compiled files. Check your package.json build script and confirm the output directory matches what you passed to --output-dir. For Preact CLI, it is build. For Vite, it is dist.
Dependencies failed to install: The lockfile format does not match the package manager. If you use yarn but have a package-lock.json, delete the lockfile and commit yarn.lock. PandaStack auto-detects the correct manager from the lockfile.
Build command not found: You specified preact build but the preact-cli binary is in devDependencies, which npm does not install by default in production mode. The buildpack installs both dependencies and devDependencies, so this should not happen unless the lockfile is corrupt or missing. Re-run npm install locally and commit the updated lockfile.
Environment variable is undefined in the app: You set PREACT_APP_API_URL but the code references process.env.API_URL (missing the prefix). Preact CLI only injects variables that match the PREACT_APP_ pattern. Rename it or change the code.
Check the full build log with panda projects logs or in the dashboard Logs tab. Build logs are stored for 10 days on the free tier, 30 days on Pro, and 90 days on Premium.
Free tier limits for static sites
The free plan includes five static sites, 100 GB of bandwidth per month, and 300 build minutes. For a typical Preact app (30-second build, 500 KB bundle), that is 600 builds per month and enough bandwidth for 200,000 page loads.
Static sites do not consume compute resources when idle (unlike container apps that scale to zero but still need a pod). There is no cold start because there is no runtime — the HTML is cached at the edge and served instantly on every request.
If you hit the bandwidth cap, upgrade to Pro for 500 GB/month at $15, or Premium for 2500 build minutes and higher traffic tiers at $25.
CLI vs API vs dashboard: when to use which
Use the CLI (panda) for day-to-day deploys and quick config changes. Use the API (with a psk_ token) for CI pipelines and scripts. Use the dashboard for analytics, logs, and team management.
The CLI is faster for one-off tasks because it stores your session and you do not have to copy project IDs. The API is better for automation because tokens do not expire and you can version-control the deploy scripts.
For multi-environment workflows (deploy to staging on every push, production on tagged releases), script both using the API and store separate project IDs for each environment.
Why static sites win for landing pages
Preact apps built as static sites have no server to crash, no database to overwhelm, and no runtime dependencies to patch. You ship a directory of HTML and JavaScript files to a CDN, and the CDN handles scaling to a million requests or scaling down to zero when traffic drops.
The free tier runs on the same infrastructure as paid tiers — multi-region CDN, automatic cache purging on deploy, server-side analytics. The only difference is bandwidth and build minute limits, not performance or reliability.
This makes PandaStack a strong choice for marketing sites, documentation, and SaaS landing pages that are statically generated at build time and do not need a backend.
References
- [Preact CLI documentation](https://preactjs.com/cli/)
- [Vite documentation](https://vitejs.dev)
- [PandaStack CLI reference](https://docs.pandastack.io)