Deploying

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

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

How each builder gets its code to GitHub, checked 11 November 2026
BuilderWay outWhat to know
LovableGit 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 plansSync creates a new private repository and syncs both ways, one branch at a time
Bolt.newGitHub from the project's GitHub icon; Download from the project title menuBolt creates a private repository on main and commits after each change
ReplitThe Git pane (Tools, then Git), or git push from the ShellSecrets and App Storage files do not travel with the code
v0Project menu, Settings, GitHub, Connectv0 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 computerCommit 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.

The stacks AI builders produce and what each needs to run
What you findWhat it isWhat 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-startA TanStack Start app (Lovable projects since 13 May 2026)Node.js running .output/server/index.mjs, port 3000 by default
nextA 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 nodeA Node.js server, sometimes serving a built frontend tooNode.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:

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.

What breaks after you move an AI-built app, and why
SymptomCauseFix
The app loads but data calls fail, or a value shows as undefinedA VITE_ or NEXT_PUBLIC_ variable was not set at build timePass it as a build argument and build again
Refreshing /dashboard gives a 404A static single-page app with no fallback to index.htmlAdd the fallback (try_files {path} /index.html in Caddy)
Sign-in fails or sends users back to the old addressThe new domain is not in the auth provider's redirect allow listAdd 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.appA preview URL hardcoded in the code or in a variableSearch the repository for the old host and replace it with a variable
The server returns 502The app listens on localhost or a fixed portListen on 0.0.0.0 and on the port in PORT
Uploaded files disappearThe app writes files into the containerUse 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

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

FactValueSource
Lovable's default stack for new projectsTanStack Start (server-rendered) since 13 May 2026; older projects are React and ViteUpgrade a project to TanStack Start (opens in a new tab)Verified on
What v0 generatesNext.js, React, TypeScript, Tailwind CSS and shadcn/uiv0 FAQs (opens in a new tab)Verified on
Backend languages Bolt.new supportsJavaScript only (Node.js); PHP and Python backends are not supportedBolt supported technologies (opens in a new tab)Verified on
Replit databasesSeparate development and production databases, each with its own DATABASE_URLDevelopment 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

  1. Deploying and hosting outside Lovable (opens in a new tab), Lovable, accessed on
  2. Deployment, hosting, and ownership options with Lovable (opens in a new tab), Lovable, accessed on
  3. Upgrade a project to TanStack Start (opens in a new tab), Lovable, accessed on
  4. GitHub for version control (opens in a new tab), Bolt, accessed on
  5. Supported technologies (opens in a new tab), Bolt, accessed on
  6. Publishing (opens in a new tab), Replit, accessed on
  7. Development and production databases (opens in a new tab), Replit, accessed on
  8. v0 FAQs (opens in a new tab), Vercel, accessed on
  9. Claude Code overview (opens in a new tab), Anthropic (opens in a new tab), accessed on
  10. Env variables and modes (opens in a new tab), Vite, accessed on
  11. How to self-host your Next.js application (opens in a new tab), Vercel, accessed on
  12. Automatic HTTPS (opens in a new tab), Caddy, accessed on
  13. Redirect URLs (opens in a new tab), Supabase, accessed on
  • 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.

    8 min read

  • 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.

    9 min read

  • 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.

    8 min read

Put OpsCrew to work on your app.

Run npx opscrew init in your app's repository. It checks your tools and tokens first, for free.