How to Write a Good User Story for Developers (as a PM or PO)

Gabbie Hajduk
[
  {
    "__component": "shared.rich-text",
    "id": 284,
    "body": "Clear, concise, and actionable development tickets that help your team move faster with fewer blockers.\n\n## Why Good Tickets Matter\n\nIf you’ve ever been deep in a planning session and realised no one really knows what a ticket is about - or a developer is needing to ask you a question every five minutes on implementation - you already understand why writing good stories matters. A well-written ticket is not just documentation - it’s a communication tool, a guide, and an accelerator.\n\nIt helps everyone: developers, testers, designers, stakeholders, even your future self. Done right, it prevents ambiguity, saves time, and builds trust across your team.\n\n## Start with Consistency\n\nConsistency helps your team know what to expect.\n\nOver the years, I've put a lot of thought into how I write tickets.  Whether a story is being picked up for the first time or revisited months later, having a clear and consistent structure helps everyone get on the same page quickly.\n\n## Ticket Structure at a Glance\n\nBefore we dive into the details, here’s a quick overview of how I typically structure a development ticket:\n\n1. **Title** - Write it as a clear task direction. For example: *“Add ability to filter order history by date”*. Think of it as a short sentence that answers: what is this ticket doing?\n1. **User Stories** - Use the format: *\"As a [type of user], I want [to do X] so I can [get Y outcome].\"*\n1. **Business Context** - Why this ticket exists, what sparked it, and how users currently solve the problem.\n1. **Proposed Solution (Initial)** - Any initial suggestions or previous attempts, including who suggested them.\n1. **Actual Solution** - The agreed solution that will be built. Include designs, links, and clear instructions.\n1. **Acceptance Criteria** - Must-haves and nice-to-haves that define when this ticket is considered complete.\n1. **Link Related Tickets** - Epics, dependencies, and parallel work.\n\nEach section serves a different purpose, but together they make for a well-rounded, easy-to-follow ticket."
  },
  {
    "__component": "shared.media",
    "id": 29,
    "file": {
      "id": 99,
      "documentId": "pftdl1d7nlx6r4hkkia0r8py",
      "name": "jira-user-story-structure.png",
      "alternativeText": "Flat-style illustration of a Jira ticket layout showing clearly labelled sections like Title, Business Context, User Stories, and Acceptance Criteria, designed to demonstrate good ticket writing structure.",
      "caption": null,
      "width": 1536,
      "height": 1024,
      "formats": {
        "thumbnail": {
          "ext": ".png",
          "url": "https://res.cloudinary.com/dmkbljcg2/image/upload/v1745100701/thumbnail_jira_user_story_structure_04c6119255.png",
          "hash": "thumbnail_jira_user_story_structure_04c6119255",
          "mime": "image/png",
          "name": "thumbnail_jira-user-story-structure.png",
          "path": null,
          "size": 22.43,
          "width": 234,
          "height": 156,
          "sizeInBytes": 22428,
          "provider_metadata": {
            "public_id": "thumbnail_jira_user_story_structure_04c6119255",
            "resource_type": "image"
          }
        }
      },
      "hash": "jira_user_story_structure_04c6119255",
      "ext": ".png",
      "mime": "image/png",
      "size": 234.06,
      "url": "https://res.cloudinary.com/dmkbljcg2/image/upload/v1745100702/jira_user_story_structure_04c6119255.png",
      "previewUrl": null,
      "provider": "cloudinary",
      "provider_metadata": {
        "public_id": "jira_user_story_structure_04c6119255",
        "resource_type": "image"
      },
      "createdAt": "2025-04-19T22:11:43.258Z",
      "updatedAt": "2025-04-19T22:11:43.258Z",
      "publishedAt": "2025-04-19T22:11:43.259Z"
    }
  },
  {
    "__component": "shared.rich-text",
    "id": 285,
    "body": "## The Ideal Ticket Structure\n\nHere’s a practical breakdown of how to write a user story that’s effective and realistic, especially from the perspective of a Product Manager or Product Owner:\n\n### User Stories\n\nUse the classic structure:\n\n**\"As a [type of user], I want [to do X] so I can [get Y outcome].\"**\n\nIf your feature has multiple user stories, list them out. Each helps clarify the who, what, and why. It doesn’t really matter how many additional ones are added, but normally I would say a maximum of five. If you find yourself listing more than that, it might be a sign the story needs to be broken down into smaller, more manageable parts. You could also be trying to solve too many problems in a single ticket. And remember, you don’t need to capture every possible user story—just the key ones that are most relevant to this particular feature, so the team can stay focused on what matters most.\n\n### Business Context\n\nStart your story with the background:\n\n- What prompted this idea?\n- Was there feedback, a stakeholder request, or an insight from data?\n- Why now?\n\nContext isn’t fluff - it’s what helps a developer (or designer, analyst, etc.) understand the thinking behind the story.\n\nI usually label this section as **Business Context**. It’s where I’ll also include how users are currently using the system. Even if the existing business process you're automating or adapting is a manual one, describing it can still give useful context to the team. For example: *“When the sales agent makes a sale, they enter the sales amount, description, etc. into X file (see attached). This allows the sales manager to keep track of all sales.”*\n\nAdd helpful facts that provide framing.\n\n### Proposed Solution (Initial)\n\nThis section is where the spark solution would go - it’s where I’d record who suggested the idea and what their proposed solution was. If I had my own version of the solution, I’d put that underneath theirs so we could see how it evolved. It helped keep track of the decision-making process and allowed others to understand how different solutions were considered. When the ticket is ready to be developed, I usually move this section to the bottom of the ticket under a heading called **History**, or move it into Confluence with a link in the ticket, so it doesn’t confuse the actual implementation path.\n\n### Actual Solution\n\nClearly explain what the solution should do:\n\n- Write in plain language, or break it down into steps or a checklist.\n- Include links to designs, diagrams, documents.\n- Where possible, display images or diagrams inline (Jira supports this).\n\nThis is the solution you want the developers to actually create.\n\nThe goal is clarity - what is someone building, and how should it behave?\n\n### Acceptance Criteria\n\nSplit this into:\n\n**Must Have** - These are your hard requirements. Think of them as pass/fail conditions. If any of these criteria are not met, the feature should not be released until they are.  \n**Nice to Have** - These are low-priority additions that shouldn’t block delivery. After the feature is released, I usually take any unfinished nice-to-have items and move them into a new ticket for the backlog. These are great for quieter times or for onboarding less senior developers who can pick them up as manageable, lower-priority tasks.\n\nExample:\n\n- **Must Have**: Add a dropdown labelled \"Status\" with options A, B, C.\n- **Nice to Have**: Display options in A-Z order. \n\nIn some teams, you might use two checkbox columns - one for developers, one for QA. This works best when everyone’s aligned. That said, this level of overhead really only works in corporate environments where things move slower and there’s a well-defined QA process. In startups, scaleups, or fast-paced companies, I’d avoid trying to enforce this - it's likely to slow things down rather than help.\n\n### Link Related Tickets\n\nAlways link:\n\n- The parent Epic (if applicable)\n- Related subtasks\n- Dependencies (e.g. API integrations, parallel stories)\n\nThis helps future you (and everyone else) see how the work fits together.\n\n## Handling Ambiguity and Change\n\nSome features are fuzzy at the edges. You might not have all the answers. That’s okay.\n\nWhen uncertainty exists:\n\n- Consider writing a **Spike Ticket** to explore the unknowns.\n- Set a rough timebox (usually estimated by the devs).\n\nIf you don’t have time for a spike:\n\n- Write out the possible scenarios.\n- Include assumptions.\n- If decisions change during implementation, log changes as a comment or create a new section in the ticket.\n\nJira has a history log, but it’s not always user-friendly - so spell out major updates in plain sight.\n\n## What Not to Include\n\nBe careful not to overstep:\n\n- Don’t include technical implementation details unless it’s a technical ticket.\n- If you must include them, add a **Technical Spec (Draft)** section and ask devs to amend.\n- Leave subtasks and system architecture to the devs - they own that space.\n\n## Edge Cases Matter\n\nMissing edge cases is a fast track to scope creep and frustration.\n\n- If known edge cases exist, write them in the ticket.\n- If they’re too detailed, link to a separate story.\n- Make it part of your definition of ready.\n\nEdge cases often change the implementation approach - better to know that up front.\n\n## Don’t Overload the Ticket\n\nTickets that are too big cause problems:\n\n- Progress looks stagnant in standups.\n- PMs can’t track momentum.\n- Devs feel under-appreciated.\n\nAim to keep tickets small:\n\n- Use subtasks or break into multiple stories.\n- As a rule of thumb, if you’re using pointing, the maximum end of your scale (e.g. 21 points in a typical Fibonacci sequence) is a strong indicator the story is too big. It likely contains hidden complexity that should either be resolved with a spike or broken down into multiple, clearer stories.\n\n**Example**: Building a marketing site\n\nInstead of writing one big story like **\"Build a marketing website with a blog and waitlist\"**, break the work down into smaller stories like this:\n\n1. Set up infrastructure (CI, DB)\n1. Create waitlist page and save signups\n1. Create homepage and link to waitlist - you could release now\n1. Create blog list page\n1. Create blog detail page\n1. Add blog to nav - now another release\n\nThis allows early releases, faster feedback, and better morale.\n\n## What About Design and Data Tickets?\n\n### Design Stories\n\nDesign stories are usually structured a little differently than developer tickets. They focus more on user journeys and goals - what the user is trying to achieve and how they might interact with the system. It’s also important to outline how the design should behave across different devices and screen sizes, with a mobile-first mindset if you're working on web products.\n\nYou should clearly define the level of fidelity expected - whether this ticket is for wireframes, high-fidelity mockups, or a clickable prototype. And if it's a prototype, make sure to state who it’s for (e.g. internal use, stakeholder review, or user testing).\n\nI also include any relevant A/B test insights or examples of how competitors solve similar problems. Finally, clearly outline both the happy path and any potential unhappy paths so the designer knows what scenarios they need to consider.\n\n### Data Tickets\n\nWhen writing stories for data teams, it’s important to distinguish between data scientists and data analysts, because their work often follows different paths.\n\nData scientists usually take on goal-driven work that is exploratory in nature. These tickets tend to resemble spikes more than structured stories, since there might be many ways to solve the problem or approach the analysis.\n\nData analysts, by contrast, often work with well-defined tasks and expected outputs. Their tickets are usually closer to development stories and could include things like producing a dashboard, generating a specific report, or pulling analysis on a user segment or behavioural trend.\n\n## How PO vs BA Stories Differ\n\nPMs and POs tend to write stories that focus on outcomes, user context, and business value. They aim to capture the reasoning behind the request and the user needs it addresses, making the stories more vision-driven and less bogged down in excessive detail.\n\nBusiness Analysts, on the other hand, often craft tickets that are more focused on specific requirements, constraints, and system behaviours. Their stories might include detailed technical rules, performance expectations, and any regulatory or compliance needs that must be considered.\n\nYou’ll often find overlap between the two styles, but the focus is different. We’ll explore this distinction more deeply in a future blog.\n\n## Dos and Don’ts of Writing User Stories\n\n**✅ Do:**\n\n- Start with clear business context to set the stage.\n- Use a structured format your team recognises.\n- Add user stories even if they’re rough - clarity improves over time.\n- Be specific with what the solution should do.\n- Include designs, links, and visual references inline when possible.\n- List edge cases and known assumptions.\n- Break down large tickets into smaller, testable parts.\n- Keep a section for historical context if ideas evolve.\n- Log changes visibly, not just in Jira history.\n- Ensure design and data stories are written separately from development stories - they should normally be distinct and not crammed into one ticket.\n\n**❌ Don’t:**\n\n- Assume everyone knows the backstory - write it down.\n- Include technical implementation unless it’s a technical ticket.\n- Add too many “nice to haves” that blur what’s essential.\n- Let ambiguity sit - use spikes or comments to clarify.\n- Overload the story with too many objectives.\n- Try to own dev subtasks - collaborate instead.\n- Forget to revisit “shelved” or parked ideas later.\n\n## Building the Ticket Over Time\n\nOne last note: your ticket doesn’t need to be fully written the moment the idea surfaces. In fact, that’s rarely how I work. I usually start with the **Business Context** and the **Proposed Solution (Initial)** as soon as the spark for the idea hits. Then, once we’ve decided to move forward with the feature and we have a clearer understanding of what we’re building, I begin to fill out the other sections like the actual solution, user stories, and acceptance criteria.\n\nI talk more about this iterative approach in [this blog on implementing lean discovery workflows](https://produmo.com/blog/implementing-lean-feature-discovery-workflows-in-product-development). It’s part of embracing discovery - writing just enough at each step without creating waste.\n\n## Final Thoughts\n\nGreat tickets aren’t about perfect grammar or clever formatting. They’re about:\n\n- Communicating the why\n- Framing the what\n- Enabling the how\n\nThe more you anticipate your team’s questions, the less time you’ll spend unblocking them later.\n\nClear tickets are a product manager’s silent superpower."
  }
]

Clear, concise, and actionable development tickets that help your team move faster with fewer blockers.

Why Good Tickets Matter

If you’ve ever been deep in a planning session and realised no one really knows what a ticket is about - or a developer is needing to ask you a question every five minutes on implementation - you already understand why writing good stories matters. A well-written ticket is not just documentation - it’s a communication tool, a guide, and an accelerator.

It helps everyone: developers, testers, designers, stakeholders, even your future self. Done right, it prevents ambiguity, saves time, and builds trust across your team.

Start with Consistency

Consistency helps your team know what to expect.

Over the years, I've put a lot of thought into how I write tickets. Whether a story is being picked up for the first time or revisited months later, having a clear and consistent structure helps everyone get on the same page quickly.

Ticket Structure at a Glance

Before we dive into the details, here’s a quick overview of how I typically structure a development ticket:

  1. Title - Write it as a clear task direction. For example: “Add ability to filter order history by date”. Think of it as a short sentence that answers: what is this ticket doing?
  2. User Stories - Use the format: "As a [type of user], I want [to do X] so I can [get Y outcome]."
  3. Business Context - Why this ticket exists, what sparked it, and how users currently solve the problem.
  4. Proposed Solution (Initial) - Any initial suggestions or previous attempts, including who suggested them.
  5. Actual Solution - The agreed solution that will be built. Include designs, links, and clear instructions.
  6. Acceptance Criteria - Must-haves and nice-to-haves that define when this ticket is considered complete.
  7. Link Related Tickets - Epics, dependencies, and parallel work.

Each section serves a different purpose, but together they make for a well-rounded, easy-to-follow ticket.

The Ideal Ticket Structure

Here’s a practical breakdown of how to write a user story that’s effective and realistic, especially from the perspective of a Product Manager or Product Owner:

User Stories

Use the classic structure:

"As a [type of user], I want [to do X] so I can [get Y outcome]."

If your feature has multiple user stories, list them out. Each helps clarify the who, what, and why. It doesn’t really matter how many additional ones are added, but normally I would say a maximum of five. If you find yourself listing more than that, it might be a sign the story needs to be broken down into smaller, more manageable parts. You could also be trying to solve too many problems in a single ticket. And remember, you don’t need to capture every possible user story—just the key ones that are most relevant to this particular feature, so the team can stay focused on what matters most.

Business Context

Start your story with the background:

  • What prompted this idea?
  • Was there feedback, a stakeholder request, or an insight from data?
  • Why now?

Context isn’t fluff - it’s what helps a developer (or designer, analyst, etc.) understand the thinking behind the story.

I usually label this section as Business Context. It’s where I’ll also include how users are currently using the system. Even if the existing business process you're automating or adapting is a manual one, describing it can still give useful context to the team. For example: “When the sales agent makes a sale, they enter the sales amount, description, etc. into X file (see attached). This allows the sales manager to keep track of all sales.”

Add helpful facts that provide framing.

Proposed Solution (Initial)

This section is where the spark solution would go - it’s where I’d record who suggested the idea and what their proposed solution was. If I had my own version of the solution, I’d put that underneath theirs so we could see how it evolved. It helped keep track of the decision-making process and allowed others to understand how different solutions were considered. When the ticket is ready to be developed, I usually move this section to the bottom of the ticket under a heading called History, or move it into Confluence with a link in the ticket, so it doesn’t confuse the actual implementation path.

Actual Solution

Clearly explain what the solution should do:

  • Write in plain language, or break it down into steps or a checklist.
  • Include links to designs, diagrams, documents.
  • Where possible, display images or diagrams inline (Jira supports this).

This is the solution you want the developers to actually create.

The goal is clarity - what is someone building, and how should it behave?

Acceptance Criteria

Split this into:

Must Have - These are your hard requirements. Think of them as pass/fail conditions. If any of these criteria are not met, the feature should not be released until they are.
Nice to Have - These are low-priority additions that shouldn’t block delivery. After the feature is released, I usually take any unfinished nice-to-have items and move them into a new ticket for the backlog. These are great for quieter times or for onboarding less senior developers who can pick them up as manageable, lower-priority tasks.

Example:

  • Must Have: Add a dropdown labelled "Status" with options A, B, C.
  • Nice to Have: Display options in A-Z order.

In some teams, you might use two checkbox columns - one for developers, one for QA. This works best when everyone’s aligned. That said, this level of overhead really only works in corporate environments where things move slower and there’s a well-defined QA process. In startups, scaleups, or fast-paced companies, I’d avoid trying to enforce this - it's likely to slow things down rather than help.

Link Related Tickets

Always link:

  • The parent Epic (if applicable)
  • Related subtasks
  • Dependencies (e.g. API integrations, parallel stories)

This helps future you (and everyone else) see how the work fits together.

Handling Ambiguity and Change

Some features are fuzzy at the edges. You might not have all the answers. That’s okay.

When uncertainty exists:

  • Consider writing a Spike Ticket to explore the unknowns.
  • Set a rough timebox (usually estimated by the devs).

If you don’t have time for a spike:

  • Write out the possible scenarios.
  • Include assumptions.
  • If decisions change during implementation, log changes as a comment or create a new section in the ticket.

Jira has a history log, but it’s not always user-friendly - so spell out major updates in plain sight.

What Not to Include

Be careful not to overstep:

  • Don’t include technical implementation details unless it’s a technical ticket.
  • If you must include them, add a Technical Spec (Draft) section and ask devs to amend.
  • Leave subtasks and system architecture to the devs - they own that space.

Edge Cases Matter

Missing edge cases is a fast track to scope creep and frustration.

  • If known edge cases exist, write them in the ticket.
  • If they’re too detailed, link to a separate story.
  • Make it part of your definition of ready.

Edge cases often change the implementation approach - better to know that up front.

Don’t Overload the Ticket

Tickets that are too big cause problems:

  • Progress looks stagnant in standups.
  • PMs can’t track momentum.
  • Devs feel under-appreciated.

Aim to keep tickets small:

  • Use subtasks or break into multiple stories.
  • As a rule of thumb, if you’re using pointing, the maximum end of your scale (e.g. 21 points in a typical Fibonacci sequence) is a strong indicator the story is too big. It likely contains hidden complexity that should either be resolved with a spike or broken down into multiple, clearer stories.

Example: Building a marketing site

Instead of writing one big story like "Build a marketing website with a blog and waitlist", break the work down into smaller stories like this:

  1. Set up infrastructure (CI, DB)
  2. Create waitlist page and save signups
  3. Create homepage and link to waitlist - you could release now
  4. Create blog list page
  5. Create blog detail page
  6. Add blog to nav - now another release

This allows early releases, faster feedback, and better morale.

What About Design and Data Tickets?

Design Stories

Design stories are usually structured a little differently than developer tickets. They focus more on user journeys and goals - what the user is trying to achieve and how they might interact with the system. It’s also important to outline how the design should behave across different devices and screen sizes, with a mobile-first mindset if you're working on web products.

You should clearly define the level of fidelity expected - whether this ticket is for wireframes, high-fidelity mockups, or a clickable prototype. And if it's a prototype, make sure to state who it’s for (e.g. internal use, stakeholder review, or user testing).

I also include any relevant A/B test insights or examples of how competitors solve similar problems. Finally, clearly outline both the happy path and any potential unhappy paths so the designer knows what scenarios they need to consider.

Data Tickets

When writing stories for data teams, it’s important to distinguish between data scientists and data analysts, because their work often follows different paths.

Data scientists usually take on goal-driven work that is exploratory in nature. These tickets tend to resemble spikes more than structured stories, since there might be many ways to solve the problem or approach the analysis.

Data analysts, by contrast, often work with well-defined tasks and expected outputs. Their tickets are usually closer to development stories and could include things like producing a dashboard, generating a specific report, or pulling analysis on a user segment or behavioural trend.

How PO vs BA Stories Differ

PMs and POs tend to write stories that focus on outcomes, user context, and business value. They aim to capture the reasoning behind the request and the user needs it addresses, making the stories more vision-driven and less bogged down in excessive detail.

Business Analysts, on the other hand, often craft tickets that are more focused on specific requirements, constraints, and system behaviours. Their stories might include detailed technical rules, performance expectations, and any regulatory or compliance needs that must be considered.

You’ll often find overlap between the two styles, but the focus is different. We’ll explore this distinction more deeply in a future blog.

Dos and Don’ts of Writing User Stories

✅ Do:

  • Start with clear business context to set the stage.
  • Use a structured format your team recognises.
  • Add user stories even if they’re rough - clarity improves over time.
  • Be specific with what the solution should do.
  • Include designs, links, and visual references inline when possible.
  • List edge cases and known assumptions.
  • Break down large tickets into smaller, testable parts.
  • Keep a section for historical context if ideas evolve.
  • Log changes visibly, not just in Jira history.
  • Ensure design and data stories are written separately from development stories - they should normally be distinct and not crammed into one ticket.

❌ Don’t:

  • Assume everyone knows the backstory - write it down.
  • Include technical implementation unless it’s a technical ticket.
  • Add too many “nice to haves” that blur what’s essential.
  • Let ambiguity sit - use spikes or comments to clarify.
  • Overload the story with too many objectives.
  • Try to own dev subtasks - collaborate instead.
  • Forget to revisit “shelved” or parked ideas later.

Building the Ticket Over Time

One last note: your ticket doesn’t need to be fully written the moment the idea surfaces. In fact, that’s rarely how I work. I usually start with the Business Context and the Proposed Solution (Initial) as soon as the spark for the idea hits. Then, once we’ve decided to move forward with the feature and we have a clearer understanding of what we’re building, I begin to fill out the other sections like the actual solution, user stories, and acceptance criteria.

I talk more about this iterative approach in this blog on implementing lean discovery workflows. It’s part of embracing discovery - writing just enough at each step without creating waste.

Final Thoughts

Great tickets aren’t about perfect grammar or clever formatting. They’re about:

  • Communicating the why
  • Framing the what
  • Enabling the how

The more you anticipate your team’s questions, the less time you’ll spend unblocking them later.

Clear tickets are a product manager’s silent superpower.