A React app that calls an external API needs the base URL and authentication token, but committing those values to Git is a mistake. The staging environment should point to a test API, production should use the live endpoint, and contributors shouldn't have access to production credentials at all.
Most platforms make you paste environment variables into a web form after deploy, then redeploy to pick them up. PandaStack supports that workflow, but there's a better option: declare required variables in pandastack.json with human-readable descriptions, and the deploy screen prompts for them before starting the build. This is the Vercel model, and it prevents the "why is my app showing undefined?" debugging loop.
Add pandastack.json to your Vite project
In your repository root, create pandastack.json:
{
"type": "static",
"language": "nodejs",
"buildCommand": "npm run build",
"outputDir": "dist",
"env": [
{
"key": "VITE_API_BASE_URL",
"description": "Backend API endpoint (e.g. https://api.yourapp.com)"
},
{
"key": "VITE_AUTH_TOKEN",
"description": "API authentication token for the backend"
}
]
}The env array tells PandaStack two things: the variable names your build process expects, and a help string shown in the UI. When someone deploys this repo, they see labeled input fields instead of a blank form.
Use the variables in your React code
Vite exposes variables prefixed with VITE_ as import.meta.env.VITE_*. In your API client:
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL;
const AUTH_TOKEN = import.meta.env.VITE_AUTH_TOKEN;
export async function fetchOrders() {
const response = await fetch(`${API_BASE_URL}/orders`, {
headers: {
'Authorization': `Bearer ${AUTH_TOKEN}`
}
});
return response.json();
}During npm run build, Vite bakes these values into the JavaScript bundle as string literals. The compiled code contains the actual URL and token, not placeholders, so there's no runtime lookup.
Deploy from the dashboard
Push pandastack.json to your main branch, then go to the PandaStack dashboard and create a new project. Select your repository. The deploy form shows:
- VITE_API_BASE_URL: Backend API endpoint (e.g. https://api.yourapp.com)
- VITE_AUTH_TOKEN: API authentication token for the backend
Fill in the values for this environment (staging or production), click Deploy, and PandaStack runs npm run build with those variables set. The build process sees them as process.env.VITE_API_BASE_URL, Vite substitutes them into your code, and the output bundle contains the configured URL.
Use the deploy button
Once pandastack.json exists, add a README badge:
[](https://dashboard.pandastack.io/deploy?repo=your-username/vite-react-app)Anyone who clicks it sees the same environment variable prompts. This makes your repo forkable: contributors can deploy their own copy with their own API credentials, and the original values stay secret.
Deploy via the REST API
For CI pipelines or scripts, use the /v1/projects endpoint:
curl -X POST https://api.pandastack.io/v1/projects \
-H "Authorization: Bearer $PANDASTACK_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"slug": "static",
"name": "vite-app-staging",
"repositoryName": "acme/vite-react-app",
"branch": "develop",
"autoDeploy": true,
"env": [
{ "name": "VITE_API_BASE_URL", "value": "https://staging-api.acme.com" },
{ "name": "VITE_AUTH_TOKEN", "value": "staging_token_xyz" }
]
}'The env array in the API payload overrides the prompts from pandastack.json. This is how you automate per-branch deploys: the CI job sets different values based on the Git branch.
Why Vite needs the VITE_ prefix
Vite only exposes environment variables that start with VITE_. If you set API_BASE_URL without the prefix, import.meta.env.API_BASE_URL will be undefined at build time. This is a security feature: it prevents accidentally leaking server-side secrets (like database credentials) into the client bundle.
If you need a value at runtime instead of build time, store it in a JSON file fetched by the app, or run a backend that serves configuration via an API endpoint.
Update variables without redeploying
After the initial deploy, you can change environment variables in the dashboard (Project Settings → Environment Variables). Click Save, then trigger a redeploy from the Deployments tab. PandaStack rebuilds with the new values.
This is also how you rotate API keys: update the variable, redeploy, and the next build picks up the new token.
Multiple environments from one repository
Create separate projects for staging and production:
- 1Staging: Deploy from the
developbranch with staging API credentials - 2Production: Deploy from
mainwith production credentials
Both projects reference the same pandastack.json, but the environment variable values differ. This mirrors the standard Git-flow deployment model.
Common mistakes
Forgetting the VITE_ prefix: If your variable is named API_URL, Vite won't expose it. Rename it to VITE_API_URL.
Exposing secrets in client code: Anything in import.meta.env ends up in the browser. Never put database credentials or server-to-server API keys in a Vite environment variable. Those belong in a backend service.
Not redeploying after changing variables: Static sites bake environment variables at build time. Updating them in the dashboard does nothing until you redeploy.
Use the CLI for scripted deploys
If you deploy the same project repeatedly (e.g., testing configuration changes), the CLI is faster:
panda login
panda projects create \
--name vite-app-prod \
--repo acme/vite-react-app \
--branch main \
--auto-deploy
panda projects env vite-app-prod VITE_API_BASE_URL=https://api.acme.com
panda projects env vite-app-prod VITE_AUTH_TOKEN=prod_token_abc
panda projects deploy vite-app-prodThe panda projects env command sets variables, and panda projects deploy triggers a rebuild. This workflow is useful for automated testing: spin up a temporary deploy, run Cypress tests, tear it down.
What happens during the build
PandaStack clones your repository, runs npm install, then executes:
VITE_API_BASE_URL=https://api.acme.com \
VITE_AUTH_TOKEN=prod_token \
npm run buildVite reads those variables and replaces every occurrence of import.meta.env.VITE_API_BASE_URL in your code with the literal string "https://api.acme.com". The final bundle contains no environment variable lookups — just hardcoded values.
The dist/ directory gets uploaded to a CDN, and your app goes live. The variables are frozen into the build and won't change until you redeploy.
References
- [Vite environment variables](https://vitejs.dev/guide/env-and-mode.html)
- [PandaStack deploy button](https://docs.pandastack.io/projects/deploy-button)
- [Static site deployment](https://docs.pandastack.io/projects/static)