---
title: "What is a User Story?"
canonical: https://wavect.io/glossary/user-story/
language: en
description: "A short feature description from the user's point of view, 'As a [role], I want [goal], so that [benefit]', capturing intent rather than a technical spec."
image: "https://wavect.io/img/general/bak/open_graph_preview.jpg"
---

METHODOLOGY

# User Story

A short feature description from the user's point of view, 'As a [role], I want [goal], so that [benefit]', capturing intent rather than a technical spec.

Last reviewed: 2026-06-02 by [Kevin Riedl](/team/kevin-riedl/) [wiki ↗](https://www.wikidata.org/wiki/Q139796365)

A user story captures a piece of value from the perspective of the person who wants it, usually in the format “As a [role], I want [goal], so that [benefit]”. It is the unit most [agile](/glossary/agile/) teams use to fill a [sprint](/glossary/sprint/) backlog. The format is not bureaucracy for its own sake. The “as a” forces you to name who actually wants this, and the “so that” forces you to state why, which is the part teams skip and then build the wrong thing. A story is a placeholder for a conversation, not a contract.

Good stories tend to satisfy the INVEST criteria: Independent (can be built on its own), Negotiable (the details are open until you discuss them), Valuable (delivers something a user or buyer cares about), Estimable (the team can size it), Small (fits inside an iteration), and Testable (you can tell when it is done). The last two are where most stories fall apart: too big to finish, or written so vaguely that nobody can say what “done” means.

Acceptance criteria are how a story becomes testable, and writing them in a [BDD](/glossary/bdd/) Given/When/Then form is the cleanest way to do it. They are the concrete conditions that must hold for the story to be accepted, written before the work starts. “As a user I want to reset my password” is an intention. The acceptance criteria (a reset link expires after an hour, an invalid token shows a clear error, a successful reset logs the user in) are what the team actually builds and tests against.

The common anti-pattern is the story that is a task in disguise. “As a developer I want to add an index to the orders table” has the user-story costume on, but there is no user and no benefit, just an engineering task wearing a hat. That is fine to track, but it is not a user story, and dressing technical tasks as stories quietly erases the user perspective the format exists to protect.

// FAQ

## FAQs

### What is a user story?

A short description of a feature from the user’s point of view, usually ‘As a [role], I want [goal], so that [benefit]’. It captures who wants something and why, and acts as a placeholder for a conversation rather than a full technical specification.

### What are the INVEST criteria?

A checklist for a good story: Independent, Negotiable, Valuable, Estimable, Small, and Testable. Most stories fail on Small (too big to finish in an iteration) or Testable (too vague to define done). The criteria are a quick way to catch stories that will cause trouble before the team commits to them.

### When does a user story become an anti-pattern?

When it is a technical task in disguise. ‘As a developer I want to add a database index’ has no real user and no benefit, just an engineering task in a costume. Tracking such work is fine, but calling it a user story erases the user perspective the format exists to protect, which defeats the point.

Related terms

- [Agile](/glossary/agile/)
- [Sprint](/glossary/sprint/)
- [BDD](/glossary/bdd/)
- [Scrum](/glossary/scrum/)

Related services

- [Custom Software Development](/services/software-development/)

Related case studies

- [Polity](/case-studies/polity/)

Related guides

- [The software development process, week by week](/software-development-guide/software-development-process/)

Talk to us

## Structured Data

```json
{
  "@context": "https://schema.org",
  "@graph": [
    {
      "@id": "https://wavect.io/#organization",
      "@type": [
        "Organization",
        "ProfessionalService",
        "LocalBusiness"
      ],
      "employee": [
        {
          "@id": "https://wavect.io/team/kevin-riedl/#person",
          "@type": "Person",
          "jobTitle": "Managing Director",
          "name": "Kevin Riedl",
          "url": "https://wavect.io/team/kevin-riedl/",
          "worksFor": {
            "@id": "https://wavect.io/#organization",
            "@type": [
              "Organization",
              "ProfessionalService",
              "LocalBusiness"
            ]
          }
        },
        {
          "@id": "https://wavect.io/team/christof-jori/#person",
          "@type": "Person",
          "jobTitle": "Managing Director",
          "name": "Christof Jori",
          "url": "https://wavect.io/team/christof-jori/",
          "worksFor": {
            "@id": "https://wavect.io/#organization",
            "@type": [
              "Organization",
              "ProfessionalService",
              "LocalBusiness"
            ]
          }
        }
      ],
      "founder": [
        {
          "@id": "https://wavect.io/team/kevin-riedl/#person",
          "@type": "Person",
          "jobTitle": "Managing Director",
          "name": "Kevin Riedl",
          "url": "https://wavect.io/team/kevin-riedl/",
          "worksFor": {
            "@id": "https://wavect.io/#organization",
            "@type": [
              "Organization",
              "ProfessionalService",
              "LocalBusiness"
            ]
          }
        },
        {
          "@id": "https://wavect.io/team/christof-jori/#person",
          "@type": "Person",
          "jobTitle": "Managing Director",
          "name": "Christof Jori",
          "url": "https://wavect.io/team/christof-jori/",
          "worksFor": {
            "@id": "https://wavect.io/#organization",
            "@type": [
              "Organization",
              "ProfessionalService",
              "LocalBusiness"
            ]
          }
        }
      ],
      "legalRepresentative": [
        {
          "@id": "https://wavect.io/team/kevin-riedl/#person",
          "@type": "Person",
          "jobTitle": "Managing Director",
          "name": "Kevin Riedl",
          "url": "https://wavect.io/team/kevin-riedl/",
          "worksFor": {
            "@id": "https://wavect.io/#organization",
            "@type": [
              "Organization",
              "ProfessionalService",
              "LocalBusiness"
            ]
          }
        },
        {
          "@id": "https://wavect.io/team/christof-jori/#person",
          "@type": "Person",
          "jobTitle": "Managing Director",
          "name": "Christof Jori",
          "url": "https://wavect.io/team/christof-jori/",
          "worksFor": {
            "@id": "https://wavect.io/#organization",
            "@type": [
              "Organization",
              "ProfessionalService",
              "LocalBusiness"
            ]
          }
        }
      ],
      "name": "Wavect GmbH",
      "subjectOf": {
        "@id": "https://wavect.io/verified-claims.json#dataset",
        "@type": "Dataset",
        "creator": {
          "@id": "https://wavect.io/#organization",
          "@type": [
            "Organization",
            "ProfessionalService",
            "LocalBusiness"
          ]
        },
        "description": "A machine-readable registry of quantitative and qualitative claims published by Wavect, with review dates, localized page appearances and public third-party citations where available.",
        "inLanguage": "en",
        "isAccessibleForFree": true,
        "license": "https://creativecommons.org/licenses/by/4.0/",
        "name": "Wavect verified publication claims",
        "url": "https://wavect.io/verified-claims.json"
      },
      "url": "https://wavect.io/"
    },
    {
      "@id": "https://wavect.io/team/kevin-riedl/#person",
      "@type": "Person",
      "jobTitle": "Managing Director",
      "name": "Kevin Riedl",
      "sameAs": [
        "https://www.wikidata.org/wiki/Q139796365",
        "https://www.linkedin.com/in/wsdt",
        "https://github.com/wsdt"
      ],
      "url": "https://wavect.io/team/kevin-riedl/",
      "worksFor": {
        "@id": "https://wavect.io/#organization",
        "@type": [
          "Organization",
          "ProfessionalService",
          "LocalBusiness"
        ]
      }
    },
    {
      "@id": "https://wavect.io/team/christof-jori/#person",
      "@type": "Person",
      "jobTitle": "Managing Director",
      "name": "Christof Jori",
      "sameAs": [
        "https://www.wikidata.org/wiki/Q139796367",
        "https://www.linkedin.com/in/jocr77/",
        "https://github.com/jo-chris"
      ],
      "url": "https://wavect.io/team/christof-jori/",
      "worksFor": {
        "@id": "https://wavect.io/#organization",
        "@type": [
          "Organization",
          "ProfessionalService",
          "LocalBusiness"
        ]
      }
    },
    {
      "@id": "https://wavect.io/#website",
      "@type": "WebSite",
      "inLanguage": [
        "en",
        "de",
        "es",
        "zh"
      ],
      "name": "Wavect",
      "potentialAction": {
        "@type": "SearchAction",
        "query-input": "required name=search_term_string",
        "target": {
          "@type": "EntryPoint",
          "urlTemplate": "https://wavect.io/search/?q={search_term_string}"
        }
      },
      "publisher": {
        "@id": "https://wavect.io/#organization",
        "@type": [
          "Organization",
          "ProfessionalService",
          "LocalBusiness"
        ]
      },
      "url": "https://wavect.io/"
    }
  ]
}
```

```json
{
  "@context": "https://schema.org",
  "@graph": [
    {
      "@id": "https://wavect.io/glossary/user-story/#term",
      "@type": "DefinedTerm",
      "alternateName": [],
      "description": "A short feature description from the user's point of view, 'As a [role], I want [goal], so that [benefit]', capturing intent rather than a technical spec.",
      "inDefinedTermSet": "https://wavect.io/glossary/#termset",
      "name": "User Story",
      "termCode": "user-story",
      "url": "https://wavect.io/glossary/user-story/"
    },
    {
      "@id": "https://wavect.io/glossary/user-story/#webpage",
      "@type": "WebPage",
      "about": {
        "@id": "https://wavect.io/#organization",
        "@type": [
          "Organization",
          "ProfessionalService",
          "LocalBusiness"
        ]
      },
      "author": {
        "@id": "https://wavect.io/team/kevin-riedl/#person",
        "@type": "Person",
        "name": "Kevin Riedl",
        "url": "https://wavect.io/team/kevin-riedl/"
      },
      "dateModified": "2026-06-02",
      "description": "A short feature description from the user's point of view, 'As a [role], I want [goal], so that [benefit]', capturing intent rather than a technical spec.",
      "headline": "User Story",
      "inLanguage": "en",
      "isPartOf": {
        "@id": "https://wavect.io/#website",
        "@type": "WebSite"
      },
      "lastReviewed": "2026-06-02",
      "mainEntity": {
        "@id": "https://wavect.io/glossary/user-story/#term"
      },
      "mentions": [
        {
          "@id": "https://wavect.io/#organization",
          "@type": [
            "Organization",
            "ProfessionalService",
            "LocalBusiness"
          ]
        }
      ],
      "name": "User Story",
      "reviewedBy": {
        "@id": "https://wavect.io/team/christof-jori/#person",
        "@type": "Person",
        "name": "Christof Jori",
        "url": "https://wavect.io/team/christof-jori/"
      },
      "speakable": {
        "@type": "SpeakableSpecification",
        "cssSelector": [
          ".gls-single__h1",
          ".gls-single__tldr"
        ]
      },
      "url": "https://wavect.io/glossary/user-story/"
    },
    {
      "@type": "BreadcrumbList",
      "itemListElement": [
        {
          "@type": "ListItem",
          "item": "https://wavect.io/",
          "name": "Home",
          "position": 1
        },
        {
          "@type": "ListItem",
          "item": "https://wavect.io/glossary/",
          "name": "Tech, product & engagement glossary",
          "position": 2
        },
        {
          "@type": "ListItem",
          "item": "https://wavect.io/glossary/user-story/",
          "name": "User Story",
          "position": 3
        }
      ]
    }
  ]
}
```

```json
{
  "@context": "https://schema.org",
  "@type": "FAQPage",
  "mainEntity": [
    {
      "@type": "Question",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "A short description of a feature from the user's point of view, usually 'As a [role], I want [goal], so that [benefit]'. It captures who wants something and why, and acts as a placeholder for a conversation rather than a full technical specification."
      },
      "name": "What is a user story?"
    },
    {
      "@type": "Question",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "A checklist for a good story: Independent, Negotiable, Valuable, Estimable, Small, and Testable. Most stories fail on Small (too big to finish in an iteration) or Testable (too vague to define done). The criteria are a quick way to catch stories that will cause trouble before the team commits to them."
      },
      "name": "What are the INVEST criteria?"
    },
    {
      "@type": "Question",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "When it is a technical task in disguise. 'As a developer I want to add a database index' has no real user and no benefit, just an engineering task in a costume. Tracking such work is fine, but calling it a user story erases the user perspective the format exists to protect, which defeats the point."
      },
      "name": "When does a user story become an anti-pattern?"
    }
  ],
  "speakable": {
    "@type": "SpeakableSpecification",
    "cssSelector": [
      ".faq-question",
      ".faq-answer"
    ]
  }
}
```
