What This Template Is For
A feature spec bridges the gap between "what we decided to build" and "what engineering actually builds." As Joel Spolsky argued in Painless Functional Specifications, a good spec eliminates ambiguity. A bad spec (or no spec) produces a feature that technically works but does not match what the PM intended, what design mocked, or what the user needs.
This template is designed for the handoff point: after discovery is done, after the PRD is approved, after designs are finalized. It translates product intent into engineering-actionable detail. Each section answers a question an engineer will ask during implementation. If you leave a section blank, expect a Slack message asking for clarification mid-sprint.
For a full walkthrough of how PMs and engineers collaborate on technical specifications, see the Technical PM Handbook. For context on user stories and how they connect to specs, the glossary entry covers the fundamentals.
How to Use This Template
- Write it with engineering, not for engineering. The best specs are co-authored. The PM fills in product context, user stories, and success criteria. The tech lead fills in API design, data model, and performance requirements. Do a joint review before sprint planning.
- Be specific about what is out of scope. Engineers will naturally think about adjacent problems. A clear "Out of Scope" section prevents well-intentioned scope creep.
- Include the "why" for every requirement. "The user should see a confirmation modal" is weaker than "The user should see a confirmation modal because this action is irreversible and accidental deletions cost us 3 support tickets per week." Context prevents engineers from deprioritizing requirements they do not understand.
- Update the spec when scope changes. A spec that does not reflect the current plan is worse than no spec. When you cut scope or change requirements mid-sprint, update the document and notify the team.
- Score this feature before writing the spec. Use the RICE Calculator to validate that this feature is worth the engineering investment before spending time on a detailed spec.
Feature Specification Template
Feature Overview
| Field | Details |
|---|---|
| Feature Name | [Clear, descriptive name] |
| PRD Link | [Link to the parent PRD or project doc] |
| Design Link | [Link to Figma file or design spec] |
| Owner (PM) | [Name] |
| Owner (Engineering) | [Tech lead name] |
| Target Release | [Sprint or date] |
| Priority | [P0 / P1 / P2] |
| Status | [Draft / In Review / Approved / In Development] |
One-line summary: [What this feature does in plain language. A sentence a new team member could read and understand.]
Context: [2-3 sentences on why this feature exists. What user problem does it solve? What business outcome does it drive? Link to relevant research, data, or customer quotes.]
User Story
Use the standard format: "As a [user type], I want [action], so that [benefit]."
Primary user story:
As a [user type], I want to [action], so that [benefit].
Secondary user stories (if applicable):
As a [user type], I want to [action], so that [benefit].
As a [user type], I want to [action], so that [benefit].
Acceptance Criteria
Define the conditions that must be true for this feature to be considered complete. Use the Given/When/Then format from Behavior-Driven Development so QA can write test cases directly from these criteria. Each acceptance criterion should be independently testable.
AC1: [Descriptive name]
- Given: [Precondition or context]
- When: [User action or system event]
- Then: [Expected outcome]
AC2: [Descriptive name]
- Given: [Precondition or context]
- When: [User action or system event]
- Then: [Expected outcome]
AC3: [Descriptive name]
- Given: [Precondition or context]
- When: [User action or system event]
- Then: [Expected outcome]
AC4: [Descriptive name]
- Given: [Precondition or context]
- When: [User action or system event]
- Then: [Expected outcome]
UI/UX Requirements
Link to the Figma file for full visual spec. Highlight critical interaction details here that might be missed in a design review.
- Layout: [Where does this feature appear? New page, modal, inline, sidebar?]
- Responsive behavior: [How does it adapt for mobile, tablet, desktop?]
- Loading states: [What does the user see while data loads?]
- Empty states: [What does the user see when there is no data?]
- Animations/transitions: [Any specific motion requirements?]
- Accessibility: [Keyboard navigation, screen reader labels, focus management, color contrast requirements]
API Requirements
Define any new or modified API endpoints this feature requires. For guidelines on API design from a PM perspective, see the API design guide.
Endpoint 1:
Method: [GET / POST / PUT / PATCH / DELETE]
Path: /api/v1/[resource]
Auth: [Required / Optional / None]
Request body:
{
"field1": "string (required)",
"field2": "number (optional, default: 10)"
}
Response (200):
{
"id": "string",
"field1": "string",
"createdAt": "ISO 8601 datetime"
}
Error responses:
400: Invalid input (validation errors in response body)
401: Unauthorized
404: Resource not found
429: Rate limited
Endpoint 2:
[Same format as above]
Data Model Changes
Describe any new tables, columns, or schema modifications required.
Table: [table_name]
New columns:
- column_name (type, nullable, default, index)
- column_name (type, nullable, default, index)
Migrations:
- [Description of migration and whether it requires downtime]
- [Backfill requirements, if any]
Edge Cases
List scenarios that fall outside the happy path. Each edge case should have a defined behavior.
| # | Edge Case | Expected Behavior |
|---|---|---|
| 1 | [Scenario] | [What should happen] |
| 2 | [Scenario] | [What should happen] |
| 3 | [Scenario] | [What should happen] |
| 4 | [Scenario] | [What should happen] |
| 5 | [Scenario] | [What should happen] |
Error States
Define what the user sees when things go wrong.
| Error Condition | User-Facing Message | Technical Response | Recovery Action |
|---|---|---|---|
| [Network failure] | [Message shown] | [HTTP status + body] | [Retry / Redirect / Fallback] |
| [Invalid input] | [Message shown] | [Validation error format] | [Inline error + field highlight] |
| [Permission denied] | [Message shown] | [403 response] | [Redirect to upgrade / Show explanation] |
| [Rate limited] | [Message shown] | [429 + Retry-After header] | [Disable button + countdown] |
| [Server error] | [Message shown] | [500 response] | [Generic error + retry option] |
Analytics Events
Define the events this feature should track.
| Event Name | Trigger | Parameters | Purpose |
|---|---|---|---|
| [event_name] | [User action] | [key: value pairs] | [What question this answers] |
| [event_name] | [User action] | [key: value pairs] | [What question this answers] |
| [event_name] | [System event] | [key: value pairs] | [What question this answers] |
Dependencies
| Dependency | Team / Service | Status | Risk | Mitigation |
|---|---|---|---|---|
| [What you depend on] | [Who owns it] | [Ready / In Progress / Blocked] | [High / Medium / Low] | [Fallback plan] |
| [What you depend on] | [Who owns it] | [Ready / In Progress / Blocked] | [High / Medium / Low] | [Fallback plan] |
Out of Scope
Explicitly list what this feature does not include. This prevents scope creep and sets expectations with stakeholders.
- [Feature or capability that is explicitly excluded]
- [Feature or capability that is explicitly excluded]
- [Future enhancement that will be addressed in a follow-up iteration]
Filled Example: Notification Preferences Feature
Feature Overview
| Field | Details |
|---|---|
| Feature Name | Notification Preferences |
| PRD Link | [Link to notification improvements PRD] |
| Design Link | [Link to Figma file] |
| Owner (PM) | Sarah Chen |
| Owner (Engineering) | Marcus Rivera |
| Target Release | Sprint 14 (March 10, 2026) |
| Priority | P1 |
| Status | Approved |
One-line summary: Users can control which notifications they receive and through which channels (in-app, email, Slack).
Context: Support tickets about notification overload increased 40% QoQ. 8 of 12 user interviews mentioned notification fatigue. Power users in large accounts (10+ members) receive 30-50 notifications per day and report missing critical alerts because they start ignoring all of them. This feature lets users customize their notification preferences by type and channel.
User Story
Primary:
As a power user in a large team, I want to choose which notifications I receive and how I receive them, so that I see critical alerts without being overwhelmed by low-priority updates.
Secondary:
As a team admin, I want to set default notification preferences for new team members, so that new users start with sensible defaults instead of receiving everything.
Acceptance Criteria
AC1: View current preferences
- Given: A logged-in user navigates to Settings > Notifications
- When: The page loads
- Then: A table displays all notification types grouped by category (Mentions, Task Updates, System Alerts, Weekly Digest) with toggles for each channel (In-App, Email, Slack)
AC2: Update a single preference
- Given: A user is viewing the notification preferences page
- When: They toggle "Email" off for "Task Updates"
- Then: The change saves automatically (no save button), a brief success indicator appears, and subsequent task update notifications are not sent via email
AC3: Bulk actions
- Given: A user wants to mute all non-critical notifications
- When: They click "Mute All" in a category header
- Then: All toggles in that category switch off except for System Alerts, which cannot be fully muted (at least one channel must remain on)
AC4: Critical alert protection
- Given: A user attempts to turn off all channels for System Alerts
- When: They toggle off the last remaining channel
- Then: The toggle reverts, and an inline message explains: "At least one channel must be active for critical alerts"
Edge Cases
| # | Edge Case | Expected Behavior |
|---|---|---|
| 1 | User has Slack integration disconnected but Slack toggle is on | Show "(not connected)" label next to Slack toggles. Clicking the toggle prompts Slack reconnection. |
| 2 | Admin changes team defaults after users have customized preferences | Existing user preferences are preserved. Only new team members get the updated defaults. |
| 3 | User is in multiple workspaces with different preferences | Preferences are scoped per workspace. The settings page shows the current workspace's preferences. |
| 4 | Notification type is added in a future release | New notification types default to "all channels on" for existing users. |
| 5 | User turns off all email notifications then resets to defaults | Reset restores the team default or system default preferences. |
Out of Scope
- Per-project notification preferences (future iteration)
- Notification scheduling (e.g., "do not disturb" hours)
- Notification history or log page
- Custom notification sounds or badge customization
