{"id":"0091437e-560a-4b02-994d-6a7744695933","shortId":"YRK7HV","kind":"skill","title":"lovstudio:deploy-to-vercel","tagline":"Deploy frontend projects to Vercel with automatic custom domain setup. Handles Vite, Next.js, CRA, and static sites. Auto-configures Cloudflare DNS CNAME records and Vercel domain aliases. Supports SPA routing via vercel.json. Trigger when user says \"deploy to vercel\", \"部署到 verce","description":"# deploy-vercel — One-Command Frontend Deployment\n\nDeploy frontend projects to Vercel with automatic custom domain and DNS setup.\n\n## When to Use\n\n- User says \"deploy to vercel\" or \"部署到 xxx.lovstudio.ai\"\n- After building a frontend project that needs hosting\n- When setting up a custom domain on an existing Vercel deployment\n\n## Arguments\n\nPass via `$ARGUMENTS`:\n\n| Argument | Example | Description |\n|----------|---------|-------------|\n| `<domain>` | `sbti.lovstudio.ai` | Custom domain to configure |\n| `--preview` | | Deploy preview only (skip `--prod`) |\n| `--no-dns` | | Skip Cloudflare DNS auto-config |\n| `--link-only` | | Only link project, don't deploy |\n\n## Workflow\n\n### Step 1: Detect Project Type\n\n```bash\nif [ -f \"vite.config.ts\" ] || [ -f \"vite.config.js\" ]; then\n  FRAMEWORK=\"vite\"\nelif [ -f \"next.config.js\" ] || [ -f \"next.config.mjs\" ]; then\n  FRAMEWORK=\"next\"\nelif grep -q \"react-scripts\" package.json 2>/dev/null; then\n  FRAMEWORK=\"cra\"\nelse\n  FRAMEWORK=\"static\"\nfi\n```\n\n### Step 2: Ensure vercel.json for SPA\n\nFor Vite/CRA (SPA) projects, create `vercel.json` if missing:\n\n```json\n{\n  \"rewrites\": [\n    { \"source\": \"/(.*)\", \"destination\": \"/\" }\n  ]\n}\n```\n\n**Skip for Next.js** — it handles routing natively.\n\n### Step 3: Deploy to Vercel\n\n```bash\n# Check CLI\nvercel --version || npm i -g vercel\n\n# Deploy (use project name from package.json \"name\" field)\n# IMPORTANT: package.json \"name\" must be lowercase, no special chars\nPROJECT_NAME=$(node -p \"require('./package.json').name\" 2>/dev/null || basename \"$PWD\")\nvercel --yes --prod\n```\n\n**Known issue**: If `package.json` name contains uppercase or invalid chars,\nvercel will error with \"Project names must be lowercase\". Fix the name first.\n\n### Step 4: Configure Custom Domain (if provided)\n\n```bash\nDOMAIN=\"<user-provided-domain>\"  # e.g. sbti.lovstudio.ai\n\n# 1. Add domain to Vercel project\nvercel domains add \"$DOMAIN\"\n\n# 2. Set alias to point domain to latest deployment\nPROD_URL=$(vercel ls --prod 2>&1 | grep -oE 'https://[^ ]+\\.vercel\\.app' | head -1)\nvercel alias set \"$PROD_URL\" \"$DOMAIN\"\n```\n\n**CRITICAL**: `vercel domains add` alone is NOT enough. You MUST also run\n`vercel alias set` to actually route traffic. Without it, the domain returns\nERR_CONNECTION_CLOSED.\n\n### Step 5: Auto-Configure Cloudflare DNS\n\n**Requires**: `CLOUDFLARE_API_KEY` env var (API Token with DNS edit permission).\n\n```bash\n# Extract base domain and subdomain\n# e.g. \"sbti.lovstudio.ai\" → base=\"lovstudio.ai\", sub=\"sbti\"\nBASE_DOMAIN=$(echo \"$DOMAIN\" | awk -F. '{print $(NF-1)\".\"$NF}')\nSUBDOMAIN=$(echo \"$DOMAIN\" | sed \"s/\\.$BASE_DOMAIN$//\")\n\n# 1. Get zone ID\nZONE_ID=$(curl -s \"https://api.cloudflare.com/client/v4/zones?name=$BASE_DOMAIN\" \\\n  -H \"Authorization: Bearer $CLOUDFLARE_API_KEY\" \\\n  -H \"Content-Type: application/json\" | python3 -c \"import sys,json; print(json.load(sys.stdin)['result'][0]['id'])\")\n\n# 2. Check if record already exists\nEXISTING=$(curl -s \"https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records?name=$DOMAIN&type=CNAME\" \\\n  -H \"Authorization: Bearer $CLOUDFLARE_API_KEY\" | python3 -c \"import sys,json; r=json.load(sys.stdin)['result']; print(r[0]['id'] if r else '')\")\n\n# 3. Create or update CNAME → cname.vercel-dns.com\nif [ -z \"$EXISTING\" ]; then\n  curl -s -X POST \"https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records\" \\\n    -H \"Authorization: Bearer $CLOUDFLARE_API_KEY\" \\\n    -H \"Content-Type: application/json\" \\\n    --data \"{\\\"type\\\":\\\"CNAME\\\",\\\"name\\\":\\\"$SUBDOMAIN\\\",\\\"content\\\":\\\"cname.vercel-dns.com\\\",\\\"ttl\\\":1,\\\"proxied\\\":false}\"\nelse\n  curl -s -X PUT \"https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/$EXISTING\" \\\n    -H \"Authorization: Bearer $CLOUDFLARE_API_KEY\" \\\n    -H \"Content-Type: application/json\" \\\n    --data \"{\\\"type\\\":\\\"CNAME\\\",\\\"name\\\":\\\"$SUBDOMAIN\\\",\\\"content\\\":\\\"cname.vercel-dns.com\\\",\\\"ttl\\\":1,\\\"proxied\\\":false}\"\nfi\n```\n\n**IMPORTANT**: `proxied` must be `false` (DNS only). Cloudflare proxy conflicts\nwith Vercel's SSL certificate provisioning.\n\nIf `CLOUDFLARE_API_KEY` is not set, print manual DNS instructions instead:\n```\nAdd DNS record:\n  Type: CNAME\n  Name: <subdomain>\n  Target: cname.vercel-dns.com\n  Proxy: OFF (DNS only)\n```\n\n### Step 6: Verify\n\n```bash\n# Wait for DNS + SSL propagation\nsleep 5\nHTTP_CODE=$(curl -sI \"https://$DOMAIN\" -o /dev/null -w '%{http_code}')\nif [ \"$HTTP_CODE\" = \"200\" ]; then\n  echo \"✓ $DOMAIN is live\"\nelse\n  echo \"⚠ HTTP $HTTP_CODE — SSL may still be provisioning, try again in 1-2 min\"\nfi\n```\n\n### Step 7: Output Summary\n\n```\n✓ Framework: vite\n✓ Deployed: https://xxx.vercel.app\n✓ Domain: https://sbti.lovstudio.ai\n✓ DNS: CNAME sbti → cname.vercel-dns.com (Cloudflare)\n✓ Settings: https://vercel.com/<scope>/<project>/settings\n```\n\n## Troubleshooting\n\n| Problem | Cause | Fix |\n|---------|-------|-----|\n| ERR_CONNECTION_CLOSED | Domain added but no alias set | Run `vercel alias set <url> <domain>` |\n| \"Project names must be lowercase\" | package.json name invalid | Fix name field |\n| SSL not provisioning | Cloudflare proxy ON | Set DNS to \"DNS only\" (no orange cloud) |\n| 404 on sub-routes | SPA missing rewrites | Add vercel.json with rewrites |\n| DNS resolves to 198.18.x.x | Local proxy (Clash etc.) | Normal — check with `dig @8.8.8.8` |\n| `CLOUDFLARE_API_KEY` not found | Token not in env | Add to `~/.zshrc`: `export CLOUDFLARE_API_KEY=...` |","tags":["deploy","vercel","skills","lovstudio","agent-skills","ai-coding-assistant","cjk","claude-code","cursor","gemini-cli","markdown-to-docx","markdown-to-pdf"],"capabilities":["skill","source-lovstudio","skill-deploy-to-vercel","topic-agent-skills","topic-ai-coding-assistant","topic-cjk","topic-claude-code","topic-cursor","topic-gemini-cli","topic-markdown-to-docx","topic-markdown-to-pdf"],"categories":["skills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/lovstudio/skills/deploy-to-vercel","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add lovstudio/skills","source_repo":"https://github.com/lovstudio/skills","install_from":"skills.sh"}},"qualityScore":"0.469","qualityRationale":"deterministic score 0.47 from registry signals: · indexed on github topic:agent-skills · 39 github stars · SKILL.md body (5,346 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-04-21T01:36:38.802Z","embedding":null,"createdAt":"2026-04-18T22:18:54.306Z","updatedAt":"2026-04-21T01:36:38.802Z","lastSeenAt":"2026-04-21T01:36:38.802Z","tsv":"'-1':308,381 '-2':611 '/.zshrc':711 '/client/v4/zones/$zone_id/dns_records':473 '/client/v4/zones/$zone_id/dns_records/$existing':503 '/client/v4/zones/$zone_id/dns_records?name=$domain&type=cname':434 '/client/v4/zones?name=$base_domain':400 '/dev/null':165,237,584 '/package.json':234 '/settings':631 '0':421,452 '1':136,277,302,390,493,523,610 '198.18':689 '2':164,174,236,287,301,423 '200':591 '3':199,457 '4':267 '404':674 '5':343,577 '6':568 '7':615 '8.8.8.8':699 'actual':331 'ad':640 'add':278,285,318,555,682,709 'alia':289,310,328,643,647 'alias':33 'alon':319 'alreadi':427 'also':325 'api':351,355,405,439,478,508,545,701,714 'api.cloudflare.com':399,433,472,502 'api.cloudflare.com/client/v4/zones/$zone_id/dns_records':471 'api.cloudflare.com/client/v4/zones/$zone_id/dns_records/$existing':501 'api.cloudflare.com/client/v4/zones/$zone_id/dns_records?name=$domain&type=cname':432 'api.cloudflare.com/client/v4/zones?name=$base_domain':398 'app':306 'application/json':411,484,514 'argument':98,101,102 'author':402,436,475,505 'auto':24,123,345 'auto-config':122 'auto-configur':23,344 'automat':12,62 'awk':377 'base':363,369,373,388 'basenam':238 'bash':140,203,273,361,570 'bearer':403,437,476,506 'build':80 'c':413,442 'caus':634 'certif':541 'char':228,252 'check':204,424,696 'clash':693 'cli':205 'close':341,638 'cloud':673 'cloudflar':26,120,347,350,404,438,477,507,534,544,628,663,700,713 'cname':28,461,487,517,559,625 'cname.vercel-dns.com':462,491,521,562,627 'code':579,587,590,601 'command':53 'config':124 'configur':25,109,268,346 'conflict':536 'connect':340,637 'contain':248 'content':409,482,490,512,520 'content-typ':408,481,511 'cra':19,168 'creat':183,458 'critic':315 'curl':396,430,467,497,580 'custom':13,63,91,106,269 'data':485,515 'deploy':3,6,43,49,55,56,73,97,111,133,200,212,295,620 'deploy-to-vercel':2 'deploy-vercel':48 'descript':104 'destin':190 'detect':137 'dig':698 'dns':27,66,118,121,348,358,532,552,556,565,573,624,667,669,686 'domain':14,32,64,92,107,270,274,279,284,286,292,314,317,337,364,374,376,385,389,582,594,622,639 'e.g':275,367 'echo':375,384,593,598 'edit':359 'elif':149,157 'els':169,456,496,597 'enough':322 'ensur':175 'env':353,708 'err':339,636 'error':255 'etc':694 'exampl':103 'exist':95,428,429,465 'export':712 'extract':362 'f':142,144,150,152,378 'fals':495,525,531 'fi':172,526,613 'field':219,659 'first':265 'fix':262,635,657 'found':704 'framework':147,155,167,170,618 'frontend':7,54,57,82 'g':210 'get':391 'grep':158,303 'h':401,407,435,474,480,504,510 'handl':16,195 'head':307 'host':86 'http':578,586,589,599,600 'id':393,395,422,453 'import':220,414,443,527 'instead':554 'instruct':553 'invalid':251,656 'issu':244 'json':187,416,445 'json.load':418,447 'key':352,406,440,479,509,546,702,715 'known':243 'latest':294 'link':126,129 'link-on':125 'live':596 'local':691 'lovstudio':1 'lovstudio.ai':370 'lowercas':225,261,653 'ls':299 'manual':551 'may':603 'min':612 'miss':186,680 'must':223,259,324,529,651 'name':215,218,222,230,235,247,258,264,488,518,560,650,655,658 'nativ':197 'need':85 'next':156 'next.config.js':151 'next.config.mjs':153 'next.js':18,193 'nf':380,382 'no-dn':116 'node':231 'normal':695 'npm':208 'o':583 'oe':304 'one':52 'one-command':51 'orang':672 'output':616 'p':232 'package.json':163,217,221,246,654 'pass':99 'permiss':360 'point':291 'post':470 'preview':110,112 'print':379,417,450,550 'problem':633 'prod':115,242,296,300,312 'project':8,58,83,130,138,182,214,229,257,282,649 'propag':575 'provid':272 'provis':542,606,662 'proxi':494,524,528,535,563,664,692 'put':500 'pwd':239 'python3':412,441 'q':159 'r':446,451,455 'react':161 'react-script':160 'record':29,426,557 'requir':233,349 'resolv':687 'result':420,449 'return':338 'rewrit':188,681,685 'rout':36,196,332,678 'run':326,645 'say':42,72 'sbti':372,626 'sbti.lovstudio.ai':105,276,368,623 'script':162 'sed':386 'set':88,288,311,329,549,629,644,648,666 'setup':15,67 'si':581 'site':22 'skill' 'skill-deploy-to-vercel' 'skip':114,119,191 'sleep':576 'sourc':189 'source-lovstudio' 'spa':35,178,181,679 'special':227 'ssl':540,574,602,660 'static':21,171 'step':135,173,198,266,342,567,614 'still':604 'sub':371,677 'sub-rout':676 'subdomain':366,383,489,519 'summari':617 'support':34 'sys':415,444 'sys.stdin':419,448 'target':561 'token':356,705 'topic-agent-skills' 'topic-ai-coding-assistant' 'topic-cjk' 'topic-claude-code' 'topic-cursor' 'topic-gemini-cli' 'topic-markdown-to-docx' 'topic-markdown-to-pdf' 'traffic':333 'tri':607 'trigger':39 'troubleshoot':632 'ttl':492,522 'type':139,410,483,486,513,516,558 'updat':460 'uppercas':249 'url':297,313 'use':70,213 'user':41,71 'var':354 'verc':47 'vercel':5,10,31,45,50,60,75,96,202,206,211,240,253,281,283,298,305,309,316,327,538,646 'vercel.com':630 'vercel.json':38,176,184,683 'verifi':569 'version':207 'via':37,100 'vite':17,148,619 'vite.config.js':145 'vite.config.ts':143 'vite/cra':180 'w':585 'wait':571 'without':334 'workflow':134 'x':469,499 'x.x':690 'xxx.lovstudio.ai':78 'xxx.vercel.app':621 'yes':241 'z':464 'zone':392,394 '部署到':46,77","prices":[{"id":"55d8848e-0517-45c7-bee1-5d3acaef0d64","listingId":"0091437e-560a-4b02-994d-6a7744695933","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"lovstudio","category":"skills","install_from":"skills.sh"},"createdAt":"2026-04-18T22:18:54.306Z"}],"sources":[{"listingId":"0091437e-560a-4b02-994d-6a7744695933","source":"github","sourceId":"lovstudio/skills/deploy-to-vercel","sourceUrl":"https://github.com/lovstudio/skills/tree/main/skills/deploy-to-vercel","isPrimary":false,"firstSeenAt":"2026-04-18T22:18:54.306Z","lastSeenAt":"2026-04-21T01:36:38.802Z"}],"details":{"listingId":"0091437e-560a-4b02-994d-6a7744695933","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"lovstudio","slug":"deploy-to-vercel","github":{"repo":"lovstudio/skills","stars":39,"topics":["agent-skills","ai-coding-assistant","cjk","claude-code","cursor","gemini-cli","markdown-to-docx","markdown-to-pdf"],"license":"mit","html_url":"https://github.com/lovstudio/skills","pushed_at":"2026-04-20T21:40:57Z","description":"Agent skills for AI coding assistants — Markdown to PDF/DOCX with 14 themes, CJK support","skill_md_sha":"05ae408548235c745d7bba2e83d9c19937f75bc0","skill_md_path":"skills/deploy-to-vercel/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/lovstudio/skills/tree/main/skills/deploy-to-vercel"},"layout":"multi","source":"github","category":"skills","frontmatter":{"name":"lovstudio:deploy-to-vercel","license":"MIT","description":"Deploy frontend projects to Vercel with automatic custom domain setup. Handles Vite, Next.js, CRA, and static sites. Auto-configures Cloudflare DNS CNAME records and Vercel domain aliases. Supports SPA routing via vercel.json. Trigger when user says \"deploy to vercel\", \"部署到 vercel\", \"vercel deploy\", or mentions a *.lovstudio.ai / custom domain with vercel deployment.","compatibility":"Requires vercel CLI (`npm i -g vercel`), gh CLI, and curl. Cloudflare DNS auto-config requires CLOUDFLARE_API_KEY env var."},"skills_sh_url":"https://skills.sh/lovstudio/skills/deploy-to-vercel"},"updatedAt":"2026-04-21T01:36:38.802Z"}}