/sc-vercel — Vercel (online frontend)
Status: implemented (online path).
flowchart TD
A["/sc-vercel"] --> B["find/create Vercel project<br/>(bound to GitHub repo)"]
B --> C["set CONVEX_DEPLOY_KEY (encrypted)"]
C --> D["set coupled build cmd<br/>npx convex deploy --cmd 'npm run build'"]
D --> E["add custom domain / subdomain"]
E --> F["read required DNS from Vercel<br/>(array-normalized + IPv4 guard)"]
F --> G["Hostinger DNS<br/>CNAME (sub) / A (apex)"]
G --> H["trigger deploy + poll readyState<br/>(15-min cap, blip-tolerant)"]
H --> I["live URL ✅<br/>NEXT_PUBLIC_CONVEX_URL injected at build"]
Connection-safe local execution
When VERCEL_TOKEN is stored in a direct SI-Coder named connection, run this skill's credential-dependent helper through sc run -- ...:
sc run -- node skills/sc-vercel/scripts/deploy.js --help
The plain node ... examples below are script-interface examples for callers that already supply the required environment. A Composio/native-MCP Vercel connection must execute through that external backend.
When to use
- You want Vercel's edge network for the Next.js frontend, with the Convex backend on Convex Cloud (managed).
- You don't want to deal with a Dockerfile / Compose for the frontend.
- The online counterpart to the self-hosted Dokploy path. Pair with
/sc-convex-cloudfor the backend.
Scope (implemented)
scripts/deploy.js is a single 12-step orchestrator:
- Build a team-aware Vercel client from
VERCEL_TOKEN(+ optionalVERCEL_TEAM_ID). - Resolve the GitHub repo:
--git-owner/--git-repo, else readoriginfrom the local git remote. findOrCreateProject({ name, gitRepo, framework:'nextjs' })— bind the repo on create.- Set env vars:
CONVEX_DEPLOY_KEY(type:'encrypted', Production only — it's a prod key). Do not setNEXT_PUBLIC_CONVEX_URL(injected by the build). - Resolve the build command without overriding the repo: explicit
--build-command→ repovercel.json→ Bun/npm-aware Convex fallback. This lets repositories can keep their own gatedbun run build:autocontract. - Add the custom domain/subdomain (tolerate 409 already-assigned).
- Read the exact required DNS from Vercel's domain config.
- Configure Hostinger DNS (TXT ownership challenge first if unverified, then the A/CNAME pointing record), or print the records to add manually if no
HOSTINGER_API_TOKEN. - Trigger the first deploy (git-linked projects auto-deploy on push; force the initial one).
- Poll
getDeploymentevery 4s untilreadyState ∈ {READY, ERROR, CANCELED}. - Soft-poll DNS propagation (
misconfigured === false) up to ~60s — never hard-fail (cert/record can lag). - Print summary: project id, deployment URL, custom domain, DNS record applied, Convex Cloud URL.
Env vars
| Var | Required | Purpose |
|---|---|---|
VERCEL_TOKEN |
yes | Personal access token, https://vercel.com/account/tokens |
VERCEL_TEAM_ID |
optional | For team-scoped projects; appended as ?teamId= to every API call |
CONVEX_DEPLOY_KEY |
yes | Convex Cloud production deploy key. Set on Vercel as encrypted, Production-only. NEVER logged |
HOSTINGER_API_TOKEN |
optional | Enables automatic DNS record writes. Without it, the records are printed for manual entry |
Build command
Resolution order is authoritative and package-manager-aware:
--build-command <cmd>when an operator explicitly supplies one.vercel.json→buildCommandfor the normal coupled path. A repository that already owns its gate/deploy orchestration must not be replaced by a generic npm command.- Generated fallback: Bun repos use
bunx convex deploy --cmd 'bun run build'; npm repos usenpx convex deploy --cmd 'npm run build'. Both include--cmd-url-env-var-name NEXT_PUBLIC_CONVEX_URL.
--decoupled deliberately bypasses a potentially coupled vercel.json command and runs only the package-manager-native frontend build.
Mandate: do NOT also hand-set NEXT_PUBLIC_CONVEX_URL in Vercel for the same coupled env — the repository command or --cmd injection is the single source of truth. The NEXT_PUBLIC_ prefix is required because Next.js does not expose the default CONVEX_URL to the browser.
DNS logic
Read live from Vercel's domain config; do not hardcode:
- Subdomain (e.g.
app.example.com) →CNAMEtorecommendedCNAME[0].value(fallbackcname.vercel-dns.com). - Apex (e.g.
example.com) →Ato the first IP ofrecommendedIPv4[rank=1].value(an array; pickvalue[0], fallback76.76.21.21). - TXT ownership challenge from
verification[]when the domain reportsverified:false— added first, thenverifyDomainis called.
CONVEX_DEPLOY_KEY is a secret: passed via env to the Vercel encrypted env, and never echoed by any script. Only NEXT_PUBLIC_CONVEX_URL (public) is printed.
Scripts
node skills/sc-vercel/scripts/deploy.js \
--project myapp --app myapp --domain app.example.com \
--git-owner <your-gh-user> --git-repo myapp --prod
| Flag | Meaning |
|---|---|
--project <name> |
Vercel project name (defaults to --app if omitted) |
--app <name> |
Logical app name (defaults to --project) |
--domain <host> |
Full host to attach — apex example.com OR subdomain app.example.com |
--git-owner <o> / --git-repo <r> |
GitHub owner/name; if absent, read from git remote get-url origin |
--ref <branch> / --branch <branch> |
Git ref/branch to deploy; if absent, derived from git rev-parse --abbrev-ref HEAD, else main (use this for master-default repos) |
--prod |
Deploy the production target / alias |
--decoupled |
Opt-out of coupled build: set NEXT_PUBLIC_CONVEX_URL from env and run only the frontend build |
--build-command <cmd> |
Explicit project build command; otherwise repo vercel.json then Bun/npm fallback wins |
--cwd <path> |
Working dir for git-remote and build-contract resolution (default: process cwd) |
File layout
sc-vercel/
├── SKILL.md
└── scripts/
├── _shared.js # getClient (VERCEL_TOKEN/VERCEL_TEAM_ID) + parseArgs
└── deploy.js # 12-step orchestrator (project + env + build + domain + DNS + deploy)
Note: the old "suggested file layout" with separate
project.js/env.js/domain.jsis superseded — project/env/domain/deploy are consolidated intodeploy.json top of thelib/vercel.jsclient.
Implementation notes
- API base:
https://api.vercel.com; authAuthorization: Bearer <VERCEL_TOKEN>; team projects append?teamId=<VERCEL_TEAM_ID>to every URL. - A git-linked project only auto-deploys if the Vercel GitHub App is installed on the repo/org.
deploy.jscannot install it headlessly; atriggerDeploy403 surfaces a clear hint to install the App. - Cross-skill:
/sc-all --target vercelskips the Dokploy app + self-hosted Convex; it uses/sc-convex-cloud+/sc-vercelinstead.