Your App Has No ID. And That's How It Gets Away With Murder.
App Passports: the document every application should have, and almost none do.
A few months ago I inherited a code base.
Not through any dramatic handover ceremony. No knowledge transfer sessions, no architecture walk through, no Loom videos. Just a Slack message from someone who'd already half-left the company saying "it's all in GitHub, should be straightforward." Then nothing. Then they were gone. Motorbike screaming off into the distance.
The service was running in production. It was doing something important. I could tell it was doing something important because, twice a week, someone from client services would ask why it was slow, and once a month something downstream would break in a way that made the support engineer quite agitated. But I had no idea what it was. What it connected to. What it owned. Who'd built it, or why they'd built it the way they had. I didn't even know how the pasta-based front end build framework hung together. Loosely is the term I would come to use.
I spent three days reverse-engineering a service that should have had a README, a runbook, and a little explanation from its author. It had none of those things. What it had was some onerous vibes and a .gitignore that ignored me.
That was the last time I let an application under my care exist without an App Passport.
What's an App Passport?
The physical passport is older than most people assume. It doesn't start with nation-states and border control. It starts with letters of safe passage, documents issued by monarchs so that messengers and merchants could move through hostile territory without being killed or detained. The Bible has one. Nehemiah carries a letter from the Persian king granting him safe conduct into the kingdom of Judah. Ancient Rome had something similar. Medieval merchants traveling overland through Europe carried them too.
The critical function of those early documents wasn't about the traveller's citizenship. It was about answering a question that strangers would inevitably ask: who are you, where are you going, and why should I let you pass? The document gave the bearer an identity legible to people who had never met them.
That's precisely the problem that application documentation is supposed to solve, and almost never does.
When a new engineer joins your team and encounters your service in the wild, they have the same questions a medieval border guard had: Who are you? What do you do here? Who vouches for you? Without answers, they either turn around (give up, avoid the service, route around it) or spend days interrogating the code base until they've reconstructed the answers themselves. Both are wasteful. Both are avoidable.
Spotify built Backstage partly to solve this at scale. A centralised software catalog where every service has metadata: what it is, who owns it, what it depends on. Thousands of services, one place to find out what any of them actually does. They open-sourced it in 2020. It's excellent, and also almost certainly more infrastructure than you need if you're running ten services rather than ten thousand.
You don't need Backstage. You need a Markdown file.
What Goes In One
The goal of an App Passport is to answer, in the first five minutes, every question a stranger would reasonably need to ask about your application. Not exhaustively. That's what the rest of your documentation is for. Just the things that let someone orient themselves and start being useful.
Here's what I put in mine:
Name and purpose. What is this thing? What problem does it solve? One or two sentences. Not marketing copy. If you can't summarise it in two sentences, you don't understand it well enough yet.
Owner. A team name and a real human being. Not a defunct Slack channel. Not a generic engineering@ address. Someone who, when something goes wrong at 2am, can be held lovingly and firmly responsible.
Status. Is this production-ready? Experimental? Deprecated but still running because nobody has the courage to turn it off? This field saves more time than any other.
Tech stack. Language, framework, runtime version. Enough for someone to know what they're walking into before they open a file.
Dependencies. What does this service call? What calls it? What databases does it own? What message queues does it sit on? Draw this with words if you have to. It's the map.
How to run it locally. A command, or a pointer to a file that contains commands. Not a twenty-step guide — just enough to get it running so someone can look at it.
Environments. Where does this live? What's the URL in production? In staging? Where do the logs go?
On-call and escalation. Who do you wake up? What's the runbook link? What are the common failure modes?
Links. Repo, CI/CD pipeline, monitoring dashboard, Jira board, ADRs if you have them. Put the links here so no one has to ask.
That's it. One file. Probably 50-100 lines. It lives in the root of the repo, it gets updated when the service changes, and it means that anyone who encounters this application for the first time can answer the border guard's question in under five minutes.
Here's a Real One
This is the App Passport for a fictional but very plausible notification service:
App Passport - Notify Service
What is this?
Notify handles all outbound communications for the platform - emails, SMS, and push notifications. It receives events from other services via a queue and dispatches them through the appropriate provider.
Owner
Team: Platform
Primary contact: @sarah.k (Slack) / sarah.k@company.com
Secondary: @on-call-platform (PagerDuty rotation)
Status
Production
Tech Stack
- Node.js 20 (LTS)
- TypeScript
- Express 4.x
- BullMQ (job queue)
- Prisma (ORM)
Dependencies
Upstream (calls us)
- user-service (triggers welcome/verification emails)
- billing-service (triggers invoice and payment confirmation emails)
- auth-service (triggers password reset emails)
Downstream (we call)
- SendGrid (email)
- Twilio (SMS)
- Firebase Cloud Messaging (push)
Infrastructure
- PostgreSQL (owns: `notifications`, `jobs` tables)
- Redis (BullMQ queue backend)
How to run locally
cp .env.example .env # fill in provider keys from 1Password > Platform > Notify
npm install
npm run devService runs on port 3002.
Environments
| Env | URL | Logs Z |
|---|---|---|
| Production | https://notify.internal.company | Datadog > notify-prod |
| Staging | https://notify.staging.company | Datadog > notify-staging |
On-Call & Escalation
- Runbook: Confluence — Notify Service Runbook
- Alert routing: PagerDuty > Platform Team > On-Call
- Common issues: Queue backup (check Redis memory), SendGrid rate limits (check provider dashboard)
Links
I've been going back through my existing applications and adding these one by one. It's a tedious afternoon. It's also the most useful thing I've done for future-me and for whoever inherits these things when I'm gone.
The code base I mentioned at the start? The one with no documentation and a bad smell? I added a passport to it too. I put my name in the owner field, which felt exposing, and I wrote down the things I'd had to reverse-engineer, which felt like confessing. But that's the deal. Ownership is the point. If someone gets that phone call in the early hours of the morning because my service is misbehaving, the least I can do is leave them a note.
An application without a passport is just an anonymous package on the conveyor belt. Nobody knows where it came from, nobody knows what's inside or if it's going to explode, and if it causes a problem, there's no return address.
Put a passport on your apps.