Deploying an app you did not write
You described an app. Something built it. It works in the preview. Now you want it on your own domain, with your own database, and the instructions start with “add a Dockerfile” and end somewhere near VPC subnet CIDR ranges.
This is not a knowledge gap you should have to close. The app is finished. What is missing is a description of how to run it, and that description is derivable from the app itself.
What those tools actually hand you
Lovable, v0, Bolt and Cursor produce an ordinary web application. Open the folder and you find a package.json, a framework, and source files. There is nothing exotic in there. A React app generated from a sentence is the same shape as a React app typed by a person over three weeks.
What is usually absent is the operational half: no Dockerfile, no infrastructure definition, often no .env.example, and a start script inherited from a template rather than matched to the code. None of that is a defect. It is simply not what those tools are for.
So the honest framing is not “AI-generated apps are hard to deploy”. It is “apps without an operational description are hard to deploy”, and generated apps are just the most common example.
The four gaps between a preview and a deploy
In our experience these are the four that actually bite, roughly in order of how often.
1.The start command points at something nothing built
package.json says "start": "node dist/server.js" because the template it came from compiled TypeScript. Your app is plain JavaScript in src/. The build succeeds, the container starts, and Node exits immediately with Cannot find module.
It is the single most common failure we see, and it is a one-line fix once you can read the crash. We wrote up that error in detail.
2.The app hardcodes a port
Generated code often has app.listen(3000). A platform assigns a port and expects your app to read it from process.env.PORT. When it does not, health checks hit a closed port, the container looks dead, and the deploy rolls back with nothing useful in the build log.
The fix is app.listen(process.env.PORT || 3000). The detection is the hard part, not the change.
3.The preview supplied things production does not
Previews are generous. They often provide a database, an auth provider, and environment variables you never saw. In production none of that exists until you create it, so the app boots and then fails on its first query with a connection error to a host that was never real.
Worth listing every process.env reference in the code before the first deploy. That list is your actual configuration requirement, and it is usually shorter than you fear.
4.Static and server-rendered look identical until the bill arrives
A React or Vite app with no server code is files: HTML, JavaScript, CSS. It can sit in object storage behind a CDN and cost essentially nothing. A Next.js app using server rendering or API routes needs a process running all the time, which costs about $42 a month on AWS once you include the load balancer.
Same visible product, two very different bills. We broke those numbers down here. Knowing which one you have is worth a few minutes.
Why “just add a Dockerfile” is bad advice
Every piece of information a Dockerfile contains is already in your repository. Which language: the manifest. Which package manager: the lockfile. How to build: the build script. How to start: the start script, or the framework’s convention. Which port: the code, or the framework’s default.
Asking you to write it down in Docker syntax is asking you to transcribe facts a machine can read, in a language you do not otherwise need, where a mistake produces an error about module resolution rather than about the thing you got wrong.
A platform can read those facts instead. That is what Eigon does: it works out the framework, the package manager, the build and start commands and the port, writes the Dockerfile, and shows you what it concluded before it builds anything. When it gets something wrong you correct one field rather than learning a file format.
What to do before your first deploy
Four things, fifteen minutes, whatever platform you use:
- Read your start script. Open
package.jsonand check that the file it names exists. If it points intodistorbuild, make sure something compiles it. - Search for a hardcoded port. Grep for
listen(. If a number is there with noprocess.env.PORT, fix that now. - List your environment variables. Grep for
process.env. Everything it finds has to exist in production, including the ones the preview gave you silently. - Decide if you need a server at all. No API routes, no server rendering, no server actions means you need a CDN, not a container, and your hosting bill is close to zero.
An app nobody typed is still just an app
We deliberately do not have a “Lovable mode” or a “v0 importer”. Eigon reads what is in the repository, not what wrote it, so an app generated from a sentence and an app typed by hand go down the same path. That is the point: the tool that produced your code should not determine whether it can be deployed properly.
What does change with generated code is how often the operational half is missing, which is why the detection and the repair matter more than the deploy. When a deploy fails, Eigon reads the container’s own crash output, names the cause in one line, proposes the exact edit, and records whether it worked.
Want to know what your app needs before committing to anything? Paste a public repository URL and you get the framework, the services it would need, the projected monthly cost and anything that would stop a deploy. No account, no card.
