Skip to content
MIT Open source and self-hostable

Tell open tabs a new version is liveNo more stale tabs.

OpenVersion is for teams that ship web apps. CI publishes each release, and every open tab offers a reload, or reloads by itself at a safe moment when it must.

Open source · MIT · Works with any framework, GitHub Actions and any CI

CI · acme/shop · deploy
$ npx openversion release --minor --notes-file CHANGELOG.md
Published Shop production: 1.5.0

  live        1.4.2 → 1.5.0
  open tabs   ~40, checking every 5 minutes
  notes       posted to OpenAnnounce as News

  next check  "A new version is ready. Reload"    ← nobody runs 1.4.2 for long
The problem

Deploys don't reach open tabs.

You shipped 1.5.0 at noon. Three people still have the app open from this morning, running yesterday's JavaScript against today's server.

tab opened 08:12runs 1.4.2
  1. GET /api/cart
  2. import('/assets/checkout-a1f9.js')
  3. ChunkLoadError: Loading chunk failed
tab opened yesterdayruns 1.4.1
  1. POST /api/orders
  2. { "deliveryNote": … }
  3. 400 Bad Request
tab opened last weekruns 1.3.0
  1. Bug report: "basket total is wrong"
  2. fixed in 1.3.1, nine days ago
  3. Status: can't reproduce

Stale chunks. Lazy-loaded files from the old build are gone, so navigation breaks.

Changed APIs. Old code sends old requests, and the server refuses them.

Fixed bugs, reported again. Support chases bugs that a reload would fix.

Features

Every tab on the live version, without nagging anyone.

A small client in your app, a CLI in your CI, and a dashboard for the moments that need a person.

The heart of OpenVersion

A reload, offered at the right moment

Each tab knows the version it was built as. When another one is live, it offers a reload with the release notes, or for a hard release reloads when the tab is hidden or on the next navigation. Never twice, so it can't loop.

Every environment on its own

Production, staging and previews each have their live version, keys and history.

Roll back in one click

Make an older release live, and open tabs go back to it. The history keeps both.

Two keys, never mixed up

The browser can only ask what's live. Only CI's deploy token can publish.

Publish from where you deploy

One CLI step after the deploy, with an idempotency key, so a retried job publishes once.

One cheap request per tab

A check is one query with an ETag. Unchanged answers are an empty 304.

Stale chunks, recovered

A failed lazy load makes the tab check at once and reload into the new build.

Self-host in one command

One Docker image, configured with environment variables, with a sensible default for every setting.

Hard refresh

After a bad deploy or a security fix, every open tab reloads once. No new release needed.

Release notes in OpenAnnounce

Each release can post its notes to OpenAnnounce as News, exactly once.

Export and import

Everything you put in comes out again, and goes back in.

How it works

Running in five minutes.

  1. 1

    Run it

    Start the server and add your app. Each environment gets a public key and a deploy token.

    terminal
    $ git clone https://github.com/openstuff-dev/open-version
    $ cd open-version && docker compose up -d
  2. 2

    Add the client

    Tell it the version your build is. <ov-update> shows the toast.

    main.ts
    import { configure } from '@openstuff-dev/version';
    import '@openstuff-dev/version/update';
    
    configure({
      url: 'https://version.example.com',
      publicKey: 'pk_…',
      version: import.meta.env.VITE_APP_VERSION,
    });
  3. 3

    Publish from CI

    One step after your deploy. Open tabs hear about it at their next check.

    .github/workflows/deploy.yml
    - run: npx openversion release --minor --notes-file CHANGELOG.md
      env:
        OPENVERSION_URL: https://version.example.com
        OPENVERSION_TOKEN: ${{ secrets.OPENVERSION_TOKEN }}
Why OpenVersion

Better than "please hard-refresh".

What matters A banner, a cache header and hope OpenVersion
Tabs learn about a deploy NoOnly on their next full page load. YesWithin one check, and at once on a stale chunk.
Force a reload after a bad deploy PartlyShip another release and wait. YesHard refresh or Make live, at a safe moment, once.
You own the data PartlyRelease history lives in CI logs. YesSelf-host it, and export everything.
Open source DependsOn the service you use. YesMIT licence.
Open source

Read the code, run it, change it.

  • MIT licence. Use it at work, fork it, sell it.
  • One Docker image. With Postgres, configured with environment variables.
  • Your data. On your servers, exportable at any time.
terminal
$ git clone https://github.com/openstuff-dev/open-version
$ cd open-version && docker compose up -d

Part of the OpenStuff family: tools built on one shared toolkit.

For teams and companies

Every app your company runs, on one server.

Each team has its own apps, keys and people, kept apart from the other teams in the database itself.

Apps and environments

One row per environment, with its live version and how many tabs have it open.

Teams

Separate teams on one server, kept apart with Postgres row-level security.

Safe by default

Tokens stored hashed and shown once, integration keys encrypted, no tracking.

Roles

Admins manage people. Developers publish and refresh. Viewers look.

Allowed origins

Only your own sites can ask an environment what's live.

Export and import

Move a team, its apps and its release history to another server.

FAQ

Questions people ask first

Is it free?

Yes. OpenVersion is open source under the MIT licence, so self-hosting costs nothing but your server.

Will it reload a page while someone is typing?

Not for a normal release: people get a toast and reload when they choose. A hard release or a hard refresh waits until the tab is hidden or the person navigates, or shows a countdown with Reload now. Your app can also take over the forced reload, for example to save a form first.

Does it work with my framework?

Yes. The client is plain JavaScript and <ov-update> is a web component, so it works with Angular, React, Vue, Svelte or none. Give it the version your build is, from your bundler or package.json.

Where is my data?

On your own server, in your Postgres. OpenVersion keeps your apps, releases and a per-minute count of version checks for the last hour, with no addresses or user data. Admins can export everything to one JSON file.

How is this different from a service worker update?

A service worker knows a new build exists only after it downloads one, and it can't roll back or force a reload across every tab. OpenVersion knows what's live from your CI, works without a service worker, and gives you rollback and hard refresh. They work fine together.

Ship, and every open tab follows.

Run it on your own server in five minutes.