Background
WICHI is a GEO (Generative Engine Optimization) SaaS. The frontend stack is Vite + React 18 + TypeScript + shadcn/ui. The backend runs on FastAPI, DB and Auth on Supabase, and server hosting on Railway. The initial frontend was built with Lovable, which also handled builds, deployment, and custom domain management.
This post documents the migration of frontend hosting from Lovable to Vercel — the reasons, planning, execution, issues encountered, and retrospective.
Pre-Migration Architecture
| Layer | Technology | Hosting |
|---|---|---|
| Frontend | Vite + React 18 + TS + shadcn/ui | Lovable |
| Backend API | FastAPI + Python | Railway |
| DB / Auth | Supabase (PostgreSQL + Auth + RLS) | Supabase Cloud |
| DNS | Cloudflare | — |
| Domain | wichi.app | Cloudflare-managed |
The key point: Lovable’s scope was limited to frontend build + hosting + custom domain. Backend, DB, Auth, and payments all operated independently from Lovable. This kept the migration scope contained and the difficulty low.
Why We Migrated
Lovable was valuable during initial prototyping. Prompt-based UI generation let us iterate fast, and it was instrumental in building WICHI’s first frontend version. Completing the frontend in 3 days during the Jocoding hackathon would not have been possible without Lovable.
The problems surfaced as we moved toward commercialization.
No Git-First Workflow
Lovable uses its own editor where you modify UI via prompts, then pushes changes to GitHub. The reverse direction is not supported — code modified directly on GitHub cannot be pulled into Lovable.
Problems this caused:
| Problem | Description |
|---|---|
| Branch conflicts | Lovable works on main, Claude Code works on dev. Merge conflicts were frequent |
| No PR-based review | Lovable pushes directly to main, bypassing PR-based code review |
| Opaque change history | Lovable’s auto-generated commit messages are prompt summaries; change intent is unclear |
| One-way sync | No GitHub-to-Lovable sync; externally modified code is not reflected in Lovable’s editor |
Even for solo development, PR-based workflows are valuable. Reviewing diffs before merging and verifying in a preview environment are basic safeguards against mistakes.
Limited Deployment Control
Production environments require fine-grained deployment configuration. Items that could not be directly managed on Lovable hosting:
- Redirect rules: SPA client-side routing fallback rewrite — redirecting deep links like
/dashboard/report/123toindex.html - Security headers: Customizing
X-Frame-Options,Content-Security-Policy,Strict-Transport-Security - Cache policies: Static asset cache expiration,
Cache-Controlheader control - Environment variable separation: Per-environment (Production, Preview, Development) variable management
- Build command customization: Pre/post-build scripts, per-environment build flags
SPA rewrite was especially critical. Without redirect rules in a React Router SPA, refreshes and deep link access return 404. On Lovable hosting, this setting was not directly accessible — Lovable handled it internally, making debugging difficult when issues arose.
Dependency Lock-in
Lovable-specific dependencies remained in the codebase:
lovable-tagger: A tagging plugin for Lovable’s editor to identify components, registered as a Vite build plugin- Configuration code for Lovable editor integration
These dependencies are unnecessary outside Lovable and must be removed when migrating to another host. The deeper the dependencies grow, the higher the migration cost — removing them early was advantageous.
Cost Structure
Lovable subscription costs $25/month ($300/yr). Vercel’s Hobby plan is free, and at WICHI’s traffic level (static site, early stage), there was no chance of exceeding the free tier’s 100GB monthly bandwidth limit.
Cost savings was not the primary migration driver. Git-first workflow and deployment control were the main reasons; cost savings was a side benefit.
Decision Matrix
| Criterion | Keep Lovable | Migrate to Vercel | Verdict |
|---|---|---|---|
| Workflow | Hybrid (Lovable + Claude Code) | Git-first single tool | Vercel wins |
| Deploy control | Limited | Full control (vercel.json) | Vercel wins |
| PR Preview | Not available | Auto-generated per PR | Vercel wins |
| Rollback | Manual restoration | Instant rollback to previous deploy | Vercel wins |
| Visual editor | Available | Not available | Lovable wins |
| Migration risk | None | Low (standard Vite project) | Acceptable |
| Downtime | None | 1-5 min during DNS switch | Acceptable |
Lovable’s only advantage was the visual editor. At the commercialization stage, Git-first workflow and deployment control outweighed the visual editor’s value.
Migration Plan
Prerequisites Verified
- Code ownership: Full source in GitHub repo (
vista-sphere-pro), buildable outside Lovable. Standard Vite project —npm run buildconfirmed working - Lovable dependency scope:
lovable-taggerregistered as devDependency only; no Lovable-dependent runtime code - Environment variable inventory: All frontend-referenced env vars cataloged —
VITE_API_URL,VITE_SUPABASE_URL,VITE_SUPABASE_ANON_KEY, etc. Fallback values were hardcoded, so Vercel env setup was not strictly required but planned for environment separation - DNS status: Confirmed wichi.app CNAME pointing to Lovable hosting in Cloudflare, checked TTL values
Execution Sequence
flowchart TD
A["1. Connect repo to Vercel\n(no downtime)"] --> B["2. Configure env variables\n(no downtime)"]
B --> C["3. Full test on Preview deploy\n(no downtime)"]
C --> D{"Tests pass?"}
D -->|Yes| E["4. Switch DNS CNAME\n(1-5 min downtime)"]
D -->|No| F["Fix issues, retest"]
F --> C
E --> G["5. Update CORS settings\n(no downtime)"]
G --> H["6. Remove Lovable-specific code\n(no downtime)"]
H --> I["7. Verify and monitor"]
The core principle: limit downtime to the single DNS switch step. Complete staging deployment and full testing on Vercel first, then switch DNS — actual downtime is confined to DNS propagation time.
Downtime Minimization
| Preparation | Description |
|---|---|
| Pre-lower TTL | Reduced CNAME TTL to 60 seconds the day before, ensuring rapid DNS cache expiration after switch |
| Staging verification | Complete functional testing on *.vercel.app domain before switching |
| Rollback plan | Reverting DNS CNAME to Lovable provides instant rollback; delay Lovable subscription cancellation until switch is confirmed |
| Switch timing | Execute during lowest-traffic window |
Execution
Step 1: Vercel Project Setup
Connected the GitHub repository to Vercel with default settings:
- Import Project on Vercel dashboard, select GitHub repo
- Framework Preset: Vite (auto-detected)
- Build Command:
npm run build(default) - Output Directory:
dist(default) - Root Directory:
/(default)
Recognized as a standard Vite project with no special configuration needed.
Step 2: Environment Variables
Configured in Vercel’s Environment Variables section. Vercel separates environment variables across Production / Preview / Development.
| Variable | Production | Preview | Description |
|---|---|---|---|
VITE_API_URL | Production API URL | Staging API URL | Backend API endpoint |
VITE_SUPABASE_URL | Supabase URL | Same | Supabase project URL |
VITE_SUPABASE_ANON_KEY | Anon Key | Same | Supabase public key |
Hardcoded fallback values meant the app would build and run without env vars set. We configured them explicitly for future environment separation — when a staging backend is added, only the Preview variables need updating.
Step 3: vercel.json Configuration
Set up SPA routing rewrite rules and security headers:
{
"rewrites": [
{ "source": "/((?!api/).*)", "destination": "/index.html" }
],
"headers": [
{
"source": "/(.*)",
"headers": [
{ "key": "X-Frame-Options", "value": "DENY" },
{ "key": "X-Content-Type-Options", "value": "nosniff" }
]
}
]
}
The rewrites rule is essential. In a React Router SPA, direct navigation or refresh on paths like /dashboard or /report/123 returns 404 if no rewrite rule exists — Vercel cannot find a static file at that path. The rewrite redirects all routes to index.html, letting React Router handle client-side routing.
Step 4: Preview Deploy Testing
Vercel automatically creates a Preview deploy at *.vercel.app. Full functional testing was performed in this staging environment.
Test checklist:
- Main page rendering
- Login / signup flow
- Dashboard access and data loading
- Analysis execution (backend API calls)
- Report viewing
- Payment page access
- Deep link direct access (SPA rewrite verification)
- No 404 on page refresh
- OG image loading
- Mobile layout
An OG image issue was discovered at this stage — detailed in the Troubleshooting section.
Step 5: Remove lovable-tagger
npm uninstall lovable-tagger
Then removed the lovable-tagger plugin registration from vite.config.ts. Since it was a devDependency used only for component identification in Lovable’s editor, removal had no runtime impact.
Confirmed npm run build completed successfully after removal.
Step 6: DNS Switch
The most carefully managed step. Changed wichi.app’s CNAME record in Cloudflare from Lovable hosting to Vercel.
sequenceDiagram
participant User as User
participant CF as Cloudflare DNS
participant L as Lovable Hosting
participant V as Vercel
Note over CF: Before: CNAME → Lovable
User->>CF: wichi.app request
CF->>L: CNAME resolves → Lovable
L->>User: Response
Note over CF: Execute CNAME change
CF->>CF: CNAME → Vercel
Note over CF: After: CNAME → Vercel
User->>CF: wichi.app request
CF->>V: CNAME resolves → Vercel
V->>User: Response
Note over CF: DNS propagation: ~1 min with 60s TTL
Execution steps:
- Add custom domain (wichi.app) in Vercel dashboard
- Note the CNAME target address Vercel provides
- Update wichi.app CNAME record to Vercel target in Cloudflare DNS
- Confirm domain verification and automatic SSL certificate issuance in Vercel dashboard
- Verify with
curl -I https://wichi.app(confirm Vercel server headers)
Thanks to pre-lowered TTL (60 seconds), DNS propagation completed in approximately 2 minutes.
Step 7: CORS Update
After DNS switch, update the backend (FastAPI) CORS settings:
| Change | Before | After |
|---|---|---|
| Add allowed domain | — | *.vercel.app (for Preview deploys) |
| Keep allowed domain | wichi.app | wichi.app (unchanged — domain itself did not change) |
| Remove allowed domain | Lovable domain | — |
Since the wichi.app domain itself did not change, production CORS remained unaffected. The only addition needed was *.vercel.app for Vercel Preview deploy URLs, enabling staging API calls from PR-generated preview URLs.
Step 8: Verification
Post-migration verification:
-
https://wichi.appaccessible - SSL certificate valid (Let’s Encrypt, Vercel auto-issued)
- All major pages and features functional
- OG images loading correctly
- Backend API calls working (no CORS issues)
- Google Search Console site access confirmed
- GA4 event collection confirmed
Troubleshooting
OG Image Dependency
Symptom: OG images broken on Preview deploy. URLs shared on social media showed no image preview.
Cause: OG image was hosted on Lovable’s GCP Storage. The HTML <meta property="og:image"> tag referenced a Lovable GCP bucket URL directly.
# Before: Lovable GCP Storage URL
<meta property="og:image" content="https://storage.googleapis.com/lovable-uploads/..." />
Canceling Lovable’s subscription could invalidate this URL. External service dependency for OG images means vulnerability to that service’s outages or policy changes.
Fix: Moved the OG image to the project’s public/ directory.
# After: Self-hosted
<meta property="og:image" content="https://wichi.app/og-image.webp" />
Placing the image in public/og-image.webp makes Vercel serve it as a static asset automatically — no external dependency.
This was missed during pre-migration analysis. Lovable’s GCP Storage dependency is invisible at the code level — it only surfaces by inspecting HTML meta tag URLs one by one.
SPA Rewrite Missing
Symptom: 404 errors on direct URL access or page refresh after Vercel deployment.
Cause: No rewrite rules in vercel.json. Lovable handled SPA hosting rewrites internally, so no explicit configuration existed in the codebase.
Fix: Added SPA rewrite rules to vercel.json — all requests except API paths redirect to index.html.
Environment Variable Fallbacks
Discovery: Hardcoded fallback values existed for environment variables:
const API_URL = import.meta.env.VITE_API_URL || "https://api.wichi.app"
This means Vercel works without explicit env var configuration in production. But it is also a problem: Preview environments call the production API too, breaking staging/production isolation.
Not an immediate issue since no separate staging backend exists yet, but when staging is added, these fallback values must be removed to enforce Vercel environment variable usage.
Before and After Comparison
Deployment Pipeline
flowchart LR
subgraph Before["Before: Lovable"]
direction TB
L1["Edit via prompts in Lovable editor"] --> L2["Lovable builds"]
L2 --> L3["Auto-deploy"]
L4["Edit code via Claude Code"] --> L5["git push"]
L5 --> L6["Not recognized by Lovable"]
L6 --> L7["Manual sync required"]
end
subgraph After["After: Vercel"]
direction TB
V1["Edit code"] --> V2["git push / Create PR"]
V2 --> V3["Vercel auto-build"]
V3 --> V4["Preview Deploy created"]
V4 --> V5["Review then merge"]
V5 --> V6["Production auto-deploy"]
end
During the Lovable era, two tools (Lovable editor + Claude Code) modified code through separate paths with incomplete synchronization. After the Vercel migration, all code changes flow through a single Git-based pipeline.
Feature Comparison
| Feature | Lovable | Vercel |
|---|---|---|
| Deploy trigger | Manual from Lovable editor | git push = auto-deploy |
| PR Preview | Not available | Auto-generated per PR with unique URL |
| Deploy history | Limited visibility in Lovable | Per-commit tracking in dashboard, build log access |
| Rollback | Manual restoration (difficult) | One-click rollback to previous deploy version |
| Env var management | Limited | Production / Preview / Development separation |
| Build config | Internal to Lovable, limited customization | Full control via vercel.json |
| Security headers | Not configurable | Configurable via vercel.json headers |
| CDN | Lovable’s own | Vercel Edge Network (global) |
| Domain SSL | Lovable-managed | Let’s Encrypt auto-issued and renewed |
| Build logs | Hard to access | Real-time build log streaming |
Workflow Comparison
| Scenario | Lovable | Vercel |
|---|---|---|
| UI component edit | Prompt in Lovable editor → manual push | Edit code → PR → Preview verify → merge |
| Deploy error found | Manual fix in Lovable editor, redeploy | Instant rollback in Vercel, then fix |
| New feature development | Hybrid Lovable(main) + Claude Code(dev) | Single tool (Claude Code) on feature branch |
| Env var change | Lovable settings page (limited) | Vercel dashboard, independent per environment |
| Build failure debug | Lovable internal error (limited info) | Full error stack in Vercel build logs |
The most impactful change: PR = Preview Deploy. Verifying code changes in a real deployment environment before merging is a safety net that prevents mistakes even in solo development. Vercel’s Preview Deploy runs in an environment identical to production, catching environment-related issues before they reach users.
Migration Checklist
A comprehensive checklist generalized for similar migrations.
Pre-Migration
- Full source code in GitHub, buildable externally
- Platform-specific dependency list identified (
lovable-tagger, etc.) - Environment variable inventory complete
- Current DNS configuration verified (CNAME target, TTL)
- Rollback plan established
Execution
- Connect repo to Vercel, configure basics
- Set environment variables (per-environment separation)
- Write
vercel.json(rewrites, headers) - Full test on Preview deploy
- Remove platform-specific dependencies (
lovable-tagger) - Migrate OG image to local hosting
- Pre-lower DNS TTL (60 seconds)
- Switch DNS CNAME (Cloudflare → Vercel)
- Confirm SSL certificate issuance
Post-Migration
- Update backend CORS settings
- Full production test
- Verify GA4 event collection
- Verify Search Console access
- Update README deployment docs
- Cancel previous platform subscription
Issue Log
| Timing | Issue | Severity | Resolution | Time Spent |
|---|---|---|---|---|
| Preview test | OG image broken | Medium | Moved image to local public/ | 15 min |
| Preview test | Deep link 404 | High | Added vercel.json rewrite rules | 10 min |
| Post-DNS switch | SSL certificate pending | Low | Vercel auto-issued, ~1 min wait | 1 min |
| Post-migration | CORS error on Preview deploys | Medium | Added *.vercel.app to backend | 5 min |
Time Spent
The entire migration took roughly half a day.
| Task | Duration |
|---|---|
| Vercel project setup + env vars | 15 min |
vercel.json configuration | 10 min |
| Preview deploy testing | 30 min |
lovable-tagger removal + build verification | 10 min |
| OG image migration | 15 min |
| DNS switch + propagation wait | 15 min |
| CORS update | 5 min |
| Production verification | 30 min |
| Documentation update | 20 min |
| Total | ~2.5 hours |
Testing and verification consumed the most time. Actual code changes were minimal — mostly configuration file edits and external service updates (DNS, CORS). DNS propagation was fast thanks to the pre-lowered TTL.
Retrospective
When Lovable Is Still the Right Tool
Leaving Lovable does not mean Lovable is a bad tool. Tools serve their intended purposes.
| Scenario | Lovable Fit | Reason |
|---|---|---|
| Hackathon / Prototyping | High | Prompt-to-UI speed is unmatched. Optimal for building a working frontend in 3 days |
| Design exploration | High | Rapidly try and compare multiple UI variations |
| Non-developer MVP creation | High | Build a deployable frontend without writing code |
| Production hosting | Low | Limitations in deploy control, env separation, rollback, PR Preview |
| Long-term maintenance | Low | No Git-first workflow, platform-specific dependencies |
For WICHI, Lovable provided clear value in the “0 to 1” phase. Building the first frontend version during a 3-day hackathon would have been much harder without it.
When to Graduate from No-Code/Low-Code Platforms
General criteria for transitioning from no-code/low-code platforms to traditional hosting — not Lovable-specific:
If 3 or more of the following apply, it is time to evaluate migration:
- PR-based code review is needed — team of 2+ or solo developer who needs change history tracking
- Direct deployment configuration control is needed — redirects, security headers, cache policies, env var separation
- Rollback capability is needed — ability to instantly revert to a previous version when post-deploy issues arise
- Platform cost is unreasonable compared to alternatives — free or low-cost hosting provides equivalent functionality
- Platform-specific dependencies are accumulating — proprietary SDKs, plugins, and config code growing in the codebase
- Integration with other tools is needed — CI/CD, monitoring, A/B testing, external service connectivity
Lessons Learned
Acknowledge the limits of pre-migration analysis. The OG image’s Lovable GCP dependency was missed during planning. Code-level dependencies are findable by searching package.json and import statements, but implicit dependencies like external URLs embedded in HTML meta tags or CDN paths are easily overlooked.
Zero downtime is unrealistic, but minimization is achievable. True zero downtime is virtually impossible in DNS-involving migrations. But pre-lowering TTL, pre-validating staging, and having a rollback plan can reduce downtime to minutes.
Platform transitions are cheaper when done early. Platform-specific dependencies accumulate over time. When migration becomes necessary, acting quickly minimizes cost. WICHI’s Lovable dependencies were limited to lovable-tagger and an OG image URL — enabling completion in half a day. Had dependencies deepened further, it would have taken much longer.
How Daily Work Changed After Migration
| Task | Before | After |
|---|---|---|
| Component edit | Lovable editor → prompt → push | Edit code → PR → Preview verify → merge |
| Deploy | Manual trigger in Lovable editor | git push = automatic. No extra steps |
| Deploy failure | Check Lovable error message (limited info) | Full error stack in Vercel build logs |
| Emergency rollback | Manual restoration (time-consuming) | Select previous deploy in Vercel dashboard → instant rollback |
| New feature verification | Local testing only | Preview URL on PR creation for real-environment verification |
PR Preview is valuable even for solo development. It catches “works locally but breaks in deployment” issues before merge. Vercel’s Preview Deploy runs in a production-identical environment, surfacing environment-related problems early.
Related Posts
After Hackathon Rejection — Pivoting to Independent SaaS
Recording the 24-hour pivot of WICHI to an independent SaaS after a hackathon rejection, covering i18n implementation, SEO setup, and monetization roadmap restructuring.
Solo SaaS Security — The Minimum You Must Do
Essential security checklist for solo SaaS builders. Defense against five critical OWASP Top 10 vulnerabilities and real-world security configuration cases improved for WICHI.
Build, Document, Share
Personal execution notes from a non-tech builder who started with AI FOMO and is now navigating the messy reality of production beyond the initial 'one-click' hype.