Configuring GitHub for a Vercel Site
How I configured the GitHub repository behind this site: a pull-request gate, checks in a CI workflow, Dependabot, and switching off the features I do not use.
On this page
My last post covered how this site is built and hosted: GitHub for source control, Vercel for building and hosting, and a pull request between the two. This post goes into the GitHub half - how the repository itself is configured, and why. Most of my delivery work has been in Azure DevOps, so rather than start from a blank page, I took the practices I would use on a client's project and found their equivalents in GitHub. This post walks through them in the order a change meets them: the branches, the checks, the dependency updates, and the features I switched off.
Translating from Azure DevOps
In Azure DevOps I would protect a branch with policies, require a pull request with a passing build before anything merged, and turn off the parts of a project the team did not use. GitHub offers the same capabilities under different names, but on a private repository on the free plan, some of them are only available if you pay. Where GitHub did not offer a free equivalent, I got the same result another way: in the CI workflow, with an open-source tool, or in my own process.
Two branches and a pull-request gate
The repository uses the two-branch model from the last post: main deploys to production, and preview deploys to the staging site at uat.cbchalmers.com. I commit and push to preview, Vercel rebuilds the staging site, and I review the change there as a visitor would see it. When I am happy with it, I open a pull request from preview to main. The pull request runs the CI checks, and I merge it once they pass - the same rule I would set for any team, with a team of one.
There is one limitation. On a private repository on the free plan, GitHub does not offer branch protection or required status checks, so nothing on the platform stops a merge while a check is failing. Waiting for the checks to pass is my own discipline. The pull request still shows the full change, the checks still run and report on it, and the history is still kept. If the repository becomes public or moves to a paid plan, enforcing the rule is a settings change rather than a rework.
Checks in a CI workflow
Vercel builds the site on every push, and its build runs the typecheck and lint as a side effect. A vulnerable dependency, a committed secret, or badly formatted code would still deploy. A GitHub Actions workflow adds the checks Vercel does not, as three independent jobs, so each one appears as its own line on the pull request and a failure is easy to identify: a dependency audit that fails on high or critical advisories in the packages the site runs on, a secret scan across the whole git history, and the typecheck, lint, and format checks. The workflow runs on pull requests only. main changes only by merging preview, so running it again after the merge would repeat checks that have already passed.
The secret scan is a good example. GitHub's own secret scanning is part of its paid security product, so the workflow instead runs gitleaks, an open-source scanner, pinned to a version and scanning the whole git history.
A separate workflow runs a wider audit, and it is the counterpart to the dependency audit among the checks above. That one is deliberately narrow: production dependencies only, high or critical severity, and it blocks the merge. This one is the opposite - the whole dependency tree, build tools included, down to moderate severity - and on a pull request it only reports, so a minor issue in a build tool does not hold up unrelated work. It also runs every Monday, where it does block, so an advisory published between pull requests still reaches me.
Configuring Dependabot
Dependabot keeps the dependencies current, and it is really two features that are easy to treat as one. Version updates are the routine track: they run on a schedule I set and open pull requests against preview, following the same path as any other change. Security updates are the urgent track: they fire when an advisory is published against a package the site uses, and GitHub always opens them against main, whatever dependabot.yml says. The rest of this section takes them in turn.
Version updates are set up in a dependabot.yml file and run weekly. I began with monthly, which seemed enough for a personal site, but the advisories the CI audit does not block - those below high, or only in the build tools - are exactly the ones these routine updates clear, and monthly meant waiting up to a month for a fix that was already available. Minor and patch updates are grouped into one pull request, so weekly adds little review work, while major updates arrive on their own so a breaking change is never hidden in a group. Two smaller settings sit alongside: each pull request is assigned to me, because the free plan has none of the automatic review requests a team would rely on, and @types/node is held at the Node.js version Vercel runs so the code is never checked against features production does not have.
Security updates need no configuration file - they are switched on in the repository's security settings - and I review each one on its own merits before merging. Sometimes Dependabot cannot make the fix itself, because the vulnerable package is pulled in by another that has not yet moved to the patched version; there I add an override in the package manager's configuration to force the patched version, with a note on why it is there and when it can be removed. The weekly audit also confirms those overrides are still doing their job.
Turning off unused features
A new GitHub repository comes with Issues, Projects, Discussions, and a Wiki switched on. On a private repository with one maintainer, none of them is used: I track work on a Jira board, and the documentation lives in Confluence. Each one is somewhere for unwanted content to land and something else to keep tidy, so I turned all four off. It is the same thinking as the small set of components in the last post: the fewer parts a system has, the less there is to secure and maintain.
Built with Claude Code
As with the rest of the site, the workflows and the Dependabot configuration were written with Claude Code, with me deciding what each one should do and reviewing every change. Each file is commented with the reasoning behind its settings, including the ones above, so the next change starts from why the setting is there.
What I would take into the next engagement
The practices I used in Azure DevOps carried across to GitHub almost unchanged, because they are about the outcome rather than the tool: a reviewed path to production, dependencies that are kept current, and no more features than the work needs. Where GitHub put a feature in a paid plan, the same result was usually available another way - a few lines of workflow, an open-source tool, or a little discipline. The same approach works on a larger estate: decide what each control is for, then use whatever the platform offers to achieve it, built in or not.
Written with the help of AI (Claude), then reviewed, edited, and approved by Chris Chalmers before publishing. More on how AI is used across this site is in the AI Policy.