Skip to main content
Back

Versioning in the GOV.UK Prototype Kit

Versioning allows you to maintain multiple iterations of your prototype without affecting previous versions.

This is particularly useful for:

  • user research — keep an older version live while testing a new one
  • stakeholder feedback — compare multiple versions side-by-side to collaborate more effectively
  • incremental changes — modify and improve designs easily without breaking existing functionality

It’s important to keep track of what changes you make and why. Consider using an index page to note these down or a separate changelog.

Key features

  • version-agnostic forms — HTML forms do not require hardcoded action attributes
  • automated routing and redirects — a function automatically prefixes all redirects
  • scalable and maintainable — adding a new version is straightforward

Folder structure

/project-root
├── app/
│   ├── routes.js
│   └── views/
│       ├── v1/
│       │   ├── routing.js
│       │   ├── question-1.html
│       │   ├── question-2.html
│       │   └── nested/
│       │       ├── question-1.html
│       │       └── question-2.html
│       └── v2/
│           ├── routing.js
│           ├── question-1.html
│           └── question-2.html
  • routes.js — this is the central routing file, it mounts each version’s router under its respective path (such as, /v1 or /v2)
  • routing.js — these files define the routes and ensure that all navigation stays within the correct version

Example question page

<form method="post" novalidate>
    <h1 class="govuk-heading-xl">Question 1</h1>
    <button type="submit" class="govuk-button" data-module="govuk-button">
        Continue
    </button>
</form>

The <form> element should not have an action attribute.

Automatic redirects

This ensures that redirects always include the correct version prefix. If you call res.redirect('/question-2'), it automatically updates to /v1/question-2 or /v2/question-2, depending on the version.

This code should go in the routing.js file for each version.

module.exports = () => {
  const govukPrototypeKit = require('govuk-prototype-kit');
  const subRouter = govukPrototypeKit.requests.setupRouter();

  subRouter.use((req, res, next) => {
    const originalRedirect = res.redirect;
    res.redirect = function(url) {
      if (url.startsWith('/') && !url.startsWith(req.baseUrl)) {
        url = req.baseUrl + url;
      }

      return originalRedirect.call(this, url);
    };

    next();
  });

  subRouter.post('/question-1', (req, res) => {
    res.redirect('/question-2');
  });

  subRouter.post('/question-2', (req, res) => {
    res.redirect('/question-1');
  });

  return subRouter;
};

You must type out the full path for the question page and the redirect page (for example, /question-1 or /question-2). You do not need to include v1 or v2—this is handled automatically. However, if your version folder contains subdirectories, you should include the full nested path (such as, /nested/question-1).

The subRouter function should be used instead of the main router function.

Check out the GitHub repository for a working example.

Mounting version-specific routers

const govukPrototypeKit = require('govuk-prototype-kit');
const router = govukPrototypeKit.requests.setupRouter();

router.use('/v1', require('./views/v1/routing')());
router.use('/v2', require('./views/v2/routing')());

module.exports = router;

This is the routes.js file. It mounts the routing.js files from each version.

Creating a new version

  1. Duplicate the v2 folder and rename it to v3. This will create a copy of all pages and routes, so you can update them without affecting previous versions.
  2. Open the routes.js file and add the following line to mount your new version:
    router.use('/v3', require('./views/v3/routing')());
    This ensures that requests to /v3 are handled by the v3 routing file.
  3. Edit the files inside the v3 folder to make your changes.