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.
| From | What Moves | Hardest Part |
|---|---|---|
| Vercel | Site, env, domains, cron | Edge middleware → standard middleware |
| Netlify | Site, redirects, functions | Rewriting _redirects / netlify.toml |
| Heroku | App, Postgres, config vars | Procfile → start command |
| Docker / VPS | Image or Dockerfile | Secrets & persistent volumes |
Preflight Checklist
- Repo URL and default branch (e.g.,
main) - Build command, start command, and port (check
package.jsonscripts / 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 nodeFrom Vercel
- In Hostwares: New Project → GitHub Repository → pick the same repo/branch.
- Set build/start — auto-detected for Next.js, or override in Site → Settings → Build.
- Copy env vars (see Environment Variables below).
- Deploy and verify on the
*.hostwares.appURL before touching DNS.
| Vercel Concept | Hostwares Equivalent |
|---|---|
vercel.json rewrites/redirects | Framework config (next.config.js redirects) or reverse proxy |
| Edge Middleware | Standard middleware / edge handled at CDN (e.g., Cloudflare Workers) |
| Serverless Functions | Long-running container — no 10s timeout; keep as API routes |
| Cron (vercel.json) | External cron → Hostwares webhook / API route |
| Analytics / Speed Insights | Bring 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
- Create site from GitHub repo as above.
- Translate
_redirects/netlify.tomlinto framework redirects or a reverse proxy. - 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 Concept | Hostwares Equivalent |
|---|---|
Procfile (web: npm start) | Site → Settings → Start command |
| Config Vars | Site → Environment (encrypted) |
| Heroku Postgres | Hostwares Databases (Postgres) — see Database Migration |
| Buildpacks | Nixpacks auto-detect or Dockerfile |
| Heroku Scheduler | External 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: 3000For private registries, store credentials as encrypted env vars — never in the image.
Database Migration
General flow works for Postgres, MySQL, or any SQL DB:
- Create a new database on Hostwares (Databases → New).
- Dump from source, restore to Hostwares.
- Point your site's
DATABASE_URLat 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.gzZero-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:
- Add domain in Hostwares: Site → Domains → Add Domain (do not change DNS yet).
- Verify ownership via the TXT record Hostwares shows you.
- Deploy and test on the Hostwares subdomain first.
- Lower DNS TTL to 60s at your provider before cutover.
- Switch DNS to Hostwares (CNAME for subdomains, A/ALIAS for apex — see Custom Domains Advanced).
- 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 backEnvironment 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 Type | Example | When to Set |
|---|---|---|
| Build-time | NEXT_PUBLIC_*, VITE_* | Before first deploy — triggers rebuild |
| Runtime | DATABASE_URL, REDIS_URL | Before deploy; container reads at boot |
| Secret | JWT_SECRET, STRIPE_KEY | Mark as Encrypted |
Verify & Roll Back
- Smoke test on the Hostwares subdomain before DNS cutover.
- Check logs —
hostwares logs --site $SITE_IDor 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