Pull Request Description Template: Write PRs That Get Reviewed Faster

Published on
Written byChristoffer Artmann
Pull Request Description Template: Write PRs That Get Reviewed Faster

We've all encountered them: pull requests with descriptions like "fixed stuff" or "updates" or worse, completely empty description fields. As reviewers, we're left playing detective, trying to understand what changed, why it matters, and what we should focus on. The result is slower reviews, missed context, and frustrating back-and-forth conversations that could have been avoided.

Here's what most developers don't realize: the five minutes we spend writing a clear PR description can save our reviewers hours of confusion and investigation. A well-structured description transforms the review experience from an archaeological dig into a guided tour of our changes.

The difference isn't about writing more—it's about writing strategically. We don't need essays, but we do need the right information organized in a way that helps reviewers do their job effectively. Good PR descriptions answer the questions reviewers will have before they even have to ask them.

Why PR Descriptions Matter More Than You Think

When we open a pull request, we're asking someone to context-switch from whatever they're working on and mentally load our entire change into their head. That's already a significant cognitive burden. If we make them hunt for basic information about what we changed and why, we're adding unnecessary friction to a process that's already challenging.

The description is our opportunity to set the stage. We know everything about our changes—we've lived with this code for hours or days. Our reviewer is coming in cold. We can either force them to reverse-engineer our intentions from code diffs, or we can give them a clear explanation that makes the review process smooth and efficient.

Good descriptions also create a paper trail. Six months from now, when someone needs to understand why we made a particular decision, our PR description becomes part of the project's institutional knowledge. We're not just writing for today's reviewer—we're writing for everyone who will need to understand this change in the future.

The Essential Elements Every PR Description Needs

Before we dive into specific templates, we need to understand what information actually helps reviewers. While the structure might vary based on the type of change, every good PR description answers three fundamental questions: what changed, why it changed, and what reviewers should pay attention to.

The "what" gives reviewers the high-level overview. We're not listing every file we touched—the diff shows that. Instead, we're explaining the nature of the change in human terms. "Added email validation to the registration flow" tells a much clearer story than "modified user model and controller."

The "why" provides the context that diffs can never capture. We might be fixing a bug that's causing customer complaints, implementing a feature that unlocks new revenue, or refactoring code to support future enhancements. This context helps reviewers evaluate whether our approach makes sense for the actual problem we're solving.

The "what to focus on" guides the reviewer's attention. Maybe we refactored a large file but only one section needs careful review. Perhaps we're using a new library and want feedback on the integration approach. By highlighting what matters most, we help reviewers provide more valuable feedback instead of getting lost in minor details.

Template 1: Bug Fix PR

Bug fixes need to clearly establish what wasn't working, how users experienced the problem, and what we changed to resolve it. Reviewers need enough context to verify that our fix actually addresses the root cause rather than just treating symptoms.

## Problem

Users were unable to complete checkout when applying discount codes to orders
over $100. The validation logic was checking the discounted total instead of the
pre-discount amount, causing valid codes to be rejected.

Reported in: #234 Affected users: ~150 customers over the past week

## Solution

Modified the discount validation to check against the original order total
before applying the discount. Updated the validation sequence to run discount
eligibility checks before calculating final prices.

## Changes

- Updated `OrderService.validateDiscount()` to use `originalTotal` instead of
  `currentTotal`
- Added validation step before discount calculation in checkout flow
- Added test cases for discount validation with various order amounts

## Testing

- Verified fix with exact scenario from bug report
- Tested edge cases: $99.99 orders, $100.00 orders, $100.01 orders
- Confirmed existing discount functionality still works correctly

## Screenshots

![Before: Error message when applying valid discount code](url-to-before-screenshot)
![After: Discount successfully applied to $150 order](url-to-after-screenshot)

## Rollout

Safe to deploy immediately. No database migrations or config changes needed.

This template works because it tells the complete story. We understand the user impact, see the technical cause, and know exactly what changed. The before/after screenshots provide visual proof that the bug existed and our fix resolved it. The reviewer can quickly verify that our solution addresses the actual problem rather than creating a workaround that might cause issues later.

Template 2: New Feature PR

Feature PRs need to establish what we're building, why it matters to users or the business, and how we approached the implementation. We want reviewers to evaluate whether our solution aligns with the intended goals and whether we've considered important edge cases.

## Feature Overview

Add ability for users to save multiple shipping addresses and select their
preferred address at checkout. This addresses the most requested feature from
our customer survey (mentioned by 43% of respondents).

Related: #456

## Implementation Approach

Used existing address validation infrastructure but extended the data model to
support multiple addresses per user. Kept the UI changes minimal by adding an
address selection dropdown that appears when multiple addresses exist.

### Key Technical Decisions

- Address limit: 5 per user (prevents abuse, covers 99% of use cases based on
  competitor analysis)
- Default address: Most recently used address becomes the default
- Migration: Existing single address converts to first saved address
  automatically

## Changes

- Database: Added `user_addresses` table with foreign key to users
- Backend: New AddressService for CRUD operations, updated CheckoutService
- Frontend: New AddressManagementView and updated checkout flow
- Tests: Full coverage for address CRUD and checkout scenarios

## Review Focus

- AddressService.validateAddress() uses third-party API - please verify error
  handling
- Migration strategy in migration_012.sql - want to ensure zero downtime

## Testing

- Tested with 0, 1, and 5 saved addresses
- Verified migration with staging database copy
- Confirmed checkout flow works with all address states

## Screenshots

![Address management screen showing list of saved addresses](url-to-screenshot)
![Checkout page with address selection dropdown](url-to-checkout-screenshot)
![Mobile view of address selection](url-to-mobile-screenshot)

Notice how this template frontloads the business value and then gets into technical details. We're helping reviewers understand not just how we built something, but why we built it this way. The screenshots show reviewers exactly what the feature looks like and where it appears in the application—essential context for evaluating whether the implementation matches the intended design. The "Review Focus" section is particularly valuable—it tells reviewers where we most need their expertise.

Template 3: Refactoring PR

Refactoring PRs are tricky because we're often changing a lot of code without changing any behavior. We need to clearly establish why the refactoring was necessary and how we ensured we didn't break anything.

## Refactoring Goal

Extract payment processing logic from OrderController into dedicated
PaymentService to support upcoming subscription billing feature (planned for
Q2).

Current state: Payment logic is tangled with order creation, making it difficult
to reuse for recurring charges. Target state: Clean PaymentService that handles
all payment operations independently.

## Approach

No behavior changes in this PR—purely structural refactoring. All existing
payment functionality works exactly as before, but the code is now organized to
support multiple payment scenarios.

### What Changed

- Created PaymentService with methods for charge, refund, and void operations
- Moved validation logic from controller to service layer
- Updated OrderController to use PaymentService instead of inline processing
- Extracted payment-related tests into PaymentServiceTest

### What Didn't Change

- Payment provider integration (still Stripe)
- User-facing payment flow
- Database schema
- API contracts

## Verification

- All existing tests pass without modification
- Added comprehensive PaymentService unit tests
- Manually tested checkout flow end-to-end
- Reviewed git diff to ensure no logical changes beyond extraction

## Review Approach

This is a large diff but the changes are mechanical. Recommend reviewing in this
order:

1. PaymentService.ts - verify the extracted logic is complete
2. OrderController.ts - confirm it correctly delegates to service
3. Tests - ensure coverage matches previous implementation

The key to refactoring PRs is being explicit about what we're NOT changing. Reviewers can focus on verifying that we successfully extracted the code without introducing subtle behavioral changes.

Template 4: Dependency Update PR

Dependency updates often seem straightforward but can hide breaking changes or require configuration updates. Our description needs to surface any risks or changes in behavior.

## Update Summary

Upgrading React from 18.2.0 to 18.3.1 to fix security vulnerability in
server-side rendering (CVE-2024-XXXXX).

Severity: Medium CVSS Score: 5.4 Impact: Potential XSS in SSR scenarios

## Changes Included

- Updated react and react-dom to 18.3.1
- Updated @types/react to match
- No code changes required

## Breaking Changes

None. This is a patch release with backward compatibility.

## Testing

- Full test suite passes (487 tests)
- Manual testing of SSR pages (user dashboard, product pages)
- Built production bundle and verified bundle size unchanged
- No console warnings or errors in development

## Deployment Notes

No special deployment steps needed. Standard deployment process applies.

Even for seemingly simple dependency bumps, this template helps reviewers quickly assess the risk and understand what testing we've done. The security context makes it clear why this update is important.

Template 5: Emergency Hotfix PR

Hotfixes need to communicate urgency while still providing enough information for a quick but thorough review. We're balancing speed with safety.

## 🚨 Emergency Fix - Production Down

Production checkout is failing for all users. Orders cannot be processed.

**Impact:** Complete checkout outage since 14:32 UTC **Affected users:** All
customers attempting to purchase **Revenue impact:** ~$2,000/minute in lost
sales

## Root Cause

Payment provider API endpoint changed from `/v1/charge` to `/v2/charge` without
notice. Our requests are hitting 404s.

## Fix

Updated PaymentService to use `/v2/charge` endpoint. This is a minimal change to
restore service immediately. Follow-up PR (#789) will add proper API version
handling.

### Changed

- Line 47 in PaymentService.ts: Updated endpoint URL
- No other changes to minimize risk

## Verification

- Tested in staging with live payment provider
- Successfully processed test transactions
- Error monitoring shows 404s stopped after staging deployment

## Rollout Plan

1. Deploy to production immediately after approval
2. Monitor error rates for 15 minutes
3. Roll back if any issues (deployment takes 2 minutes)

**Please review ASAP** - production is down

The hotfix template prioritizes clarity and urgency while still giving reviewers the information they need to verify the fix won't make things worse. Notice how we acknowledge this is a temporary fix with a follow-up planned.

Template 6: Documentation Update PR

Documentation PRs often get minimal descriptions, but they benefit from context just like code changes. We need to explain what we're documenting and why it matters.

## Documentation Update

Added troubleshooting guide for common database connection errors after multiple
support tickets about the same issues.

## What's New

- Troubleshooting section in database setup docs
- Common error messages with solutions
- Environment variable configuration examples

## Context

Support has received 15 tickets in the past month about database connection
failures. Analysis showed 80% were configuration issues with clear solutions.
This documentation will reduce support burden and help developers resolve issues
faster.

Related support tickets: SUPPORT-234, SUPPORT-256, SUPPORT-278

## Changes

- Added "Troubleshooting Database Connections" section to docs/database-setup.md
- Included example environment configurations for common scenarios
- Added links to related documentation

## Review Focus

Please verify the technical accuracy of the connection string examples,
especially the SSL configuration section.

Documentation updates deserve context about why we're making the changes. This helps reviewers evaluate whether we're addressing the right information gaps.

Markdown Formatting Tips for Better PR Descriptions

GitHub's markdown support gives us powerful tools to make PR descriptions more readable and useful. We can use formatting to guide reviewers through our changes and highlight important information.

Task lists help us communicate what we've completed and what might still be pending. We can use them to show our testing checklist, implementation steps, or review criteria:

## Testing Checklist

- [x] Unit tests passing
- [x] Integration tests passing
- [x] Manual testing in staging
- [ ] Performance testing (in progress)

This gives reviewers a clear picture of what's been verified and what might need extra attention.

Code blocks in descriptions can provide context for complex changes or show before/after states without making reviewers hunt through the diff:

## Before

```js
if (user.role === 'admin' || user.role === 'moderator') {
  // allow access
}
```

After

if (PRIVILEGED_ROLES.includes(user.role)) {
  // allow access
}

Linking to related issues, other PRs, or documentation helps reviewers understand the broader context. Using `#123` automatically links to issue 123 in the same repository, while `@username` can notify specific people who should be aware of the changes.

Tables work well for comparing options or summarizing test results:

```markdown
| Browser  | Status | Notes            |
|----------|--------|------------------|
| Chrome   | ✅     | All tests pass   |
| Firefox  | ✅     | All tests pass   |
| Safari   | ⚠️     | Minor UI glitch  |

We can use details/summary blocks to include information that's helpful but not essential to every reviewer:

<details>
<summary>Detailed performance benchmarks</summary>

[Include detailed performance data here]

</details>

This keeps the main description focused while making additional context available to reviewers who want it.

The Power of Visual Documentation: Screenshots and Videos

One of the most underutilized tools in PR descriptions is visual documentation. Screenshots and videos can communicate what changed and where in the application faster than paragraphs of text. When reviewers can see the actual user interface changes, error states, or interaction flows, they can provide more informed feedback without having to pull down the branch and navigate through the application themselves.

For any PR that touches the user interface, screenshots aren't optional—they're essential. A reviewer looking at changed React components or CSS files can see what the code does, but they can't easily visualize how it looks to users without visual references. Screenshots answer the immediate question every reviewer has when reviewing UI changes: "What does this actually look like?"

Videos take this a step further by showing interaction flows and animations. If we've implemented a multi-step wizard, a drag-and-drop interface, or any feature with state changes and transitions, a short screen recording shows reviewers exactly how users will experience the feature. A 30-second video can replace several paragraphs of explanation about how a feature works.

Visual documentation is particularly valuable when we're fixing bugs. Instead of describing "the button was misaligned on mobile devices," we can show a before screenshot demonstrating the problem and an after screenshot showing the fix. This visual comparison makes it immediately clear what the bug was and how we resolved it. Reviewers can verify the fix addresses the actual issue without having to reproduce the bug themselves.

The location context that screenshots provide is also crucial. When we say "updated the navigation menu," reviewers might wonder which navigation menu—the header, sidebar, mobile menu, or footer? A screenshot immediately shows them exactly where in the application the change exists. This is especially important in large applications where similar UI patterns might appear in multiple places.

For backend or API changes that have frontend implications, screenshots of the data or responses help reviewers understand the full picture. If we're modifying an API endpoint, showing screenshots of how the frontend consumes and displays that data helps reviewers evaluate whether our backend changes support the intended user experience.

When including screenshots, we should annotate them when helpful. Arrows, highlights, or labels can draw attention to specific elements that changed. If we're showing a complex screen with one small modification, an annotation helps reviewers immediately spot what's new or different without having to compare it mentally to the old version.

Screen recordings are particularly effective for demonstrating:

  • User interaction flows (clicking through a multi-step process)
  • Animations and transitions (how modals appear, how elements move)
  • Responsive behavior (how the layout adapts to different screen sizes)
  • Loading states and async operations (how the UI behaves while waiting for data)
  • Error handling (what users see when something goes wrong)

We can record these with simple tools like macOS's built-in screenshot tool, Windows Game Bar, or browser extensions. The videos don't need to be polished or edited—a raw screen recording showing the functionality is enough. We can upload videos directly to GitHub by dragging them into the PR description, or use animated GIFs for shorter demonstrations.

The key is to show, not just tell. Instead of writing "the form now validates email addresses in real-time and shows error messages below each field," we show a video of someone typing an invalid email and the error appearing. Instead of describing "the loading spinner appears while fetching data," we show it happening. Visual documentation eliminates ambiguity and helps reviewers quickly understand both the changes and their impact on the user experience.

For mobile app changes, screenshots at different screen sizes or device types help reviewers understand how the changes work across the device landscape. We might include screenshots from both iOS and Android, or from different device sizes to show responsive behavior.

Even for changes that seem purely technical, consider whether visual documentation helps. If we're optimizing a database query that makes a page load faster, a before/after video showing the performance improvement makes the impact tangible. If we're fixing a race condition in the UI, a video demonstrating the bug and then showing it resolved provides clear evidence that our fix works.

The investment in capturing screenshots and videos is minimal—usually just a few minutes—but the payoff for reviewers is substantial. They can understand changes immediately without having to set up the development environment, navigate to the right screen, and reproduce our exact scenario. This speeds up reviews and leads to better feedback because reviewers can focus on evaluating the solution rather than figuring out what changed.

Adapting Templates to Your Team's Needs

These templates are starting points, not rigid requirements. Different teams, projects, and situations call for different approaches. The key is understanding what information helps your specific reviewers do their job effectively.

Some teams might need more emphasis on security implications. Others might care more about performance impact or backwards compatibility. We should adapt our templates to surface the information that matters most to our reviewers and our project's priorities.

Smaller teams might prefer shorter descriptions since reviewers often have more context about the work being done. Larger teams or open-source projects might need more extensive explanations since reviewers might not be familiar with the specific feature area or business context.

The goal isn't to follow a template religiously—it's to communicate effectively. If a bug fix is genuinely straightforward and needs less explanation, we don't need to force it into every section of the template. But we should still provide enough context that reviewers can verify our fix addresses the actual problem.

Making PR Descriptions Part of Your Workflow

Writing good PR descriptions becomes easier when we treat them as part of the development process rather than an afterthought. We can draft our description while we're working on the changes, capturing context and decisions while they're fresh in our mind.

Some developers start by writing the PR description before they write any code. This helps clarify their thinking about what they're building and why. The description becomes a design document that guides the implementation.

We can also use our commit messages as raw material for the PR description. If we've been writing clear, contextual commit messages, we already have much of the content we need. We're just reorganizing it into a coherent narrative for reviewers.

When we finish our implementation, we should read through our draft description with fresh eyes. Does it tell the complete story? Would someone unfamiliar with our work understand what we changed and why? Are we highlighting the areas where we most need reviewer expertise?

The few minutes we invest in crafting a clear, comprehensive PR description pay dividends in faster reviews, better feedback, and fewer misunderstandings. We're not just writing for our reviewers—we're creating documentation for everyone who will interact with this code in the future. That includes our future selves when we're trying to remember why we made certain decisions months or years ago.

Good PR descriptions are an investment in our team's effectiveness and our codebase's maintainability. They transform code review from a frustrating game of twenty questions into a collaborative conversation about building better software.