Open-source project
amborle/featmap avatar
amborle/featmap

Featmap is a self-hostable user story mapping tool for product backlogs

The simple and open source user story mapping tool.

538 stars99 forksTypeScriptMIT

At a glance

What is it?
Featmap is a React, TypeScript and Go application for user story mapping, giving product managers personas, markdown editing, story discussions, annotations and estimates with roll-ups in a single map, backed by PostgreSQL and deployable as a binary or a Docker compose stack. It suits a team that wants story mapping off a hosted SaaS, and it is a single-purpose tool.
Who is it for?
Adopt Featmap if your product team wants to run user story mapping on infrastructure it controls, because the whole application ships as one Go binary with the frontend embedded, which means one process, one database and no node runtime on the server. Do not adopt it if you want a full work item tracker, since the README positions it as a lightweight work item management system rather than a replacement for a tracker with sprints and burndown.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 150 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What story mapping is for, according to the README

Featmap is described as a user story mapping tool for product people to build, plan and communicate product backlogs, and the README spends a paragraph on the technique itself before describing the software. User story mapping, or just story mapping, is an effective tool to create, plan and communicate your product backlog, the technique was created by Jeff Patton, and its primary utility is providing an overview of the entire product and how user goals are broken down into a series of tasks. Finally, it helps to define valuable product slices, meaning releases, and to prioritise between them. That framing matters for evaluating the tool, because a story map is a specific artefact with a specific structure, and a tool that supports it well is not the same as a tool that supports issue tracking well. The motivation paragraph is blunt about the gap Featmap fills: there are many user story mapping tools, however none are really focused on ease-of-use and simplicity. The primary language of the repository is TypeScript, the licence is MIT, the default branch is master, and the last push to the repository was on 2026-05-26, with v2.3.4 published the same day after v2.2.2 and v2.2.1.

The feature list and the intended audience

The features are six lines long, which tells you the tool's ambition level. Personas. Markdown editing. Discuss user stories. Share your user story maps with external stakeholders. User story annotations. User story estimates with roll-ups. Each of those is a specific capability rather than a category, and the share item is the one that matters for a product team, since a story map is only useful if the people who fund the work can read it. Annotations and estimates with roll-ups are the difference between a diagram and a planning instrument, since a roll-up aggregates estimates up the map so a slice can be compared to another slice. The intended audience is stated as product managers, product owners or just about anyone who is building products, and the README adds that Featmap can also be used as a lightweight work item management system for development teams. That word lightweight is doing real work in that sentence, and it is the main thing to hold on to when you decide whether it fits.

Running the released binary

Featmap can be run on your own server, and the requirements are short: PostgreSQL 11 or newer, and one of the pre-built binaries for your platform from the releases page. You download the Featmap binary for your platform and make it executable if needed, then start it.

bash
./featmap

You then open http://localhost:5000 in your browser. Configuration is read from environment variables, with a conf.json file in the working directory supported as a fallback. Only two variables are required: DATABASE_URL, the PostgreSQL connection string, and JWT_SECRET, the secret key for JWT token signing. The rest are optional: PORT for the HTTP port with a default of 5000, APP_SITE_URL for the public URL of the app, ENVIRONMENT which you set to development for non-HTTPS cookie support, MODE which you set to hosted if running as a hosted service, and the EMAIL_FROM and SMTP_SERVER, SMTP_PORT, SMTP_USER, SMTP_PASS group for invitation and password emails, with SMTP_PORT defaulting to 587. Environment variables take precedence over conf.json, and values not set in either use defaults where applicable.

The conf.json fallback

The fallback file is a single JSON object with camelCase keys that mirror the environment variables, and it is the quickest way to get a local instance running.

json
{
  "appSiteURL": "https://localhost:5000",
  "dbConnectionString": "postgresql://postgres:postgres@localhost:5432/featmap?sslmode=disable",
  "jwtSecret": "ChangeMeForProduction",
  "port": "5000",
  "emailFrom": "",
  "smtpServer": "",
  "smtpPort": "587",
  "smtpUser": "",
  "smtpPass": "",
  "environment": "development"
}

Two things in that file deserve attention. The jwtSecret value is a placeholder named ChangeMeForProduction, and the same default appears in the Docker compose file, so a deployment that does not override it is running with a publicly known signing key. The environment value of development is the switch for non-HTTPS cookie support, which matters because cookies set over plain HTTP behave differently, and a self-hosted instance behind a reverse proxy terminating TLS needs the right value here. The database URL uses sslmode=disable, which is fine for a local database and wrong for a remote one.

Building from source and running it under Docker

The source build needs Go 1.22 or newer, Node.js 18 or newer and PostgreSQL, and the quick start is a clone, a config copy and a build.

bash
git clone https://github.com/amborle/featmap.git
cd featmap
cp config/conf.json .

# Build and run
make build
./bin/featmap

The Docker route copies the packaged environment file and brings up the compose stack.

bash
cp config/.env .
docker-compose build
docker-compose up -d

The compose file defines a postgres service on the postgres:16-alpine image with a health check that runs pg_isready against the configured user, and a featmap service that waits for the database to report healthy before it starts. The application service is exposed on a configurable host port that defaults to 5000, and its environment assembles the database URL from the same database name, user and password variables with defaults of featmap. The Dockerfile shows why a single binary is possible: it installs Node into a builder stage, runs the webapp npm build so that go:embed can pick up the frontend output, compiles the Go binary with CGO disabled, and copies only that binary and the CA certificates into a minimal alpine runtime image with port 5000 exposed.

The stack behind the map

The backend is Go with the Chi v5 router and JWT authentication through jwtauth/v5 and golang-jwt/jwt/v5, PostgreSQL access via sqlx, structured logging with log/slog, graceful shutdown with signal handling, a health check endpoint at GET /v1/health, and embedded migrations and webapp via go:embed. The frontend is TypeScript and React 18 with functional components and hooks, a Redux store based on RTK, React Router v5, Vite 6 for builds, Tailwind CSS 3, @hello-pangea/dnd for drag-and-drop, and TypeScript 6. The repository root shows the shape of the code, with account-api.go, link-api.go, users-api.go and workspace-api.go as the API surfaces, model.go, repo.go and service.go as the layers, mware.go and response.go for middleware and responses, email.go for the mail side, a migrations/ directory, a lexorank/ directory, a tmpl/ directory, and a webapp/ directory for the SPA. The go.mod declares a module of github.com/amborle/featmap with go 1.25.0, which is worth noticing against the README's stated Go 1.22+ prerequisite for building from source.

Makefile targets and testing

The Makefile is the front door for development, and its targets are documented as a table in the README. make builds the Go binary and includes the webapp build via go:embed, make webapp builds the frontend SPA, make dev builds the webapp and runs the server, make test runs the Go tests, make e2e runs the Playwright end-to-end tests, make vet runs go vet, make clean removes build artefacts, make release cross-compiles for darwin, linux and windows, and there are docker-build and docker-up targets for the image and the compose services. The two test commands are short.

bash
make test
bash
make e2e

The Go suite covers API integration tests, middleware unit tests and validation tests, while the Playwright suite is browser based with a mocked API. That split is a sensible structure for an application whose frontend and backend are coupled through a single binary: you test the API directly in Go and you test the browser behaviour against a mock, so neither suite needs the whole stack running.

Where Featmap is the wrong choice

Four boundaries are worth stating. The first is scope. The feature list is six items and the README calls the tool lightweight, so if your team needs a tracker with sprint planning, burndown charts, time tracking, a defect workflow and a configurable board, Featmap will feel thin and you will end up maintaining a second system. The second is the story mapping method itself. Featmap assumes you want to work the way Jeff Patton's technique works, with the map as the primary artefact and the backlog derived from it. Teams that plan in a different shape, or that treat the story map as a one-off workshop artefact rather than a living document, get less from it. The third is the hosted service versus self-hosting split. The README offers the hosted service at www.featmap.com as the simplest way and self-hosting as the alternative, and the MODE variable is set to hosted when running as a hosted service, so the two modes are not identical products and the invitation and password email features depend on the SMTP settings being filled in. A self-hosted instance with no SMTP configuration will have no way to send invitations or password resets. The fourth is upgrade handling. The README's upgrade instruction is to download the latest release and replace the binary, and to back up the database before upgrading, which tells you the schema migrations run against your data and that rollback is not something the tool offers you. The reasonable alternative for a team that wants the story mapping method without running a server is to keep the map in a structured text format in the repository and live with the loss of the sharing and discussion features, or to use a general purpose collaborative tool and a template.

Editorial conclusion

Adopt Featmap if your product team wants to run user story mapping on infrastructure it controls, because the whole application ships as one Go binary with the frontend embedded, which means one process, one database and no node runtime on the server. Do not adopt it if you want a full work item tracker, since the README positions it as a lightweight work item management system rather than a replacement for a tracker with sprints and burndown. Verify two things before you deploy it: that your JWT_SECRET is changed from the default, since the shipped conf.json and the compose file both default to ChangeMeForProduction, and that your database is backed up before an upgrade, because the README's upgrade instruction is to replace the binary and back up the database first. The practical first step is to run make build on a machine with Go and Node, start the server against a local PostgreSQL 11 database and open http://localhost:5000.

Frequently asked questions

What is Featmap?

It is an open source user story mapping tool for product people to build, plan and communicate product backlogs, built with React, TypeScript and Go. The features are personas, markdown editing, story discussions, sharing with external stakeholders, story annotations and estimates with roll-ups.

How do I self-host Featmap?

You need PostgreSQL 11 or newer and one of the pre-built binaries for your platform from the releases page. Make the binary executable, run ./featmap and open http://localhost:5000. Configuration comes from environment variables, with a conf.json file in the working directory as a fallback.

Which environment variables does Featmap require?

Only two are required: DATABASE_URL for the PostgreSQL connection string and JWT_SECRET for signing JWT tokens. PORT defaults to 5000, and APP_SITE_URL, ENVIRONMENT, MODE, EMAIL_FROM and the SMTP_SERVER, SMTP_PORT, SMTP_USER and SMTP_PASS variables are optional, with environment variables taking precedence over conf.json.

How do I build Featmap from source?

You need Go 1.22 or newer, Node.js 18 or newer and PostgreSQL. Run git clone, cd featmap, cp config/conf.json ., then make build and ./bin/featmap. The Go binary embeds the built frontend through go:embed, and the Makefile has separate targets for the webapp build, tests, vetting and release cross-compilation.

How is Featmap upgraded?

The README instructs you to download the latest release and replace the binary, and to back up your database before upgrading. The repository ships tagged releases including v2.3.4, and the last push to the repository was on 2026-05-26.

Official sources

  1. amborle/featmap on GitHub
  2. Issues
  3. License: MIT
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/amborle-featmap.svg)](https://hysenlabs.com/projects/amborle-featmap)

Was this useful?