5 min read
On this page

Deploy Daily

If deploying is scary, you deploy less often. If you deploy less often, each deploy contains more changes. If each deploy contains more changes, the risk of breaking something goes up. If the risk goes up, deploying becomes scarier. This is the deployment fear cycle, and it kills startups slowly by turning shipping into an event instead of a habit.

The fix is counterintuitive: deploy more, not less. Deploy every day. Deploy multiple times per day. Make deploys so small and so routine that nobody even notices they happened.

The Deployment Fear Cycle

The vicious cycle:
  Scary deploy → Deploy less often → Bigger changes per deploy →
  More things break → Deploys get scarier → Deploy even less often →
  Even bigger changes → ...

The virtuous cycle:
  Small deploy → Nothing breaks → Deploy again → Confidence grows →
  Deploy more often → Changes get smaller → Even less breaks → ...

This is not theory. This is the core finding of the DORA (DevOps Research and Assessment) metrics research: elite engineering teams deploy on demand (multiple times per day), and they have lower failure rates than teams that deploy weekly or monthly. Smaller batches are safer batches.

What Daily Deployment Looks Like

A day in a daily-deploy team:
  09:30  Engineer A merges a bug fix. CI runs. Auto-deploys to production.
  11:00  Engineer B merges a new feature (behind a flag). Auto-deploys.
  14:00  Engineer A merges a database index. Auto-deploys.
  15:30  Engineer B merges a copy change. Auto-deploys.
  16:00  Engineer A enables the feature flag for 10% of users.

  Total deploys: 4
  Total incidents: 0
  Total drama: 0

Each deploy is small. Each deploy changes one thing. If something breaks, you know exactly what caused it because you changed exactly one thing since the last known-good state.

GitHub deploys hundreds of times per day. Shopify deploys over 80 times per day. Etsy pioneered continuous deployment and became the model for the practice. These are large companies now, but they started this practice when they were small. The habit scales up; it does not need to start large.

Prerequisites for Daily Deployment

You do not need a sophisticated platform to deploy daily. You need four things:

Minimum requirements:
  1. Automated deployment (one command or automatic on merge)
  2. Basic automated tests (catch the obvious regressions)
  3. Health checks (know if the deploy broke something)
  4. Rollback capability (undo a bad deploy in under 5 minutes)

Automated Deployment

Simplest possible setup:
  - Push to main branch
  - GitHub Actions runs tests
  - If tests pass, deploy automatically

  For a simple app on Railway, Vercel, or Fly.io:
    Push to main → Platform detects change → Builds → Deploys
    Total setup time: 30 minutes

  For a VPS:
    Push to main → GitHub Action SSHs to server → Pulls code → Restarts
    Total setup time: 1 hour

If your deploy process has manual steps ("SSH into the server, pull the latest, run migrations, restart the service"), automate them. Every manual step is a step that can be forgotten, done wrong, or done differently each time.

Basic Tests

You do not need 100% test coverage. You need tests for the things that would be embarrassing to break:

Minimum test coverage for daily deploys:
  - Can users sign up and log in?
  - Can users perform the core action (whatever your product does)?
  - Do payments process correctly?
  - Do API endpoints return the expected status codes?
  - Does the app start without crashing?

This is probably 10-20 tests. Not 2,000.

Health Checks

After every deploy, verify the application is running:

Health check approaches:
  Simplest: Hit the homepage, verify 200 status code
  Better: Hit a /health endpoint that checks database connectivity
  Best: Run a synthetic transaction (sign up, perform action, verify)

Monitoring tools:
  Free: UptimeRobot (checks every 5 minutes)
  Cheap: Betterstack, Checkly
  Built-in: Most platforms (Vercel, Railway) have basic health checks

Rollback

When a deploy breaks something, you need to undo it fast:

Rollback strategies:
  Platform-based (Vercel, Railway, Fly.io):
    Click "rollback" in the dashboard. Done.

  Git-based:
    git revert HEAD && git push
    CI/CD re-deploys the previous state.

  Container-based:
    Point the load balancer back to the previous container image.

  VPS:
    Keep the previous version's artifacts. Swap the symlink.

Target: rollback in under 5 minutes.

Trunk-Based Development for Small Teams

Feature branches make sense for large teams with complex review processes. For small teams deploying daily, trunk-based development is faster and simpler.

Trunk-based development:
  - Everyone commits to main (or to very short-lived branches)
  - Branches live for hours, not days or weeks
  - Merge daily, ideally multiple times per day
  - Use feature flags to hide incomplete work
  - No long-running branches that diverge and cause merge conflicts

Traditional Git Flow:
  feature/new-dashboard → develop → staging → release → main
  Time from code to production: days to weeks

Trunk-based:
  main → production
  Time from code to production: minutes to hours

Google, Facebook, and LinkedIn all use trunk-based development at massive scale. If it works for a monorepo with thousands of engineers, it works for your two-person team.

Short-Lived Branches

If you use branches, keep them short:

Good branch lifecycle:
  10:00  Create branch from main
  12:00  Open PR
  12:30  Review (quick, because the diff is small)
  13:00  Merge to main
  13:05  Auto-deployed to production

Bad branch lifecycle:
  Monday: Create branch
  Tuesday-Thursday: Keep working on branch
  Friday: Open PR with 800 lines changed
  Next Monday: Reviewer has questions
  Next Wednesday: Finally merge
  Next Thursday: Three merge conflicts with other work

The goal is branches that live for hours, not days. If a feature takes three days to build, merge intermediate progress behind a feature flag every day.

Feature Flags for Incomplete Work

The objection to daily deployment is always: "But the feature isn't done yet." Feature flags solve this completely.

Feature flag for incomplete work:
  if (featureFlags.newDashboard) {
    renderNewDashboard()
  } else {
    renderOldDashboard()
  }

The new dashboard code is in production. It is deployed. It is running.
But no user sees it because the flag is off.

When the feature is ready:
  - Turn the flag on for internal users (dogfooding)
  - Turn it on for 10% of users (canary)
  - Turn it on for everyone (full rollout)
  - Remove the flag and the old code path (cleanup)

This means your main branch is always deployable. There is no "we can't deploy because the feature branch isn't done." Everything is deployed, always. Visibility is controlled separately from deployment.

More detail on feature flags in the next subtopic. The point here is that feature flags are what make daily deployment possible for features that take more than a day to build.

Overcoming Resistance

Common objections and responses:

"We can't deploy without QA testing everything."
  → QA can test behind a feature flag before it's enabled for users.
    Deploy the code. Test it in production. Enable it when QA approves.

"What if we break production?"
  → You will. That's why you have health checks and rollback.
    A small deploy that breaks one thing is fixed in minutes.
    A large deploy that breaks five things takes hours.

"Our database migrations are risky."
  → Separate schema changes from code changes. Deploy the migration
    first (backward-compatible). Deploy the code that uses it second.
    If the code deploy fails, the schema is still compatible.

"We don't have tests."
  → Start with 5 smoke tests for critical paths. You don't need
    comprehensive coverage to deploy daily. You need enough to
    catch catastrophic regressions.

"Management wants a release schedule."
  → Deploy daily to production. "Release" features on the schedule
    management wants by toggling feature flags. Deployment and
    release are separate concerns.

The Deploy Checklist

For teams transitioning to daily deploys, a simple checklist prevents mistakes:

Pre-deploy (automated in CI):
  □ Tests pass
  □ Build succeeds
  □ No secrets in the diff

Post-deploy (automated or manual for first few weeks):
  □ Health check passes
  □ No error rate spike in monitoring
  □ Core user flows still work

If anything fails:
  □ Rollback immediately
  □ Investigate after rollback, not before
  □ Fix the issue and re-deploy

The key discipline: rollback first, investigate second. Do not debug a production incident while users are affected. Undo the damage, then figure out what happened.

Measuring Deployment Health

DORA metrics (simplified for small teams):
  Deployment frequency: How often do you deploy?
    Target: Daily or more

  Lead time for changes: How long from commit to production?
    Target: Under 1 hour

  Change failure rate: What percentage of deploys cause incidents?
    Target: Under 15%

  Time to restore: How long to recover from a failed deploy?
    Target: Under 30 minutes

Track these monthly. Even rough numbers reveal trends.

Common Pitfalls

  • Deploying daily without automated tests. Daily deploys without tests is just breaking production faster. You need at least basic smoke tests before adopting this practice.
  • Deploying daily without rollback capability. If you cannot undo a bad deploy in five minutes, you are not ready for daily deploys. Fix rollback first.
  • Long-running feature branches. A branch that lives for a week is a branch that will have merge conflicts and a scary merge. Use feature flags instead.
  • Deploying database migrations and code changes together. Separate them. Deploy backward-compatible schema changes first. Deploy code changes second. This lets you roll back code without schema conflicts.
  • Treating deployment as a ceremony. If deploying requires a meeting, a sign-off, or a deployment window, you will not deploy daily. Automate the process until it requires zero human coordination.
  • Not monitoring after deploys. Deploying without checking whether the deploy worked is deploying blind. Automated health checks are the minimum.

Key Takeaways

  • The deployment fear cycle is real: less frequent deploys lead to bigger changes, more risk, and more fear. Break the cycle by deploying small changes frequently.
  • Daily deployment requires four things: automated deployment, basic tests, health checks, and rollback capability. None of these are expensive or complex to set up.
  • Use trunk-based development with short-lived branches. Feature flags let you deploy incomplete work to production without exposing it to users.
  • Rollback first, investigate second. Never debug a production incident while users are affected by it.
  • Separate deployment from release. Deploy code continuously. Release features when they are ready by toggling flags. These are different activities with different cadences.