Skip to main content
HostwaresHostwares

Migrations

Move to Hostwares from Vercel, Netlify, Heroku, or any Docker host — sites, domains, databases, and env vars.

Overview

Hostwares can run anything that builds into a container or static output — Next.js, Vite, Astro, SvelteKit, Django, Rails, Go, or a plain Dockerfile. Most migrations finish in under 30 minutes: create a site from the same repo, copy env vars, move the DB, then cut over DNS.

FromWhat MovesHardest Part
VercelSite, env, domains, cronEdge middleware → standard middleware
NetlifySite, redirects, functionsRewriting _redirects / netlify.toml
HerokuApp, Postgres, config varsProcfile → start command
Docker / VPSImage or DockerfileSecrets & persistent volumes

Preflight Checklist

  • Repo URL and default branch (e.g., main)
  • Build command, start command, and port (check package.json scripts / Procfile / Dockerfile)
  • Full list of environment variables (including build-time vars)
  • Database engine, size, and connection string
  • Custom domains and current DNS provider
  • Background jobs / cron schedules
# Inventory script — run in your repo
echo "== Build ==" && cat package.json | grep -A5 '"scripts"'
echo "== Env keys ==" && grep -R "process.env" --include="*.ts" --include="*.js" | cut -d: -f2 | sort -u
echo "== Port ==" && grep -R "PORT" --include="*.ts" --include="*.js" | head
echo "== Node ==" && cat .nvmrc 2>/dev/null || cat package.json | grep node

From Vercel

  1. In Hostwares: New Project → GitHub Repository → pick the same repo/branch.
  2. Set build/start — auto-detected for Next.js, or override in Site → Settings → Build.
  3. Copy env vars (see Environment Variables below).
  4. Deploy and verify on the *.hostwares.app URL before touching DNS.
Vercel ConceptHostwares Equivalent
vercel.json rewrites/redirectsFramework config (next.config.js redirects) or reverse proxy
Edge MiddlewareStandard middleware / edge handled at CDN (e.g., Cloudflare Workers)
Serverless FunctionsLong-running container — no 10s timeout; keep as API routes
Cron (vercel.json)External cron → Hostwares webhook / API route
Analytics / Speed InsightsBring your own (PostHog, etc.) or Hostwares logs
// next.config.js — keep your Vercel redirects, they work here too
async redirects() {
  return [{ source: "/old", destination: "/new", permanent: true }];
}

// Cron replacement: trigger via Hostwares API
curl -X PATCH https://hostwares.com/api/sites/$SITE_ID \
  -H "Authorization: Bearer $HOSTWARES_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"action": "deploy"}'
// Or hit your own /api/cron route from an external scheduler (GitHub Actions cron, etc.)

From Netlify

  1. Create site from GitHub repo as above.
  2. Translate _redirects / netlify.toml into framework redirects or a reverse proxy.
  3. Move Netlify Functions to API routes or a separate service container.
# _redirects (Netlify)
/old  /new  301
/api/*  https://api.example.com/:splat  200

// Equivalent in next.config.js
async redirects() { return [{ source: "/old", destination: "/new", permanent: true }]; }
async rewrites() { return [{ source: "/api/:path*", destination: "https://api.example.com/:path*" }]; }

// Netlify Functions -> API routes
// Before: netlify/functions/hello.js
// After:  app/api/hello/route.js (Next.js) or /api/hello (any framework)

From Heroku

Heroku ConceptHostwares Equivalent
Procfile (web: npm start)Site → Settings → Start command
Config VarsSite → Environment (encrypted)
Heroku PostgresHostwares Databases (Postgres) — see Database Migration
BuildpacksNixpacks auto-detect or Dockerfile
Heroku SchedulerExternal cron → API route
# Procfile
web: npm start
worker: node worker.js

# On Hostwares:
# - web -> Site start command: npm start
# - worker -> One-Click Service or second site with start command: node worker.js

# Config vars -> env
heroku config --app my-app
# Copy each key/value into Site → Environment (mark secrets as encrypted)

From Docker / Any Host

If you already have a Dockerfile or a published image, deploy it directly:

# Option A: paste your Dockerfile into Hostwares (we build it)
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:20-alpine AS runner
WORKDIR /app
COPY --from=builder /app/.next ./.next
COPY --from=builder /app/node_modules ./node_modules
COPY package.json ./
EXPOSE 3000
CMD ["npm", "start"]

# Option B: deploy a prebuilt image
# Site -> New Project -> Docker Image
# Image: ghcr.io/org/app:latest
# Port: 3000

For private registries, store credentials as encrypted env vars — never in the image.

Database Migration

General flow works for Postgres, MySQL, or any SQL DB:

  1. Create a new database on Hostwares (Databases → New).
  2. Dump from source, restore to Hostwares.
  3. Point your site's DATABASE_URL at the new DB and redeploy.
# Postgres: dump from source, restore to Hostwares
pg_dump "$SOURCE_DATABASE_URL" -Fc -f dump.dump
pg_restore -d "$HOSTWARES_DATABASE_URL" --no-owner --no-acl dump.dump

# Alternative: plain SQL
pg_dump "$SOURCE_DATABASE_URL" | psql "$HOSTWARES_DATABASE_URL"

# MySQL
mysqldump -h $SRC_HOST -u $SRC_USER -p $SRC_DB | mysql -h $HW_HOST -u $HW_USER -p $HW_DB

# Verify row counts
psql "$HOSTWARES_DATABASE_URL" -c "SELECT count(*) FROM users;"
psql "$SOURCE_DATABASE_URL" -c "SELECT count(*) FROM users;"

# Large DBs: compress and checksum
pg_dump "$SOURCE_DATABASE_URL" -Fc | gzip > dump.gz
sha256sum dump.gz

Zero-downtime cutover

  • Put source DB in read-only or pause writes during the final dump.
  • For continuous sync, use logical replication if your source supports it, then promote.
  • Always create a manual backup on Hostwares after restore (Backups).

Domains & DNS Cutover

Keep downtime at zero with a staged cutover:

  1. Add domain in Hostwares: Site → Domains → Add Domain (do not change DNS yet).
  2. Verify ownership via the TXT record Hostwares shows you.
  3. Deploy and test on the Hostwares subdomain first.
  4. Lower DNS TTL to 60s at your provider before cutover.
  5. Switch DNS to Hostwares (CNAME for subdomains, A/ALIAS for apex — see Custom Domains Advanced).
  6. Wait for TLS to issue, then test https://yourdomain.com.
# Verify DNS propagation
dig +short yourdomain.com
dig +short www.yourdomain.com

# Check TLS
curl -I https://yourdomain.com

# Keep old host for 48h as instant rollback — just flip DNS back

Environment Variables

Export from source, import to Hostwares. Keep build-time and runtime vars separate.

# Vercel
vercel env pull .env.local
# Then import via API
curl -X PATCH https://hostwares.com/api/sites/$SITE_ID \
  -H "Authorization: Bearer $HOSTWARES_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "envVariables": [
      {"key": "DATABASE_URL", "value": "postgres://...", "encrypted": true},
      {"key": "NEXT_PUBLIC_API_URL", "value": "https://api.example.com"}
    ]
  }'

# Heroku
heroku config --json --app my-app | jq '[to_entries[] | {key: .key, value: .value}]'

# Netlify
netlify env:list --json

# Generic .env file -> API (bash)
while IFS='=' read -r k v; do
  [[ "$k" =~ ^#.*$ || -z "$k" ]] && continue
  echo "Importing $k"
done < .env.production
Var TypeExampleWhen to Set
Build-timeNEXT_PUBLIC_*, VITE_*Before first deploy — triggers rebuild
RuntimeDATABASE_URL, REDIS_URLBefore deploy; container reads at boot
SecretJWT_SECRET, STRIPE_KEYMark as Encrypted

Verify & Roll Back

  • Smoke test on the Hostwares subdomain before DNS cutover.
  • Check logshostwares logs --site $SITE_ID or Site → Logs.
  • Monitor for 30 minutes after cutover (error rate, p95).
  • Rollback is instant: revert DNS to the old host, or Site → Deployments → Rollback for app-level issues.
# Post-cutover checks
curl -s https://yourdomain.com/api/health | jq
curl -I https://yourdomain.com | grep -i "strict-transport"

# If anything is off — DNS rollback is one record change
# Keep old deployment live for 48h