How to deploy an app you built with AI to your own server
From a Lovable, Bolt.new, Replit, v0 or Claude Code project to a live URL on a server you control: code, build, backend, secrets, HTTPS and what breaks on the way.
TL;DR
- Get the code into a GitHub (opens in a new tab) repository, then find out whether it is static files (a Vite single-page app, which needs an
index.htmlfallback) or a server (Next.js (opens in a new tab), TanStack Start, Express) that needs Node.js (opens in a new tab) running. - Most builder apps keep their backend hosted (Supabase (opens in a new tab), Lovable (opens in a new tab) Cloud, Bolt (opens in a new tab) Database, Replit (opens in a new tab)'s database), so you can move only the frontend and keep it, or move both.
- Public variables such as
VITE_andNEXT_PUBLIC_are baked in at build time, so set them before you build, and keep real secrets on the server only. - Run the app in a container behind a reverse proxy such as Caddy (opens in a new tab), which gets and renews the HTTPS certificate by itself; before you switch the domain, check deep links, sign-in redirects and hardcoded preview URLs.
On this page
To deploy an AI-built app to your own server, you do five things: get the code into a Git repository, find out whether it is static files or a server, decide where its backend lives, build it into a container image with the right environment variables, and run that image behind a reverse proxy that serves your domain over HTTPS. Lovable, Bolt.new, Replit, v0 (opens in a new tab) and Claude Code (opens in a new tab) all take this path; what differs is the stack each one produces and the backend it leans on.
Every builder fact below comes from the builder's own documentation, checked on 11 November 2026. The Dockerfiles and the Caddy and Docker (opens in a new tab) Compose files in the builder guides were built and run in Docker the same day, on Node.js 22, against fresh apps from the Vite, TanStack Start and Next.js starters and a small Express and PostgreSQL (opens in a new tab) app.
When staying on the builder's hosting is the better choice
Every builder hosts what it builds: Lovable publishes to lovable.app with custom domains and a managed backend, Bolt has Bolt Cloud hosting with .bolt.host addresses, Replit publishes to its own Google Cloud (opens in a new tab) infrastructure, and v0 publishes to Vercel (opens in a new tab). Lovable's own docs recommend starting on Lovable, syncing the code with Git, and moving parts only when you hit a real constraint. Stay where you are when:
- you still build and change the app in the builder every day, and its one-click publish is part of that loop;
- the app is a prototype or an internal tool, and the builder's hosting costs less than your time;
- the app leans on services the builder runs for you and you do not want to replace them yet. Lovable's AI features and app connectors, for example, run through Lovable, and moving the built-in backend means replacing them with your own provider accounts.
Move when you need something the builder's hosting does not give you: a fixed monthly price, data in a region or on hardware you choose, other services on the same machine, root access, or an app that no longer depends on one vendor. The comparisons of your own server against Vercel and against hosting platforms in general go through the trade-offs.
Step 1: Get the code into a Git repository
| Builder | Way out | What to know |
|---|---|---|
| Lovable | Git sync with GitHub (github.com on every plan), GitLab (opens in a new tab) or Bitbucket (opens in a new tab); a .zip download on paid plans | Sync creates a new private repository and syncs both ways, one branch at a time |
| Bolt.new | GitHub from the project's GitHub icon; Download from the project title menu | Bolt creates a private repository on main and commits after each change |
| Replit | The Git pane (Tools, then Git), or git push from the Shell | Secrets and App Storage files do not travel with the code |
| v0 | Project menu, Settings, GitHub, Connect | v0 creates a private repository and pushes to a working branch per chat |
| Claude Code, Cursor (opens in a new tab) | The code is already on your computer | Commit it and push it to a repository you own |
Then clone the repository and run the app on your own computer. If it does not start locally, it will not start on a server, and a local run shows you every environment variable it expects.
Step 2: Find out what kind of app it is
Open package.json and look at the dependencies and the build and start scripts.
| What you find | What it is | What runs on the server |
|---|---|---|
vite and react, no server framework, a build script that writes dist/ | A static single-page app (Lovable projects from before 13 May 2026, and any builder's Vite app) | A web server that serves dist/ and answers unknown paths with index.html |
@tanstack/react-start | A TanStack Start app (Lovable projects since 13 May 2026) | Node.js running .output/server/index.mjs, port 3000 by default |
next | A Next.js app (every v0 project) | Node.js running the Next.js server, port 3000 by default |
express, fastify, hono or a start script that runs node | A Node.js server, sometimes serving a built frontend too | Node.js running the start script, on the port in PORT |
Step 3: Decide where the backend lives
Most builder apps keep their data and sign-in in a hosted service that the code reaches over the internet and that does not move with it:
- Lovable Cloud is Lovable's built-in backend, built on Supabase: a database, sign-in, file storage, edge functions and secrets. Lovable's docs describe hosting the frontend elsewhere while keeping it, and moving the backend only to managed or self-hosted Supabase.
- Supabase that you connected yourself is your own project, reachable from any host.
- Bolt Database is Bolt's built-in database. Bolt's documented way to own it is to claim it into your Supabase organisation, on the Pro or Teams plan.
- Replit's database is a managed PostgreSQL with separate development and production databases. Only the production one is reachable from outside the app, through its connection string, which is how you copy the data out.
- v0's integrations (Neon (opens in a new tab), Supabase, Upstash (opens in a new tab), Vercel Blob) are added through the Vercel Marketplace, and their connection values live in the Vercel project's environment variables.
Move the frontend first and keep the backend where it is. Once the app runs on your server against it, decide whether to move the data too, as a separate step with its own test.
Step 4: Sort the environment variables
Build-time public variables. Vite exposes variables that start with VITE_ to the browser and replaces them in the code at build time; Next.js does the same with NEXT_PUBLIC_. Their values end up inside the JavaScript every visitor downloads, so:
- they must be set when the image is built, not only when it runs, or the app ships with empty values;
- changing one means building again;
- they must never hold a secret. A Supabase URL and its publishable (anon) key are meant to be public; a service role key, a Stripe secret key or a database password is not.
Runtime variables. Everything else, read on the server while the app runs: DATABASE_URL, API secrets, session secrets. These go into the container's environment on the server, from a file that never enters the repository. A server-rendered app can need a public value twice: a Lovable TanStack Start app reads its Supabase URL and key as VITE_ values in the browser and again as SUPABASE_URL and SUPABASE_PUBLISHABLE_KEY on the server.
Collect both lists before you build. Lovable keeps its public Supabase values in the repository's .env; Bolt keeps environment variables in .env but its secrets only on Bolt's servers; Replit's secrets must be re-entered; v0 keeps everything in the Vercel project's settings.
Step 5: Put the app in a container
The Dockerfile depends on the stack from step 2; each builder article has one that was built and run for that stack:
- a static Vite app: build with Node.js, then serve
dist/with Caddy and anindex.htmlfallback (in the Lovable guide and the Bolt.new guide); - a TanStack Start app: build with Nitro's Node.js preset and run
node .output/server/index.mjs(the Lovable guide); - a Next.js app: build with
output: "standalone"and runnode server.js(the v0 guide, and Next.js on a VPS for more depth); - a Node.js server with a PostgreSQL database next to it (the Replit guide).
Every stack gets the same front door: a reverse proxy takes the public traffic on ports 80 and 443 and passes requests to the app. Caddy also handles the domain's HTTPS certificate by itself: when the domain's DNS record points at the server and ports 80 and 443 are open, it obtains and renews it and redirects HTTP to HTTPS. This Caddyfile is the whole configuration for an app that listens on port 3000:
app.example.com {
reverse_proxy app:3000
}This compose.yaml runs the app and Caddy together, with the certificate kept in a volume so it survives restarts:
services:
app:
build: .
env_file: .env.production
restart: unless-stopped
caddy:
image: caddy:2-alpine
restart: unless-stopped
ports:
- "80:80"
- "443:443"
- "443:443/udp"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- caddy_data:/data
- caddy_config:/config
volumes:
caddy_data:
caddy_config:Replace app.example.com with your domain; on the server, docker compose up -d --build builds the image and starts both. Build-time variables from step 4 go under build.args, as each builder guide shows. Only Caddy's ports are published to the internet, never the app's. We ran these files with localhost as the site address, where Caddy issues a certificate from its own local authority; a public certificate for a real domain needs a real server and DNS record, which this test did not cover.
Step 6: Get a server and point the domain at it
Any Linux server with Docker works, including one you already pay for. The general steps are the same for every app: how to deploy a web app to a VPS covers creating the server, SSH keys, the firewall and Docker; Docker Compose on Hetzner with GitHub Actions and a DigitalOcean Droplet walk through two providers; and Hetzner vs DigitalOcean helps you pick one.
For the domain, add an A record (and an AAAA record if the server has IPv6) pointing at the server's address. Caddy can only get the certificate after that record resolves, so set it before the first start.
Once the app is live, add deploys without downtime, so an update does not drop visitors, and a preview for every pull request, which replaces the builder's preview link.
Step 7: Fix what breaks after the move
Check each of these on a temporary address while the builder's hosting keeps running. Once all pass, move the domain and unpublish the old copy when you are ready.
| Symptom | Cause | Fix |
|---|---|---|
The app loads but data calls fail, or a value shows as undefined | A VITE_ or NEXT_PUBLIC_ variable was not set at build time | Pass it as a build argument and build again |
Refreshing /dashboard gives a 404 | A static single-page app with no fallback to index.html | Add the fallback (try_files {path} /index.html in Caddy) |
| Sign-in fails or sends users back to the old address | The new domain is not in the auth provider's redirect allow list | Add it to Supabase's Site URL and Redirect URLs, and to each OAuth provider |
Links, emails or API calls point at lovable.app, .bolt.host, .replit.app or vercel.app | A preview URL hardcoded in the code or in a variable | Search the repository for the old host and replace it with a variable |
| The server returns 502 | The app listens on localhost or a fixed port | Listen on 0.0.0.0 and on the port in PORT |
| Uploaded files disappear | The app writes files into the container | Use object storage or a mounted volume |
Lovable apps, and Bolt apps whose database you claimed into Supabase, sign users in through Supabase. Its Site URL is the default redirect address that confirmation and password-reset emails use, and its Redirect URLs list says where users may be sent after sign-in. In a Supabase project of your own, both are on the dashboard's URL Configuration page; for Lovable Cloud, Lovable's hosting guide says only to add the new address to the auth provider's allowed redirect URLs.
Deploy an AI-built app, builder by builder
- Lovable. Deploy a Lovable app to your own server covers both the Vite and the TanStack Start path, and the backend that is Supabase underneath.
- Replit. Deploy a Replit app to a VPS translates the four deployment types and the
.replitbuild and run commands, and copies the production database. - Bolt.new. Deploy a Bolt.new app to your own server gets the code out and claims Bolt Database into Supabase.
- v0. Deploy a v0 app without Vercel moves it to a standalone Next.js server and gets its environment variables out of Vercel.
- Claude Code and Cursor. The code is already yours; Claude Code built your app: here is how to put it online covers where it runs and how much of the deploy you let an agent do.
Doing this with OpsCrew
OpsCrew is an open-source tool that takes an app from its GitHub repository to a hardened server on your own cloud account. It recognises code exported from Lovable, Bolt, Replit and v0, and its free opscrew scan checks the repository for leaked keys and exposed Supabase or Firebase (opens in a new tab) data before you go live.
It builds the container image in GitHub Actions (opens in a new tab) with its own Dockerfile for Vite and Next.js apps and Node.js servers such as Express (or yours, if the repository has one), and handles VITE_ and NEXT_PUBLIC_ values as build-time values that are public by nature. It deploys to a new server on Hetzner Cloud (opens in a new tab) or DigitalOcean (opens in a new tab), or to a server you already have, buys or connects your domain on Cloudflare (opens in a new tab), and runs a database next to your app when you want one, or keeps the hosted one you already use. Every change waits for your approval of its exact plan. In Claude Code, the OpsCrew plugin runs the same flow from the chat. The setup page lists the accounts and tools you need, and use cases shows what it does for an app from an AI builder.
Key facts
| Fact | Value | Source |
|---|---|---|
| Lovable's default stack for new projects | TanStack Start (server-rendered) since 13 May 2026; older projects are React and Vite | Upgrade a project to TanStack Start (opens in a new tab)Verified on |
| What v0 generates | Next.js, React, TypeScript, Tailwind CSS and shadcn/ui | v0 FAQs (opens in a new tab)Verified on |
| Backend languages Bolt.new supports | JavaScript only (Node.js); PHP and Python backends are not supported | Bolt supported technologies (opens in a new tab)Verified on |
| Replit databases | Separate development and production databases, each with its own DATABASE_URL | Development and production databases (opens in a new tab)Verified on |
Frequently asked questions
How does Replit deploy apps, and can I run the same app elsewhere?
Replit publishes a snapshot of the app as an Autoscale, Static, Reserved VM or Scheduled deployment on its own Google Cloud infrastructure. The same code runs elsewhere if you copy the build and run commands from the .replit file, re-enter the secrets and move the production database with pg_dump.
Can Claude Code deploy apps?
Claude Code is an agentic coding tool, not a host. It can write the Dockerfile and deployment files and, with your permission, run deploy commands, but the app still needs somewhere to run: a platform or a server you control.
Do I need Docker to deploy an AI-built app?
No, but it is the simplest repeatable way to run one on your own server. The same image runs on your laptop, in CI and on the server, and the server needs only Docker installed.
Sources
- Deploying and hosting outside Lovable (opens in a new tab)
- Deployment, hosting, and ownership options with Lovable (opens in a new tab)
- Upgrade a project to TanStack Start (opens in a new tab)
- GitHub for version control (opens in a new tab)
- Supported technologies (opens in a new tab)
- Publishing (opens in a new tab)
- Development and production databases (opens in a new tab)
- v0 FAQs (opens in a new tab)
- Claude Code overview (opens in a new tab)
- Env variables and modes (opens in a new tab)
- How to self-host your Next.js application (opens in a new tab)
- Automatic HTTPS (opens in a new tab)
- Redirect URLs (opens in a new tab)
Related articles
- Deploying
Deploy a Bolt.new app to your own server
How to deploy a Bolt.new app outside Bolt Cloud: get the code, find out which stack Bolt chose, build it in Docker, serve it over HTTPS, and claim the database into Supabase.
- Deploying
Deploy a Lovable app to your own server (Vite or TanStack Start)
How to deploy a Lovable app to a server you control: tell the Vite and TanStack Start stacks apart, sync it to GitHub, build it in Docker, serve it over HTTPS, and keep or move the Supabase backend.
- Deploying
Deploy a Replit app to a VPS
How to move a Replit app to a VPS you control: push it to GitHub, turn the .replit build and run commands into a Dockerfile, re-create the secrets, and move the production database with pg_dump.