Deploy a Lovable export

Take the app Lovable built you and put it on a live HTTPS URL of your own.

Lovable exports a standard Vite + React project, so deploying it on Dockhold is the Vite path with two export-specific steps: get the code onto GitHub, and carry over any environment variables Lovable used. This recipe is the whole path.

1. Get the code on GitHub

In Lovable, connect the project to GitHub (the GitHub option in your project's settings) so your code lives in a repository you own. That repo is what Dockhold deploys.

2. Add a start command that serves the build

A Lovable export already has a build script. Add a small static server so the built app is served on the port Dockhold assigns:

npm install --save-dev serve

Then make sure package.json has:

{
  "scripts": {
    "build": "vite build",
    "start": "serve -s dist -l $PORT"
  }
}

Your app must listen on 0.0.0.0 and read its port from the PORT environment variable — never localhost, never a hardcoded port. Dockhold assigns PORT at runtime; an app that ignores it can't receive traffic.

Then add a Dockerfile at the repo root so the export is built before it's served:

FROM node:20-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:20-alpine
WORKDIR /app
RUN npm install -g serve@14
COPY --from=build /app/dist ./dist
# Shell form so $PORT expands at runtime
CMD serve -s dist -l $PORT

Without the Dockerfile, the build system can serve an exported SPA as raw source — you'll get a blank page. The Dockerfile builds it first.

3. Carry over your Supabase config

A Lovable app talks to Supabase using a project URL and an anon key. By default the export reads them from VITE_-prefixed variables that Vite inlines into the build, which means baking them into the repo. The cleaner path on Dockhold is to set them in the dashboard and read them at runtime: the container writes your dashboard values into the page when it starts, and your code reads them from window.__APP_CONFIG__ instead of import.meta.env. You can then change or rotate them in the dashboard with no rebuild. The full-stack recipe and the fullstack-web template show the exact setup — point your Supabase client at the runtime values the same way.

A Supabase anon key is designed to be public, so it's safe in the browser — but a service-role key is not, and neither is any other real secret. Keep those on a server (your own API or a Next.js route handler), never in the frontend bundle.

4. Connect the repo and deploy

  1. Open the dashboard, connect GitHub, and pick the repo.
  2. Dockhold builds from your Dockerfile and runs it.

Your app goes live at https://<your-app>.dockhold.app with HTTPS handled for you. Every later push to your main branch redeploys.

Troubleshooting

  • Blank page, and the browser is fetching /src/main.jsx: the un-built source is being served — make sure the Dockerfile is at the repo root so the export is built first.
  • 404 on refresh of a client route: keep the -s flag (serve -s dist) — it sends client-side routes to index.html.
  • "Failed to fetch" / Supabase calls fail: the Supabase URL or anon key isn't reaching the app. Set them as dashboard variables and make sure your client reads the runtime values (window.__APP_CONFIG__), then restart.

Next