Skip to content
← stanwood.dev
A wall clock above a developer's desk with code on screen

Ship Clock

stanwood.dev · production deploy tracker

One number on the wall. Days since this site last shipped — no spin, no excuses. Updates every five minutes from Vercel.

...
loading mission data

The Cadence Ladder

how to read your number

0d
shipped today

In the zone. Daily-driver project — every day is a build day.

1d
shipped yesterday

Streak intact. Yesterday still counts — keep the loop tight.

2–3d
fresh off the line

Active development. Healthy side-project rhythm — most indie shippers live here.

4–6d
clock is ticking

Between sprints. Not bad — but block out a shipping day before momentum slips.

7–13d
getting rusty

Probably waiting on a decision or a review. A typo fix or version bump resets the clock — momentum compounds.

14d+
dust is collecting

Abandonment risk. Even a README polish counts — ship something, anything, today.

Status labels come straight from the counter above. The 28-day grid shows your real cadence — gaps speak louder than the headline number.

Build Your Own

three steps · ~30 minutes

01

Create a Vercel read token

In Vercel → Account Settings → Tokens, create a scoped read token. Grab your Project ID from the project settings URL.

02

Call the deployments API

One fetch pulls the last 25 production deploys with commit metadata attached. The rest is arithmetic.

03

Mount a counter component

Compute daysSince from deployments[0].created and display it. Poll every 5 minutes with a setInterval or use stale-while-revalidate caching.

// GET /api/ship-clock
const url =
  `https://api.vercel.com/v6/deployments` +
  `?projectId=${VERCEL_PROJECT_ID}` +
  `&target=production&limit=25&state=READY`;

const res = await fetch(url, {
  headers: { Authorization: `Bearer ${VERCEL_TOKEN}` }
});

const { deployments } = await res.json();
const lastDeploy = new Date(deployments[0].created);
const daysSince = Math.floor(
  (Date.now() - lastDeploy.getTime()) / 86400000
);

Works with any Vercel project. Swap in GitHub Actions or Fly.io by adapting the deployment source.
Commit metadata (message, SHA, PR number) lives in deployments[0].meta.