| .forgejo/workflows | ||
| README.md | ||
Vercel Deploy Workflow @ v1
A reusable Forgejo workflow for deploying projects to Vercel. Routes pushes to a production branch to the live site and pushes to a preview branch to a preview environment.
Features
- Separate production and preview deployments based on branch
- Builds run on your Forgejo runner (build logs stay in Forgejo, not Vercel)
- Bun and Node.js both available in the build environment
- Configurable runtime versions, branch names, and runner label
Prerequisites
- Forgejo v7 or later (reusable workflow support)
- A registered Forgejo runner with the
ubuntu-latestlabel (or override via theruns_oninput) - A Vercel project that is not connected to any Git integration
- Vercel API token, org ID, and project ID
Disconnecting Vercel from Git
If your project was previously deployed via Vercel's GitHub integration, disconnect it first to avoid duplicate deploys:
Vercel dashboard → Project → Settings → Git → Disconnect.
The project and its environment variables stay; only the auto-deploy hook is removed.
Obtaining credentials
Token: Vercel dashboard → Account Settings → Tokens → Create. Scope it to the team that owns the project.
Org ID and Project ID: Run npx vercel link once locally inside the repo. It creates .vercel/project.json containing both IDs. Copy the values, then delete the folder or verify it's in .gitignore.
Vercel's "team ID" and "org ID" refer to the same value — use whichever name your tooling expects.
Configuring a preview domain (optional)
Vercel's per-branch domain assignment requires their Git integration, which only supports GitHub/GitLab/BitBucket — so it doesn't work for Forgejo-driven deploys. Instead, this workflow aliases each preview deployment itself.
Add the subdomain in Vercel project Settings → Domains (without attaching it to a branch), then pass it to the workflow via the preview_domain input. After every preview deploy, the workflow runs vercel alias set to point the domain at the new deployment.
Usage
Add .forgejo/workflows/deploy.yml to your repo:
name: Deploy
on:
push:
branches: [main, preview]
jobs:
deploy:
uses: you/vercel-deploy-workflow/.forgejo/workflows/deploy.yml@v1
secrets: inherit
Replace you/vercel-deploy-workflow with the actual path to this repo on your Forgejo instance. Add the three secrets via repo Settings → Actions → Secrets, or at the organization level if multiple repos will use this workflow.
secrets: inherit is required rather than per-secret declarations because Forgejo's runner does not yet implement the workflow_call.secrets key (tracked in forgejo#6069). On the upside, this means adding a fourth secret to the workflow later won't require updating any consumers.
With custom branch names
jobs:
deploy:
uses: you/vercel-deploy-workflow/.forgejo/workflows/deploy.yml@v1
with:
production_branch: production
preview_branch: staging
secrets: inherit
Make sure the on: push: branches: list in the caller matches the branches you've configured.
With a preview domain alias
jobs:
deploy:
uses: you/vercel-deploy-workflow/.forgejo/workflows/deploy.yml@v1
with:
preview_domain: preview.example.com
secrets: inherit
Inputs
| Input | Type | Default | Description |
|---|---|---|---|
production_branch |
string | main |
Branch that triggers production deploys |
preview_branch |
string | preview |
Branch that triggers preview deploys |
preview_domain |
string | "" |
Custom domain to alias to each preview deploy. Leave empty to skip aliasing. |
node_version |
string | "24" |
Node.js version |
bun_version |
string | latest |
Bun version |
runs_on |
string | ubuntu-latest |
Runner label |
Secrets
These must be defined at the repo or org level on your Forgejo instance. The reusable workflow doesn't pre-declare them (see the note in Usage), so missing secrets surface as auth errors at the first vercel command rather than as workflow validation errors.
| Secret | Required | Description |
|---|---|---|
VERCEL_TOKEN |
yes | Vercel API token |
VERCEL_ORG_ID |
yes | Vercel team/org ID |
VERCEL_PROJECT_ID |
yes | Vercel project ID |
Notes
GITHUB_API_URL override
The Pull and Build steps explicitly set GITHUB_API_URL and GITHUB_SERVER_URL to GitHub's real URLs. Forgejo runners default these to the Forgejo instance, and Bun reads GITHUB_API_URL to fetch tarballs for any github.com dependency. Without the override, bun install routes through the Forgejo API and 404s on every GitHub-hosted dependency.
Pinned action SHAs
Actions are pinned to commit SHAs from code.forgejo.org, the Forgejo mirror. If your runner is configured to resolve actions from a different source (e.g. github.com directly), you'll need to use SHAs from that source instead. setup-bun is referenced via its full GitHub URL because it isn't mirrored on code.forgejo.org.
To refresh a pin:
git ls-remote https://code.forgejo.org/actions/checkout refs/tags/v4
git ls-remote https://code.forgejo.org/actions/setup-node refs/tags/v4
git ls-remote https://github.com/oven-sh/setup-bun refs/tags/v2
Versioning this workflow
Consumers pin to a ref via @v1, @v1.2.0, or a full commit SHA. The recommended convention:
- Cut tags
v1.0.0,v1.1.0, etc. for releases - Maintain a floating
v1tag pointing at the latest 1.x release for consumers who want minor updates automatically - Bump the major version (
v2) for any breaking change to inputs or behavior
This mirrors how actions/checkout and similar first-party actions handle versioning.