logo
Back to Blog
Cursor AIDeploymentDebuggingProduction EnvironmentVibe Coding

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

Convergex AIAugust 9, 20268 min read
A developer looking frustrated at a screen showing code, with a 'production error' message overlay, symbolizing the common 'works locally but not in production' problem.

It's a common headache: your Cursor app runs perfectly on localhost:3000 but breaks when deployed. This guide diagnoses and fixes hardcoded URLs, missing environment variables, and SQLite-to-Postgres migration issues, ensuring your AI-generated app thrives in production.

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 reasons your Cursor app works locally but not in production and, more importantly, how to fix them so your application runs reliably when it's actually deployed.

The Hardcoded URL Trap

One of the most frequent culprits when a Cursor app works locally but not in production is the use of hardcoded URLs. When you're developing, http://localhost:3000 or http://127.0.0.1:8000 is perfectly fine. However, in a production environment, your application will have a public domain, and any internal or external calls pointing to localhost will simply fail.

Where to Look for Hardcoded URLs

  • API Endpoints: Your frontend might be making API calls to a hardcoded local backend URL.
  • OAuth Redirect URIs: Authentication providers (like Supabase Auth, as seen in complex Cursor apps) often require specific redirect URIs. If these are localhost in production, your authentication flow will break.
  • Webhook Endpoints: Any services that need to call back into your application (e.g., payment gateways, background job processors like Inngest) will need a public URL.
  • Asset Paths: Less common, but sometimes image or script paths can inadvertently point to local resources.

The Fix: Environment Variables for URLs

The solution is to replace all hardcoded localhost references with environment variables. This allows you to dynamically inject the correct production URL at deployment time.

// Bad: Hardcoded URL
const API_BASE_URL = 'http://localhost:3001/api';

// Good: Using an environment variable
const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3001/api';

Remember to define NEXT_PUBLIC_API_URL (or whatever you name it) in your production environment settings. For Next.js applications, NEXT_PUBLIC_ prefixed variables are exposed to the browser, while others are server-side only.

Missing Environment Configuration

This is arguably the biggest reason a Cursor app works locally but not in production. Your local .env file is a development convenience; production servers do not automatically pick up these files. Every secret, API key, database connection string, and callback URL needs to be explicitly configured in your production environment. If you find your fix Cursor apps guide, this will almost certainly be covered.

Why Local .env Files Don't Cut It

When your app runs locally, your laptop handles everything, including loading variables from your .env file. When deployed, the hosting platform takes over, and it needs its own set of instructions for these variables. Missing variables often lead to silent failures, where functions just don't work, or the app crashes without a clear error message in the UI.

Auditing Your Environment Variables

Before deploying, you must audit every variable your app needs. Search your codebase for process.env references and list each one. This includes:

  • Database URLs: DATABASE_URL
  • API Keys: STRIPE_SECRET_KEY, OPENAI_API_KEY
  • Authentication Secrets: AUTH_SECRET, SUPABASE_KEY
  • Callback URLs: NEXTAUTH_URL, SUPABASE_REDIRECT_URL

Separate public frontend variables (e.g., NEXT_PUBLIC_...) from server-only secrets. Identify which variables must be available at build time versus runtime, as some platforms handle these differently.

Setting Variables in Production

Every hosting provider (Vercel, Railway, Netlify, etc.) has a dedicated section in their dashboard for environment variables. You'll need to manually add each variable from your audited list here. Ensure values are correct for production and not leftover development or test values.

SQLite to PostgreSQL Migration

AI-generated apps often default to SQLite for local development because it's file-based and requires zero setup. It's fantastic for getting started quickly. However, SQLite is not suitable for most production applications due to limitations in concurrency, scaling, and the challenges of managing a file-based database on a distributed server environment.

If your Cursor app works locally but not in production and involves a database, this is a prime suspect.

Why PostgreSQL is the Production Standard

PostgreSQL is a robust, open-source relational database that handles concurrent connections and large datasets gracefully. It's the go-to choice for production environments, especially for complex applications with authentication, user data, and background jobs, like the VibeSplit app mentioned in recent developments.

The Migration Process (with Prisma as an example)

Many Cursor-built apps leverage Prisma as an ORM, which simplifies database management significantly.

  1. Provision a PostgreSQL Database: Sign up for a hosted Postgres service. Popular choices include Supabase, Railway Postgres, or Vercel Postgres. Obtain your DATABASE_URL.

  2. Update Your Schema: If you used specific SQLite types that don't map directly to Postgres, you might need minor adjustments in your schema.prisma file. For most common types, Prisma handles the mapping automatically.

  3. Update Environment Variable: In your production environment settings, update the DATABASE_URL to point to your new PostgreSQL instance. Locally, you can update your .env file temporarily to test the connection:

    DATABASE_URL="postgresql://user:password@host:port/database?schema=public"
    
  4. Run Migrations: With Prisma, you'll apply your schema to the new Postgres database. First, generate a new migration if you made schema changes, then push it to the database:

    npx prisma migrate dev --name init
    npx prisma db push # For development, or 'npx prisma migrate deploy' for production
    

    The prisma migrate deploy command is crucial for production environments as it applies pending migrations.

  5. Seed Initial Data (if applicable): If your app relies on initial data (e.g., admin users, default settings), you'll need to run your seeding script against the new production database.

Verifying in a Real Environment: The Pre-Flight Check

Don't just deploy and hope for the best. Proactive verification can save hours of debugging. The gap between 'working on my machine' and 'accessible via a URL' is wider than most tutorials suggest, but a few simple checks go a long way.

1. Run a Local Build

Before even touching a hosting platform, run your build command locally. For most JavaScript projects, this is npm run build or yarn build. If it fails here, it will definitely fail in production. Fix any build errors immediately.

2. Test Environment Variables Locally (Simulated Production)

Temporarily comment out your local .env file and try to run your app, injecting environment variables directly into your shell. This helps catch missing or incorrectly referenced variables before deployment.

NEXT_PUBLIC_API_URL='https://api.yourdomain.com' npm run dev

3. Utilize Staging Environments

If your hosting platform supports it, deploy to a staging environment first. This is a near-identical replica of production where you can test thoroughly without affecting live users. This is invaluable for catching those subtle differences that make your Cursor app work locally but not in production.

4. Monitor Logs and Network Requests

Once deployed, diligently check the server logs provided by your hosting platform. Error messages here are your best friends. In your browser's developer tools, inspect the 'Network' tab to see if API calls are failing, returning unexpected errors, or pointing to incorrect URLs.

Get Your Vibe-Coded App to Production

Experiencing a Cursor app that works locally but not in production is a common hurdle, but it's a solvable one. By systematically addressing hardcoded URLs, ensuring robust environment configuration, and migrating from development databases like SQLite to production-ready solutions like PostgreSQL, you can bridge the gap between your local sandbox and a live, reliable application.

If you find these deployment challenges overwhelming, remember that Convergex AI specializes in taking 'vibe coded' prototypes and transforming them into production-ready products. We finish and fix Cursor-built apps, ensuring they run reliably when deployed and can be safely extended by future developers.

Related articles

Stuck at 80% on a vibe-coded app?

We finish, harden, and ship AI-generated apps. Let's talk.

Book a 15 min intro call