Back to Explore
GuideVibeFix 编辑部Updated Oct 19, 2026

Desktop App Distribution for Vibe Projects: Code Signing, Notarization & Auto-Updates

AI can write a desktop app in one evening, but macOS notarization, Windows signing certificates, and auto-updates are all process grunt work. This guide lays out the complete runway from build to user: an Electron vs. Tauri decision table, the full Developer ID signing + notarization flow, OV/EV vs. Azure cloud signing, auto-updates on both platforms, four distribution channels, a CI packaging pipeline, and a 12-item pre-release checklist.

Close-up photo of a MacBook keyboard, symbolizing desktop app distribution for indie developers

AI can write a desktop app shockingly fast now: one evening, from zero to a working Tauri or Electron app — UI, features, packaging, all done. But what happens next catches most people off guard: you send the installer to your first real user, they double-click it, and instead of your app they see macOS saying "is damaged and can't be opened," or Windows' blue SmartScreen warning: "Windows protected your PC. Unrecognized app." The features you stayed up all night building? They never even saw them.

Users won't research what code signing is. They'll draw one conclusion: this software is broken. Then they delete it and never come back. What you lost isn't one download — it's a seed user who was willing to try, and seed users are an indie developer's most precious asset.

This isn't a problem with your code. It's that you haven't paved the distribution runway yet. Code signing, Apple notarization, Windows certificates, auto-updates, CI packaging — it's all process grunt work. AI can't configure it for you, can't pay your developer fees, can't guard your private keys. You have to walk it once yourself. The good news: once you've walked it, everything after is copy-paste. This article is the complete blueprint for that runway: from choosing Electron vs. Tauri, to the moment a user double-clicks your installer, to the first auto-update they receive.

A boundary note first: this guide covers desktop distribution only. Mobile publishing (App Store / Google Play review) and browser extension publishing are different games, covered by two separate VibeFix guides — vibe-project-mobile-app-store-launch-guide and browser-extension-store-launch-guide — and won't be expanded here.

Who this is for: indie developers who've already vibe-coded a working desktop app and are stuck at "how do I get it to users." Whether you use Electron or Tauri, the runway is the same; only the construction tools differ. Follow along once — roughly one weekend: signing and notarization on Saturday, auto-updates and CI on Sunday. From next Monday on, shipping a release is a single command.

1. Pick Your Runway: Electron vs. Tauri Decision Table

Distribution costs are largely decided the moment you pick a framework. Bundle size determines whether users will download it; launch speed determines whether they'll stay. Both are written into your fate the moment you run npm create. Scored across four dimensions — higher is better for indie developers:

DimensionTauri (v2)Electron
Bundle size★★★★★ Installers are usually a few MB to tens of MB; uses the system WebView, no bundled browser engine★★☆☆☆ Ships full Chromium; installers routinely exceed 100MB, still large after dmg compression
Launch speed & memory★★★★★ Rust binary + native WebView: fast cold start, low memory footprint★★★☆☆ Chromium startup overhead, high resident memory — users will come back to complain when their fans spin up
System API coverage★★★☆☆ Official plugin system is mature (fs, dialog, updater, notification, etc.), but obscure OS capabilities may require writing Rust yourself★★★★★ A decade of ecosystem; there's an npm package for everything, full Node API access, rarely need to touch native code
Solo maintenance cost★★★★☆ You need to read Rust compiler errors, but day-to-day development is still your frontend stack; one extra build link (cargo)★★★★★ Pure JS/TS, lowest mental overhead, the build chain is just npm

The verdict is clear: default to Tauri. Bundle size and launch speed are the life-or-death lines of desktop UX, and indie developers have no brand premium to make users tolerate a 150MB download and spinning fans. An 8MB dmg and a 150MB dmg feel like completely different decisions to someone hovering over the download button.

PaperOtter on VibeFix is the textbook case: Tauri + Rust + TypeScript, maintained by one person, shipping for Mac / Windows / Linux — a local document toolkit with 775 commits of continuous iteration since September 2026, doing its own update check on launch. That's Tauri's sweet spot: small, beautiful, three platforms, maintainable by one human.

Three cases for going back to Electron — don't fight it: first, your app deeply depends on Chromium-only capabilities (embedded PDF rendering, special audio/video codecs, Widevine DRM) that Tauri's system WebView can't provide; second, your team has zero Rust appetite and a brutal deadline — Electron's pure-frontend mental model really is lighter; third, your users are largely on old or heavily customized systems (some corporate intranet Windows boxes, Frankenstein Linux distros), where Electron's bundled Chromium consistency saves you pain — Tauri on Linux depends on the system's webkit2gtk, which gets flaky across distros. Outside of these, don't hesitate: pick Tauri.

Once you've chosen, learn what your build artifacts actually look like, so you don't mismatch them when configuring update feeds later: Tauri produces .app and .dmg on macOS (the updater uses the .app.tar.gz), NSIS .exe and MSI on Windows (the updater reuses the installer itself), and AppImage / .deb / .rpm on Linux. On the Electron side, Squirrel.Windows wants .nupkg, macOS wants zip or dmg. The file extensions in your update endpoint config must match your build artifacts — that's the most common rookie mistake when wiring up the update feed in section 4.

One last answer for the question every vibe coder asks: can AI write Rust? Yes. The Rust side of a Tauri app is usually thin — a few dozen lines of template code plus a handful of commands — and AI-generated quality is plenty. The real business logic still lives in the frontend. When something breaks, paste the compiler error back in; AI is actually better at fixing Rust compile errors than JS logic bugs, because the compiler points at the problem precisely. Don't retreat to Electron just because you "don't know Rust" — that's trading tactical comfort for strategic baggage.

2. The macOS Double Lock: Developer ID Signing + Notarization

macOS distribution in eight words: sign first, then notarize. Both are mandatory — sign without notarizing and macOS 10.15+ will still block you. Gatekeeper doesn't do "half signed."

Upfront cost, stated plainly: Apple Developer membership, $99/year. It's the only gateway to signing certificates and the notarization service — no alternatives, no "can I get by with a free account" (free accounts are for on-device debugging only; they can't do Developer ID distribution signing). Pick the Developer ID Application certificate type (for distribution outside the store), not Apple Distribution (that's for Mac App Store submissions — pick wrong and everything after is wasted work, including redoing the CSR flow).

The standard four-step flow, with a pitfall in each step:

  • Build the artifact: produce your .app or .dmg first. Note that every executable, every helper, every nested .app inside the bundle must be signed. Miss one and notarization fails.
  • Sign with codesign: sign with your Developer ID Application certificate, with hardened runtime enabled and a timestamp. Skip hardened runtime here and notarization is guaranteed to reject you. Tauri users set signingIdentity in tauri.conf.json (or the APPLE_SIGNING_IDENTITY env var) and signing happens automatically at build; if you have no certificate yet and just want to run locally, "-" gives you ad-hoc signing — fine for playing, useless for distribution.
  • Submit with notarytool: xcrun notarytool submit --wait. Apple runs automated security scanning, usually returning a verdict in minutes to tens of minutes. Important framing: notarization is not "app review" — it's automated malware and signature checking. Don't wait on it with an App Store review mindset, and don't write "approved by Apple" in your release notes. Different thing entirely.
  • Staple with stapler: after approval, xcrun stapler staple attaches the notarization ticket to your artifact, so Gatekeeper accepts it even offline. Skip stapling and Gatekeeper has to check the ticket online — one more moving part that can fail. If you distribute a dmg, staple the dmg itself too.
macOS signing, notarization and stapling flowchart: build artifact, codesign, notarytool submit, notarization verdict (fix causes and resubmit on rejection), stapler staple, distribute to users

Tauri users have it easiest: once the signing identity is configured, notarization goes through the App Store Connect API (APPLE_API_ISSUER / APPLE_API_KEY / APPLE_API_KEY_PATH) or your Apple ID, and tauri build runs the whole sign → notarize → staple chain automatically. Electron users wire up @electron/notarize or Electron Forge's config — same idea, and Electron's official code-signing doc covers the Forge, Packager, and Builder paths.

One Electron-specific trap worth its own paragraph: safeStorage (Keychain encryption), autoUpdater (Squirrel.Mac auto-updates), and setLoginItemSettings (launch at login) misbehave when signing isn't right — Keychain re-prompts for permission after every update, login items silently fail to register. It looks like a framework bug; it's all signing. Electron's official docs call this out explicitly: with an unsigned app, macOS can't tell that two builds are "the same app." Check your signing before debugging — it'll save you an afternoon.

Don't panic over notarization rejections — ninety percent fall into three buckets: an unsigned helper or third-party binary snuck into the bundle (most common with Electron apps, e.g. an unsigned ffmpeg you tossed in while packaging); wrong or missing entitlements; hardened runtime not enabled. Read the notarytool log, fix each item, resubmit. First submissions can be slower; it speeds up after that.

Two practical details: both dmg and zip are accepted submission formats, but the order is sign first, then pack into dmg, then notarize and staple the dmg — don't reverse it. When debugging, xcrun notarytool log pulls the full log and xcrun notarytool history shows submission history — far more useful than staring at --wait output. In Tauri CI, if notarization keeps failing, try --skip-stapling for one run to confirm signing itself is fine, then add stapling back. Bisect the problem.

3. Windows Signing: Three Roads — OV, EV, and Cloud Signing

Windows has no Apple-style unified notarization, only code-signing certificates, and the logic is inverted: certificate first, trust later. Without a certificate your app is "Unknown publisher" in users' eyes; with one, SmartScreen decides whether to warn based on your "reputation."

The recommendation first: indie developers should look at Azure Trusted Signing (now renamed Artifact Signing, Microsoft's official cloud signing service). The Basic tier is $9.99/month for 5,000 signatures a month, and Electron's official docs call it "the cheapest option for code signing on Windows" that "gets rid of SmartScreen warnings." Your private key lives in Microsoft's HSM; you just call the API. No USB token to buy, no certificate renewals to babysit — certificates live about 3 days and rotate automatically, so a stolen one is useless. Tauri's official docs cover the wiring too: set signCommand to artifact-signing-cli with your endpoint, account name, and certificate profile.

The two traditional roads, with their true costs laid out:

  • OV certificates (Organization Validated): cheap, starting around a hundred-plus dollars a year. But SmartScreen reputation accrues slowly with time and download volume — for the first few months, your users will still see the blue "Unknown publisher" dialog. Fine for tools that can grow on word of mouth without hurry. Tauri's official Windows signing guide is written around OV certs: convert to .pfx, import into the certificate store, configure certificateThumbprint — every step documented.
  • EV certificates (Extended Validation): expensive, $300–900 a year, but much higher starting trust and far fewer SmartScreen warnings. The catch: since June 2023 Microsoft requires EV private keys to live in FIPS 140-2 compliant hardware security modules — they can't be downloaded onto CI machines. That's fatal for GitHub Actions automation — you can't plug a USB token into a CI runner. Unless you use a cloud signing service (e.g. DigiCert KeyLocker, which Electron's own apps use) that keeps the hardware in the provider's datacenter and signs remotely, your pipeline dies at the "insert USB token" step.

Where do you buy? Microsoft doesn't sell direct — go to DigiCert, Sectigo, GlobalSign, SSL.com or their resellers, and shop around; prices vary a lot. Don't buy an SSL certificate by mistake — that's for website HTTPS, it can't sign code. Tauri's official docs emphasize this with an exclamation mark; people fall for it every year.

One more back road: if you develop on Linux or macOS, Electron's official docs mention jsign for signing Windows binaries via Azure Trusted Signing without a Windows VM. On the Tauri side, relic with Azure Key Vault does the same job. Many tools, one principle: don't let the private key leave a safe place.

A word on SmartScreen's "reputation" system: it's essentially a black-box score fed by download volume, time, and certificate type. A new app on an OV cert will very likely still trigger warnings for its first few hundred downloads — that's normal, don't spiral. The honest way to warm up reputation: sign early, ship early, keep a steady release cadence, so the signal "this publisher keeps shipping normal software" stays consistent. An EV cert just moves your starting line far forward; it's not immunity — misbehaving software gets its EV revoked too.

The single sentence from this section worth memorizing: you must configure a timestamp server. Certificates expire; an RFC 3161 timestamp proves "this signature was made while the certificate was valid." With timestamping, your historical releases stay trusted after the certificate expires; without it, every old version becomes "Unknown publisher" overnight the day your certificate lapses. Tauri's timestampUrl config and signtool's /tr flag exist for exactly this. Don't wait until your first certificate expires to think about it — you'll spend that day explaining yourself in your user group.

Let's total it up: Apple Developer $99/year + Azure Trusted Signing $9.99/month ≈ $220/year for "trusted distribution on both platforms." The OV route is ~$100+/year but costs you months of SmartScreen warnings; the EV route is $300–900/year plus the HSM-in-CI problem. Indie developers should try in this order: Azure Trusted Signing → OV → EV. You rarely go wrong.

4. Auto-Updates, Pick One: electron-updater vs. the Tauri Updater

Shipping is only the first half. Your user has 1.0.0 installed; you fix a bug and ship 1.0.1. Expecting them to manually download and reinstall? Dream on. Auto-update isn't a bonus feature — it's part of distribution, and it needs wiring on day one. Add it after you have users and the migration cost plus support cost will teach you a lesson — old versions without an update client can't even receive your pushes.

  • electron-updater (Squirrel-based): the most mature ecosystem. GitHub Releases works directly as the update feed, configuration is a few lines, delta updates and resumable downloads come free. Note that Squirrel.Mac on macOS requires the app to be signed — back to section 2: signing is the foundation, and without it updates won't even run.
  • Tauri updater plugin: built around a minisign keypair. tauri signer generate creates .key (private) and .key.pub (public — its contents go into tauri.conf.json, not a file path). In CI, sign via the TAURI_SIGNING_PRIVATE_KEY (and TAURI_SIGNING_PRIVATE_KEY_PASSWORD) environment variables — the official docs explicitly note that .env files do not work here; real environment variables only. Set createUpdaterArtifacts to true and the build auto-generates signed update bundles with .sig files plus a latest.json manifest; point endpoints at the latest.json on GitHub Releases and tauri-action uploads it to the Release automatically. On Windows there's also an installMode choice: passive (progress bar, no interaction — recommended) vs. quiet.

Here's the red line — listen carefully: lose your updater private key and you permanently lose the ability to push updates to installed users. Tauri's official docs put it bluntly: never share the private key with anyone; lose it and you cannot publish updates to users who already have the app. Your only recourse then is begging users via announcements to manually download and reinstall — a disaster for an indie developer. So: private key into a password manager, plus an offsite backup. This is infrastructure-level stuff; don't just leave it in ~/.tauri on some laptop. Before wiping a machine or reinstalling the OS, confirm the key is backed up.

Don't forget permissions: Tauri v2's capability model requires explicitly declaring updater:default, updater:allow-check, updater:allow-download-and-install and friends in capabilities. Undeclared, and frontend update API calls get rejected outright. That's part of the v2 security model, not a bug.

Advanced play: Tauri endpoints support {{target}} / {{arch}} / {{current_version}} variables, so the server can do staged rollouts and rollbacks per version — even switching endpoints and public keys at runtime. Beta channel isolation runs on exactly this; section 7 expands it.

Update UX deserves thought too. The recommended combo: one silent check at launch (no interrupting popup), a manual "Check for updates" entry in the menu or settings, and a dialog with real release notes letting the user pick "Update now" or "Later" when something's available. The Tauri updater plugin ships a built-in dialog, or you can turn it off and wire your own events into a progress bar. Never be that app: silently downloading in the background, force-installing on quit, losing user configs on restart. Every brutal update spends down users' trust in the words "auto-update."

5. Four Distribution Channels: Cost vs. Trust

Your bundle is signed, updates are wired — where does the user get the first installer? Four channels, ranked by cost and trust. Note these aren't multiple choice; it's a combo:

ChannelCostTrustBest for
Direct from your websiteA domain + object storageRests entirely on your signing and notarization; an ugly page discounts trust directlyProducts with a brand that need a landing page
GitHub ReleasesZeroHigh trust with developers; regular users hesitate at github.com linksOpen source, dev tools; doubles as your update feed — two birds
Homebrew caskZero (maintain your own tap, one formula file)Maximum trust with Mac developers; one-command installThe indie developer's trust lever
winget / MSIXwinget is free (submit a PR); MSIX packaging is fiddlyHigh trust with Windows users; MSIX fits enterprise procurement checklistsReaching regular Windows users / enterprise customers

A real case: whrss on VibeFix — an indie developer who "vibed" four Swift menu-bar utilities in a week with AI, put all of them through Apple Developer ID signing and notarization, made them download-extract-and-double-click ready, had each app check GitHub Releases for updates itself, and installed via a single brew install --cask whrss9527/tap/pop. Signing + notarization solves "it opens," Homebrew solves "I dare install it," GitHub Releases solves "it stays updated" — the full trio, with big-company distribution polish from a one-person team.

Homebrew cask deserves a few more words: for Mac developers it's the highest-trust zero-cost channel. No review to pass — maintain your own tap repo, point the cask file at your GitHub Releases artifacts, done. Users get one-command installs, a far better experience than hunting for a download button on your site. Same for winget: one PR to winget-pkgs and Windows users winget install your app. Your website's landing page has one job: detect the visitor's OS and shove the right download button in their face — every year, sites that make Mac users hunt for the .exe talk a batch of people out of installing.

My recommendation: the indie starter pack is GitHub Releases (update feed) + Homebrew cask (Mac acquisition) + winget (Windows acquisition) + website landing page (brand home). Take all four; total cost is near zero and the trust compounds. The website is the storefront; the other three are plumbing.

One often-missed mutual exclusion: if you plan to ship via the Mac App Store or Microsoft Store, don't roll your own auto-update — store policies forbid self-updating apps, and Tauri's official docs state the updater plugin is restricted on mobile and store channels. Store distribution and direct distribution are two routes; pick one and wire up its full kit. Don't mix and match.

6. The CI Packaging Pipeline: Configure Once, Ship Forever

Manual packaging gets annoying the third time, error-prone the tenth, and by the twentieth you'll be skipping a platform's signature. A three-platform GitHub Actions matrix is the standard answer — configure once, benefit forever:

  • Matrix: macos-latest (arm64 and x86_64 targets — Tauri's official template does exactly this), ubuntu-22.04, windows-latest; fail-fast: false so one broken platform doesn't kill the other two. Note Linux builds need system deps like webkit2gtk installed first — Tauri's official template includes the apt commands; just copy them.
  • Secrets for keys: APPLE_CERTIFICATE (base64-encoded .p12), APPLE_CERTIFICATE_PASSWORD, TAURI_SIGNING_PRIVATE_KEY, WINDOWS_CERTIFICATE, etc. Reference only via ${{ secrets.XXX }} in the workflow — never echo one; a single leak in logs means revoke and reissue. Also grant the workflow contents: write, or tauri-action fails creating the Release with "Resource not accessible by integration" — a gotcha Tauri's official guide lists explicitly.
  • tauri-action: the officially maintained Action — one step runs tauri build, uploads artifacts, and creates the GitHub Release. Tauri's official distribution guide ships a copy-paste workflow template: checkout → install Node → install Rust (with swatinem/rust-cache caching, roughly doubling build speed) → install frontend deps → tauri-apps/tauri-action@v1. Trigger on tag pushes (app-v* or v*); shipping becomes git tag v1.2.0 && git push --tags, then collect your Release in ~20 minutes.

Electron folks take Electron Forge / electron-builder — identical shape: matrix build → sign (@electron/windows-sign / @electron/osx-sign) → notarize (@electron/notarize) → upload to Release. Different tools, same runway. Electron's official code-signing doc lists the wiring for Forge, Packager, Builder, Squirrel.Windows, and WiX MSI each — match your setup and go.

A ritual suggestion: savor the moment you push the tag the first time the pipeline goes green. From that day on, shipping stops being "an afternoon of manual labor" and becomes a single command. Your vibe project now has industrial-grade release capability — and you're still just one person.

Once the pipeline is green, make it foolproof: write a release script that does three things in one command — bump the version in all three places per semver (tag, tauri.conf.json, package.json; mismatches are a classic cause of dead update checks), draft a changelog from git log, tag and push to trigger the pipeline. Tauri's official template has a thoughtful touch: releaseDraft: true creates the Release as a draft first — you inspect the artifacts, then publish manually. Strongly recommended while you're new; turn it off once you fully trust the pipeline.

7. Versioning and Update Channels: The Social Contract of Shipping

With auto-update in play, the version number is your contract with users. Break it carelessly and you pay.

A real-world lesson first: many indie developers wing the version on their first release — jumping from 1.0 straight to 2.0, or mixing beta and stable on the same update feed. Then one morning users wake up to a transformed UI and dead plugins — because a MAJOR bump should have been their choice to make. Semver isn't bureaucracy; it's self-restraint for when you're deciding on users' behalf.

  • Follow semver, strictly: MAJOR.MINOR.PATCH. Breaking changes must bump MAJOR — don't sneak a shortcut change or feature removal into a PATCH. Auto-updated users never got the "read the notes and decide" moment; you decided for them, so own the consequences. Especially on desktop, where rollback is far harder than on the web.
  • Isolate beta channels: stable and beta get different update endpoints. Tauri's dynamic endpoints natively fan out on {{current_version}} — the server pushes to whoever it wants; electron-updater has channel config too. The iron rule: beta users never receive stable pushes, stable users never receive beta pushes. Offer an explicit switch for changing channels; never switch silently. Tauri's updater even supports changing endpoints and public keys at runtime — enough for canary and staged rollouts.
  • Force updates for exactly one reason: security vulnerabilities. Day to day, use "remind me + later" (the Tauri updater dialog or your own popup) and leave the choice with the user; reserve silent installs and install-on-launch for enterprise-internal distribution. Force-update a consumer product once and your reviews gain a "the update wiped my configs" — not scaremongering, it's a recurring headline in those review sections. Back up user data before updating, verify configs survive after — that's table stakes.
  • Write release notes like a human: in latest.json notes and Release notes, "fixed garbled Chinese characters when exporting PDF" retains users better than "bug fixes and improvements." Two human sentences cost nothing and get users to click "Update now" instead of "Remind me later." Five minutes on release notes per ship is the highest-ROI work you'll do.

8. The 12-Item Pre-Release Checklist

Print it (or keep it as CHECKLIST.md in the repo) and tick every box, every release. Don't find it tedious — each skipped item costs users. Better yet, put the checklist in CI too: automate what you can (signature verification, version consistency, update-package signature checks) as workflow jobs — machines are more reliable than humans. Keep only what truly needs hands (clean-environment testing, release notes) for a focused half hour on ship day:

  • 1. All three platform installers install and launch on a clean VM / fresh user account (not your dev machine — it has every certificate already, it proves nothing)
  • 2. macOS: spctl -a -vvv confirms Gatekeeper lets it through; stapler validate confirms the ticket is stapled
  • 3. Windows: on a machine that's never seen your certificate, confirm SmartScreen shows a verified publisher, not "unknown"
  • 4. Signatures carry timestamps (historical versions stay trusted after cert expiry — that sentence from section 3, verify it)
  • 5. Auto-update: full end-to-end from the previous stable to this candidate (download, verify, install, relaunch)
  • 6. Update signature check: tamper one byte of an update package and confirm the client refuses it (don't let the update channel become an attack vector)
  • 7. Version follows semver and matches in all three places: tag, tauri.conf.json, package.json
  • 8. Beta/stable channel isolation verified (neither receives the other's builds)
  • 9. Release notes written by a human (non-empty, not "bug fixes")
  • 10. Rollback plan: if this release has a critical bug, can you ship a higher-versioned fix (when downgrades aren't allowed); Tauri's dynamic update server can push a rollback server-side
  • 11. Website download page / Homebrew cask / winget links point at the new Release (don't serve users the old build)
  • 12. Release announcement ready: what's new, known issues, where to give feedback (users knowing where to find you matters more than the bug itself)

One final restatement of this guide's core judgments: default to Tauri, always configure the timestamp server, guard the updater private key like infrastructure, take all four channels. There's no silver bullet on the distribution runway — but once you've walked it, every vibe project you build gets a road from "built" to "shipped." Next time AI writes you an app in an evening, you push a tag, and twenty minutes later your users get the update. That's what vibe coding was supposed to end with.

Paving the runway isn't one-and-done, either — there are two "annual inspections": Apple Developer membership renewal (lapse it and certificates plus notarization stop together; set a reminder a month ahead), and your Windows certificate or signing service renewal. Put both dates in your calendar next to domain renewals. Distribution is like plumbing and electricity — invisible until it breaks, and fixing it always takes days.

Views 0Comments 0

Comments (0)

ME
0/1000
Loading comments...
Browse projectsPublish your project

Related articles

Neon 'Sorry We're Closed' sign photographed in a shop window at dusk, symbolizing a graceful feature sunset
Guide
Saying Goodbye Gracefully: The Feature Sunset Playbook for Vibe Projects

Vibe developers ship fast but rarely shut down cleanly — zombie features quietly eat all maintenance time. This guide turns sunsetting into a launch in reverse: the three sunset questions, a 30/90-day announcement window, data export scripts, pro-rata refunds, farewell email templates, 301 redirect maps, code archiving, and a 12-item acceptance checklist.

Payments & MonetizationDeploymentIndie Development
Blurred close-up of source code on a dark editor screen, glowing syntax colors
Guide
GraphQL vs tRPC for Vibe Projects: Picking the Right API Layer

AI writes REST fast and sloppy — one renamed field crashes frontend and backend together. This guide gives solo TypeScript teams a clear stance: default to tRPC for free end-to-end type safety, switch to GraphQL only on three signals. Includes a runnable tRPC + Next.js setup, schema-first GraphQL with codegen, the DataLoader fix for AI-generated N+1 resolvers, depth-limit and complexity guardrails, auth via middleware vs directives, the decision tree, and a 5-step REST-to-tRPC migration SOP.

Backend EngineeringProject BuildingIndie Development
Screenshot of a form builder drag-and-drop interface: field component palette on the left, canvas in the middle, properties panel on the right
Guide
Building a Form Builder for Your Vibe Project: Schema, Render Engine, and Drag-and-Drop

Questionnaires, sign-ups, applications… once your vibe project grows its third form, hand-written maintenance starts to spiral. This hands-on guide builds a form builder from zero: JSON Schema as the data contract, UI schema for layout, a type-to-component registry for rendering, a rule engine for conditional logic, plus the drag-and-drop canvas and schema versioning — with an AJV/zod decision guide and a launch checklist.

Developer WorkflowProject BuildingIndie Development