Cursor App Works Locally But Not in Production? Here's the Fix.

It's a common headache: your Cursor app runs perfectly on localhost but breaks when deployed. We'll diagnose and fix hardcoded URLs, missing environment variables, and SQLite-to-Postgres migration issues, ensuring your Cursor app works locally but not in production is a problem of the past.
You've just spent a few evenings with Cursor, crafting what feels like a genuinely innovative application. It runs beautifully on localhost:3000, the UI is slick, and the backend hums along. You're ready to share it with the world. Then, the inevitable happens: you deploy, and your Cursor app works locally but not in production. This isn't a unique problem; it's a rite of passage for many AI-generated apps that move from local sandbox to live server. The gap between 'working on my machine' and 'accessible via a URL' is often wider than expected, leading to frustration and wasted time.
At Convergex AI, we regularly see these issues with 'vibe coded' applications. The good news is that most of these deployment pitfalls are predictable and fixable. This hands-on guide will walk you through the most common culprits when your Cursor app works locally but not in production, providing specific solutions to get your application running reliably in any environment.
The Hardcoded URL Trap
One of the most frequent reasons a Cursor app works locally but not in production is the presence of hardcoded URLs. During rapid development, especially with AI assistance, it's easy to bake localhost:3000 or similar local endpoints directly into your code. While this works perfectly in your development environment, it becomes a critical failure point when deployed to a live server with a different domain or IP address.
Why it happens:
AI agents, trained on vast codebases, often prioritize functional examples over robust, environment-agnostic configurations. They'll generate code that works for the immediate context, which is typically your local machine.
The Fix: Environment Variables for URLs
The solution is simple: replace all hardcoded URLs with environment variables. This allows you to configure different URLs for development, staging, and production without changing your codebase.
- Identify all instances: Search your project for
localhost:,127.0.0.1:, or any specific port numbers (e.g.,:3000,:8000). Pay close attention to API endpoints, OAuth redirect URIs, and asset paths. - Define environment variables: For each identified URL, create a descriptive environment variable. For example,
NEXT_PUBLIC_API_URLfor your frontend API calls andDATABASE_URLfor your backend. - Update your code: Replace the hardcoded strings with references to these new environment variables.
Consider this common pattern in a Next.js app:
// Before (bad practice)
const API_BASE = "http://localhost:8000/api";
// After (good practice)
const API_BASE = process.env.NEXT_PUBLIC_API_URL || "http://localhost:8000/api";
For server-side code, you might omit the NEXT_PUBLIC_ prefix, as these variables are not exposed to the client. Ensure your .env file reflects your local development setup and your production environment variables are configured correctly on your hosting platform.
Missing Environment Configuration
Another major culprit behind a Cursor app working locally but not in production is improperly configured or missing environment variables in your deployment environment. Your local .env file is a sanctuary for secrets and configurations, but it's not deployed with your application.
Why it happens:
AI often generates code that implicitly relies on .env files for configuration. When you deploy, these files are typically ignored for security reasons, leaving your production server without crucial API keys, database credentials, and other settings.
The Fix: Audit and Configure
- Pre-Flight Check: Before even attempting to deploy, run your build command locally (e.g.,
npm run buildoryarn build). If it fails here, it will definitely fail in production. Fix any errors before proceeding. Then, document every variable in your.envfile. This list is your blueprint for production. - Audit
process.envreferences: Systematically search your entire codebase for every instance ofprocess.env. List each variable you find. This ensures you don't miss any critical configurations. - Separate public vs. secret: Differentiate between variables needed by the frontend (e.g.,
NEXT_PUBLIC_variables in Next.js) and server-only secrets (e.g., database URLs, API keys). - Build-time vs. Runtime: Identify variables that must be available during the build process versus those that can be loaded at runtime. Some platforms require certain variables to be present during build for optimizations.
- Configure on the server: Every hosting platform (Vercel, Railway, Render, etc.) provides a secure way to manage environment variables. Manually add each audited variable to your platform's environment store. Never commit
.envfiles to your repository.
// Example of a secret environment variable
const STRIPE_SECRET_KEY = process.env.STRIPE_SECRET_KEY;
if (!STRIPE_SECRET_KEY) {
throw new Error("STRIPE_SECRET_KEY is not defined. Check your environment variables.");
}
Explicitly checking for variable existence, as shown above, can help prevent silent failures in production.
SQLite to PostgreSQL Migration
It's incredibly common for a Cursor-built app to use SQLite locally. It's fast, file-based, and requires zero setup – perfect for rapid prototyping. However, SQLite is almost never suitable for production environments, especially for web applications.
Why it breaks in production:
- Concurrency: SQLite struggles with multiple concurrent writes, leading to database locking issues and poor performance under load.
- Scalability: It's designed for single-user, local access, not for networked applications with many users.
- Deployment: A file-based database doesn't easily persist across server restarts or scale across multiple instances in a typical cloud deployment.
The Fix: Migrate to a Robust Database (e.g., PostgreSQL)
The standard solution is to migrate your database to a production-grade relational database like PostgreSQL. Platforms like Supabase, Railway, and Render offer managed PostgreSQL services that integrate seamlessly.
-
Provision a PostgreSQL database: Set up a new PostgreSQL instance on your chosen cloud provider. You'll get a connection string (the
DATABASE_URL). -
Update your ORM configuration: If you're using Prisma, TypeORM, or Sequelize, update your configuration to point to the new PostgreSQL
DATABASE_URL.For Prisma, your
schema.prismamight change from:datasource db { provider = "sqlite" url = env("DATABASE_URL") }To:
datasource db { provider = "postgresql" url = env("DATABASE_URL") } -
Migrate your schema: Run your ORM's migration commands to apply your database schema to the new PostgreSQL instance. For Prisma, this would be
npx prisma migrate dev --name init(for initial setup) ornpx prisma migrate deployfor production. -
Migrate your data (if any): If you have existing data in your local SQLite database that you need to preserve, you'll need to export it (e.g., to CSV or SQL dumps) and import it into your new PostgreSQL database. There are many tools available for this, depending on your ORM and database.
-
Update environment variables: Ensure your production environment on your hosting platform has the correct
DATABASE_URLpointing to your PostgreSQL instance.
Verifying in a Real Environment
Simply deploying isn't enough; you need to verify your fixes. It’s not uncommon for a Cursor app to work locally but not in production even after applying these changes if verification is skipped.
- Local Build & Preview: Before pushing to production, always run
npm run buildlocally. If it builds successfully, use your hosting provider's local preview command (e.g.,vercel devornext startafternext build) to test it in a production-like environment on your machine. - Staging Environment: If possible, deploy to a staging environment first. This is a mirror of your production setup but isolated. It allows you to catch issues without impacting live users.
- Check Logs: After deployment, immediately check your application logs. Look for database connection errors, API call failures, or missing environment variable warnings.
- Manual Testing: Thoroughly test every critical feature of your application in the deployed environment. Don't assume anything works just because it built.
- Monitor Performance: Use monitoring tools to observe your application's performance, error rates, and resource utilization. This can reveal subtle issues that manual testing might miss.
If you find yourself repeatedly struggling with these types of deployment issues, remember that you don't have to tackle them alone. Convergex AI specializes in taking vibe-coded prototypes and turning them into production-ready products. We can help you fix Cursor apps and ensure your innovative ideas are deployed reliably.
Sources & further reading
- https://www.convergexai.com/blog/cursor-app-works-locally-but-not-in-production-heres-the-fix
- https://www.convergexai.com/fix/cursor
- https://dev.to/thpl/deploying-a-complex-cursor-built-app-prisma-postgres-inngest-supabase-in-production-4019
- https://repoassistant.com/cursor-env-vars-not-loading
- https://interloper.io/blog/how-to-deploy-cursor-app-to-production
- https://blink.new/blog/how-to-deploy-cursor-app
- https://www.rapidevelopers.com/cursor-tutorial/how-to-specify-environment-variables-so-cursor-ai-s-suggestions-match-local-qa-or-production-setups
- https://noprod.dev/blog/deploy-vibe-coded-app