The client-handoff problem: how to deliver a SaaS the client can actually run after you're gone.
The most overlooked deliverable on a client SaaS project isn't the code — it's the runbook. Most freelancers ship neither. Here's the handoff packet I include with every project.
Most client SaaS projects "end" with a deployed URL and a Slack message. That's not a handoff — that's an abandonment. A real handoff includes a credentials transfer, a runbook for the four things that break, an ops dashboard the client can read without you, and a clean exit ramp for the day they stop paying you. Below is the actual packet I deliver.
The problem, briefly
You ship a SaaS for a client. They love it. Three months later you're done with retainer. They reach out: "the app stopped working, can you help?" You log in. The DB filled up because nobody knew where to look. The Stripe webhook secret rotated. The error log hasn't been opened in 90 days. You spend a free Saturday afternoon fixing it because you feel bad. That's the failure mode.
The fix is delivering a handoff packet that lets the client (or their next dev) operate the thing without you. It takes 2-3 hours to put together. It saves you many more.
The packet — six items
1. The credentials sheet
A 1Password vault (shared with the client) with every account, every secret, every API key, owned by the client's email. Never your personal Cloudflare. Never your personal GitHub Org. The client owns the seat, you have access while engaged.
The single biggest pre-mistake I made early: I had the Cloudflare account in my name "for convenience." First handoff turned into a week of migration. Now: client owns the cloud account from day one, full stop.
2. The runbook for the 4 things that break
One Markdown file. Four headings. For each: symptom, cause, fix.
# Runbook — Client A SaaS
## 1. Stripe webhook started failing
Symptom: payments succeed but subscriptions don't update
Cause: webhook signing secret rotated
Fix: dashboard → developers → webhooks → reveal new secret
update STRIPE_WEBHOOK_SECRET in Cloudflare worker env
## 2. App is slow on the dashboard page
Symptom: /dashboard takes > 3s
Cause: usually the bookings query missed an index
Fix: run scripts/analyze-db.ts and review slow queries
## 3. Email reminders stopped sending
... (etc)
## 4. Database storage warning
... (etc)
That's it. Four items. The four most common breakages. The runbook is updated every time something new breaks — but it stays short. A 30-page runbook is a runbook nobody reads.
3. The morning report
The agent's morning Slack post (see three apps on autopilot). Even if the client never hires another freelancer, they get a morning summary in their inbox forever. They learn the app's heartbeat.
4. The third-party access map
One PDF page that diagrams every external service the app uses, who owns the account, and what would happen if the service went down.
- Cloudflare — client owns, runs the entire app
- Stripe — client owns, billing
- Resend — client owns, all transactional email
- Sentry — client owns, error monitoring
- GitHub — client owns the org, repo lives there
- Domain registrar — client owns the domain
You'll notice the pattern. Client owns everything. You're a guest in their stack.
5. The exit ramp
One paragraph that explains: if you fire me tomorrow, what happens, what you need to know, and how to find another dev. Verbatim:
If our engagement ends, your app continues running. All resources are in your accounts. Revoke my GitHub access and rotate the secrets in 1Password. The repo is at [URL]. Any developer familiar with TypeScript and Cloudflare Workers can pick it up — the README has a 5-minute "run locally" section. Recommended replacement freelancers: [3 names + emails].
Including the recommended replacements is what separates a real handoff from a pretend one. It's also a referral economy: the three people I list refer me back when their dance card is full.
6. The video walkthrough
One Loom, 8 minutes. Tour of the dashboard, where logs live, how to read the morning report, where the runbook is, what to do when alerts fire. Clients watch it once. Then they keep the link. I've never had a client ask me a question that wasn't already in the Loom.
The cost of doing this right
The whole packet takes me 2-3 hours to assemble at the end of a project. I include it as part of the fixed-price scope. Clients are visibly relieved when they see it — most of them have never gotten one from a previous developer.
The benefit, beyond the obvious: I get re-hired more often. Clients who left me on good terms come back when they want a new product. The handoff packet is the thing they remember when they're trying to decide who to call.
"Make yourself replaceable" sounds like bad business advice. It's the best business advice you'll get.
The agent does most of this
buildr's agent will draft the runbook, the morning-report config, and the third-party access map automatically when you tell it "we're handing this off to the client." I review and trim. The video walkthrough is still on me. The Loom hasn't been replaced yet.
The handoff packet is the difference between a delivered project and an abandoned one.
Three hours of your time at the end of a project. Stops the Saturday-afternoon support pings. Gets you re-hired more often. Costs the client nothing extra. Hard to find a higher-leverage hour of work.
Hand off the project. Keep the relationship.
buildr's agent drafts the handoff packet — runbook, alert routing, morning report, third-party map. You ship it, client signs, you both move on cleanly.
Build my app free