Lesson 20 of 30
Every open PR gets its own live, clickable URL. A reviewer who can actually click the button behaves differently than one just reading a diff.
15 min read
Every option explains itself — why the right one is right, and why each wrong one is wrong. Miss one and it comes back later on a spaced-repetition schedule.
This topic is about judgment and practical tradeoffs more than a single right answer — a mock interview is the better way to test yourself on it.
Be interviewed on this →Hints without spoilers, and a plain explanation of why a wrong answer was wrong — answered only from this lesson. Free account, no card.
Sign up freeWhat interviewers actually ask about this, and what a strong answer has to cover.
A strong answer covers
Likely follow-ups
A preview deployment is a full, running copy of your app, deployed automatically for a single pull request, at its own unique URL, that stays live for as long as the PR stays open. Push a commit, the pipeline builds and deploys it again; close or merge the PR, the preview gets torn down. This is the pattern Vercel and Netlify made the default expectation for frontend work, and it's genuinely changed how review happens, not just where code gets hosted.
The reason it matters isn't novelty, it's what it does to review quality. Reading a diff tells a reviewer what changed in the code. Clicking a live preview tells them what changed for a user — does the button actually look right at 375px wide, does the loading state flash awkwardly, does the new form actually submit, does the animation feel off in a way that never shows up in a git diff. A reviewer stuck reading only source has to simulate the UI in their head, and that simulation is where real bugs hide — a CSS specificity conflict, a state update that renders one frame too late, an edge case only visible when you actually click through the flow. A live URL turns "does this look right" from a guess into an observation.
A preview-deployment pipeline is really three things wired together: a trigger, a unique target, and a place to post the result back.
name: Preview Deploy
on:
pull_request:
types: [opened, synchronize, reopened]
jobs:
preview:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: 11.5.0
- uses: actions/setup-node@v4
with:
node-version: 24
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm build
- name: Deploy preview
id: deploy
run: |
URL=$(vercel deploy --token=${{ secrets.VERCEL_TOKEN }} --yes)
echo "url=$URL" >> "$GITHUB_OUTPUT"
- name: Comment preview URL on the PR
uses: actions/github-script@v7
with:
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `Preview deployed: ${{ steps.deploy.outputs.url }}`
})
types: [opened, synchronize, reopened] is the trigger — it fires on the first push to a new PR, on every subsequent push (synchronize), and if a closed PR gets reopened, so the preview always reflects the PR's latest commit, not its first one. vercel deploy (or an equivalent for your host) is what makes the target unique — each deployment gets its own generated subdomain, isolated from main's production deployment and every other open PR's preview. The final step is what actually delivers the value to a human: without posting the URL back as a PR comment, the preview exists but nobody finds it, which defeats the entire point.
A pull request is opened: #142, adding a dark mode toggle.
The environments-and-promotion lesson covered dev → staging → production as a ladder a build gets promoted up. A preview deployment is that same idea shrunk down and multiplied — instead of one staging environment shared by everyone, every PR gets its own throwaway rung on the ladder, disposable the moment the PR closes.