Works in preview but breaks in production
Why it happens
An app that runs flawlessly in preview can break the moment you publish. This is almost always caused by environmental differences between the two runtimes - preview and production each have their own isolated environment, filesystem, and configuration.
Info
Preview and production are completely separate containers. A change in one does not automatically propagate to the other. See Preview vs Published for details.
Common culprits
Environment variables not set in production
The most frequent cause. If your code reads
process.env.STRIPE_SECRET_KEY and that variable exists in preview but not production, the app will fail.
What to check:
- Open the Manage → Secrets panel in your workspace
- Confirm every variable your app needs is present in production
- Environment variables flow automatically on publish, but new keys( not values) must be added to
by the agent and then republished, the Secrets UI(Manage → Secrets) can only edit values of existing keys, not add new ones.env - Re-publish after adding missing variables
Tip
Agents often set variables in preview during development via
.env files. If a key was set in the preview pod but never written to .env, it will not be present in production. Ask the agent to add any missing keys to .env, then re-publish.Hardcoded localhost
or preview URLs
localhostCode that references
http://localhost:3000 or your preview URL ({slug}.preview.emergentagent.com) will break in production because those addresses are unreachable from the live published app.
Examples:
- API base URLs:
const API = "http://localhost:8000" - Webhook callbacks:
callbackUrl: "https://my-app.preview.emergentagent.com/hook" - OAuth redirect URIs hardcoded to preview
Fix:
Use environment variables for all URLs:
const API_BASE = process.env.NEXT_PUBLIC_API_URL || "http://localhost:3000";Set
NEXT_PUBLIC_API_URL differently in preview vs production.
CORS configuration pointing to the wrong origin
If your backend explicitly allows only your preview domain:
allowed_origins = ["https://my-app.preview.emergentagent.com"]…production requests from
https://my-app.emergent.host (or your custom domain) will be blocked.
Fix:
- Use an environment variable for allowed origins
- Or allow both domains
- Or use a wildcard pattern if security allows
Files written at runtime disappear
Production containers use an ephemeral filesystem. Any file your app writes to disk (uploads, generated PDFs, cached images) will be lost on restart or scale-out.
Symptoms:
- User uploads work initially, then vanish
- Generated files return 404 after a few hours
- SQLite databases lose data
Fix:
Use Emergent Object Store for persistent file storage. Never rely on the local filesystem for data that must survive restarts.
Do not use local disk for persistence
The container filesystem is wiped on every re-publish and can be cleared at any time during autoscaling.
Missing system dependencies
Preview may have been running on a container that happened to have a system tool installed, but production does not.
Common examples:
| Tool | Used for | Symptom in production |
|---|---|---|
| Video encoding, audio extraction | "ffmpeg: command not found" |
| Playwright | Browser automation, screenshots | Chromium binary missing |
| ImageMagick | Image resizing, format conversion | "convert: not found" |
| wkhtmltopdf | HTML-to-PDF rendering | PDF generation fails silently |
Fix:
Declare dependencies in your project:
- Add
to your build scriptplaywright install - Declare the required package dependencies explicitly in your project configuration
- Or ask the agent to install it via system packages
If the tool was present in preview by chance, you must explicitly require it for production.
Webhooks still pointing to preview
External services (Stripe, Twilio, GitHub) may still have webhook URLs pointing to your preview instance.
What happens:
- Payment confirmations arrive in preview but not production
- SMS replies are processed in the wrong environment
- OAuth flows redirect to the old URL
Fix:
- Log into each third-party service
- Update webhook/callback URLs to your production domain
- Test the flow end-to-end in production
Use environment-specific webhook secrets
Store separate webhook signing secrets for preview and production so you can safely test webhooks without triggering real side effects.
Debugging checklist
Compare environment variables
Open the Preview → Manage → Secrets panel and ensure every variable in preview also exists in production with the correct value. Remember: new keys must be added to
.env by the agent and republished.Check logs
View production logs in the workspace. Look for missing-variable errors, connection timeouts, or "command not found."
Search for hardcoded URLs
Grep your codebase for
localhost, 127.0.0.1, .preview.emergentagent.com and replace with environment variables.Verify CORS origins
Ensure your backend allows requests from your production domain (or custom domain if configured).
Audit file writes
If your app writes files, confirm they go to Object Store, not
/tmp or the project directory.Confirm system dependencies
If preview worked but production crashes on a missing binary, declare that dependency explicitly in your project configuration.
Update external webhooks
Check every third-party integration and point webhooks to your live domain.
Still broken?
If none of the above applies, describe the exact error message in chat - agents can compare your preview and production configurations and identify the mismatch.

