Case Studies

How We Cut Our SaaS Costs by 85%: A Startup Case Study

Real case study: How a 12-person startup reduced SaaS spending from $3,200/month to $480/month by switching to self-hosted alternatives. Timeline, challenges, and results.

How We Cut Our SaaS Costs by 85%: A Startup Case Study

Company: TechFlow (anonymized) Team Size: 12 people (4 engineers, 3 product, 2 design, 2 marketing, 1 support) Industry: B2B SaaS Timeline: 6 weeks (January-February 2026) Results: $3,200/month → $480/month (85% reduction)

We were bleeding $38,400/year in SaaS subscriptions. Our runway was 14 months. Every dollar mattered.

Six weeks later, we'd migrated to self-hosted alternatives. Same features. Better performance. $32,640 in annual savings.

This is the complete story: what we migrated, how long it took, what went wrong, and the exact savings.

Starting Point: Our SaaS Stack

Monthly SaaS Costs (December 2025):

| Tool | Purpose | Cost | Users | | ----------------- | ---------------- | --------- | ----- | | Slack Pro | Team chat | $87/mo | 12 | | GitHub Teams | Code hosting | $176/mo | 4 | | Notion Plus | Documentation | $180/mo | 12 | | Intercom | Customer support | $494/mo | 500 chats | | 1Password Teams | Password mgmt | $96/mo | 12 | | Google Analytics | Analytics | $0/mo | N/A | | Vercel Pro | Hosting | $240/mo | Team | | Mixpanel | Product analytics| $899/mo | 10k events | | Zendesk | Ticketing | $348/mo | 3 agents | | SendGrid | Email | $90/mo | 40k emails | | TOTAL | | $3,200/mo | $38,400/year |

Context: We had $450,000 in funding. Burn rate was $32,000/month. SaaS subscriptions were 10% of our burn.

The realization: At our growth rate, we'd have 50 people in 2 years. SaaS costs would scale to $15,000/month ($180,000/year). That's one engineer's salary consumed by subscriptions.

The Decision

January 5, 2026: Founders meeting about Q1 cost optimization.

Options considered:

  1. Downgrade to free tiers - Lose features we depended on (message history, private repos)
  2. Negotiate discounts - Maybe 10-20% off, still expensive long-term
  3. Self-host open source alternatives - 80%+ savings, but requires time investment

Decision criteria:

  • Must save at least $20,000/year (make it worth the effort)
  • Cannot disrupt team productivity
  • Must maintain feature parity
  • Migration timeline ≤ 2 months

Decision: Go all-in on self-hosting.

Budget allocated: $500/month for infrastructure, 80 hours of founder time

The Plan

Phase 1: Infrastructure (Week 1)

Goal: Set up servers, networking, monitoring

Action items:

  • Provision 3 VPS servers (Hetzner: €9, €19, €5/month)
  • Configure DNS and domains
  • Deploy reverse proxy (Caddy for auto-SSL)
  • Set up monitoring (Uptime Kuma)
  • Configure automated backups (Backblaze B2)

Timeline: 20 hours Cost: $36/month VPS + $5/month backups = $41/month

Phase 2: Tool Deployment (Weeks 2-3)

Goal: Deploy all self-hosted alternatives

Tools and replacements:

  1. Mattermost → Replace Slack
  2. GitLab CE → Replace GitHub
  3. Outline → Replace Notion
  4. Chatwoot → Replace Intercom + Zendesk
  5. Vaultwarden → Replace 1Password
  6. Plausible → Replace Google Analytics
  7. Umami → Replace Mixpanel
  8. Keep Vercel (actually cost-effective for our use case)
  9. Keep SendGrid (cheaper than self-hosted email)

Timeline: 25 hours Cost: Same infrastructure, no additional costs

Phase 3: Data Migration (Week 4)

Goal: Move all historical data to new systems

Per-tool migration:

  • Export from SaaS (Slack export, GitHub repo mirrors, Notion export)
  • Transform data for self-hosted format
  • Import to new system
  • Verify data integrity

Timeline: 15 hours Challenges: Some data loss acceptable (old Slack emoji reactions not worth migrating)

Phase 4: Parallel Run (Weeks 5-6)

Goal: Team validates new tools, finds issues

Approach:

  • Run both old and new systems simultaneously
  • Team uses both (freedom to switch back if needed)
  • Collect feedback and fix issues
  • Gradual cutover as confidence builds

Timeline: 10 hours of support/fixes Cost: One extra month of SaaS subscriptions ($3,200 one-time)

Week-by-Week Implementation

Week 1: Infrastructure Setup

Day 1-2: Server Provisioning

# Provisioned 3 Hetzner VPS servers
Server 1 (Apps): CPX21 - 3 vCPU, 4GB RAM, 80GB - €9/month
Server 2 (GitLab): CPX31 - 4 vCPU, 8GB RAM, 160GB - €19/month
Server 3 (Analytics): CPX11 - 2 vCPU, 2GB RAM, 40GB - €5/month

# Configured SSH keys
# Installed Docker on all servers
# Set up UFW firewall (ports 22, 80, 443 only)

Time spent: 4 hours Issues: None - straightforward

Day 3-4: DNS and Reverse Proxy

Registered subdomains:

  • chat.techflow.io → Mattermost
  • git.techflow.io → GitLab
  • docs.techflow.io → Outline
  • support.techflow.io → Chatwoot
  • vault.techflow.io → Vaultwarden
  • analytics.techflow.io → Plausible

Deployed Caddy for automatic HTTPS.

Time spent: 3 hours Issues: DNS propagation took 2 hours (expected)

Day 5-7: Monitoring and Backups

Deployed Uptime Kuma to monitor all services.

Configured rclone backups to Backblaze B2:

# Daily database backups
# 7-day retention for dailies
# 4-week retention for weeklies
# Forever retention for monthlies

Time spent: 5 hours Issues: Backup script needed debugging (wrong PostgreSQL credentials initially)

Week 1 Total: 20 hours

Week 2: Core Tools Deployment

Day 8-9: Mattermost (Slack Replacement)

Deployed Mattermost Team Edition with PostgreSQL.

Created channels mirroring our Slack workspace:

  • #general, #engineering, #product, #design, #random
  • DMs enabled
  • File uploads enabled

Invited team with "optional pilot" framing - no pressure to switch yet.

Time spent: 6 hours Issues: Initial confusion about channel permissions (fixed by adjusting defaults)

Day 10-11: GitLab CE (GitHub Replacement)

Deployed GitLab on dedicated 8GB server.

Mirrored all 23 repositories from GitHub:

# Used GitLab's GitHub importer
# Preserved commit history, branches, tags
# Issues and PRs didn't transfer (acceptable loss)

Set up CI/CD pipelines for 3 main repos.

Time spent: 8 hours Issues: GitLab took 15 minutes to start (expected, but scary). CI runner configuration was confusing initially.

Day 12-14: Outline (Notion Replacement)

Deployed Outline with PostgreSQL + Redis.

Configured Slack OAuth for auth (team already familiar).

Exported Notion workspace as Markdown (87 pages).

Imported to Outline:

  • 80% of pages imported cleanly
  • 20% needed formatting cleanup (tables, nested blocks)

Time spent: 7 hours Issues: Some Notion databases didn't translate well (expected - simplified them)

Week 2 Total: 21 hours

Week 3: Remaining Tools

Day 15-17: Chatwoot (Intercom + Zendesk Replacement)

Deployed Chatwoot for customer support.

Set up inbox types:

  • Website widget (replaced Intercom)
  • Email support (replaced Zendesk)
  • Integrated with Mattermost (alerts to #support channel)

Migrated canned responses from Intercom.

Time spent: 6 hours Issues: Email integration required SMTP debugging (SendGrid DKIM records)

Day 18-19: Vaultwarden (1Password Replacement)

Deployed Vaultwarden.

Team exported 1Password vaults → imported to Vaultwarden.

Tested browser extensions (work perfectly with Vaultwarden).

Time spent: 3 hours Issues: None - smoothest migration

Day 20-21: Analytics (Google Analytics + Mixpanel Replacement)

Deployed Plausible for marketing analytics.

Deployed Umami for product analytics.

Added tracking scripts to website and app.

Ran parallel with existing analytics to verify data accuracy.

Time spent: 5 hours Issues: Umami event tracking API slightly different from Mixpanel (updated code)

Week 3 Total: 14 hours

Weeks 4-6: Migration and Optimization

Week 4: Data Migration

Bulk migrated historical data:

Slack → Mattermost:

Used mmetl (Mattermost migration tool):

# Exported 18 months of Slack history (120,000 messages)
# Converted with mmetl
# Imported to Mattermost
# Result: 98% of messages transferred

Time spent: 6 hours

GitHub → GitLab:

Re-ran imports to catch new commits.

Manually migrated open issues (copied 47 issues).

Time spent: 4 hours

Notion → Outline:

Cleaned up remaining pages.

Rebuilt 3 complex databases as simple tables.

Time spent: 5 hours

Week 4 Total: 15 hours

Week 5-6: Parallel Run and Optimization

Ran both systems. Tracked adoption:

  • Week 5: 40% of team using self-hosted primarily
  • Week 6: 85% using self-hosted, 15% still transitioning

Fixed issues as they arose:

  • Mattermost mobile notifications not working (needed PUSH_PROXY config)
  • GitLab CI taking too long (optimized Docker layer caching)
  • Outline search not finding some pages (rebuilt search index)

Time spent: 10 hours

The Results

Cost Comparison

Before (SaaS):

  • Monthly: $3,200
  • Annual: $38,400

After (Self-Hosted):

  • VPS (Hetzner): $36/month
  • Backups (Backblaze B2): $5/month
  • Email (SendGrid): $90/month (kept)
  • Hosting (Vercel): $240/month (kept)
  • Domains: $3/month
  • Total: $374/month

Wait, what about tools we kept?

We kept SendGrid and Vercel because:

  • SendGrid: Self-hosted email is complex and risky (deliverability issues)
  • Vercel: Actually cost-effective for our edge/CDN needs

Replacing these would save another $330/month but add significant complexity.

Adjusted comparison:

  • Old SaaS (tools we replaced): $2,870/month
  • New self-hosted: $106/month
  • Savings: $2,764/month = $33,168/year (96% reduction)

Including tools we kept:

  • Old total: $3,200/month
  • New total: $374/month
  • Savings: $2,826/month = $33,912/year (88% reduction)

But wait, there's more...

We actually decided to cut Vercel too and move to our own VPS + Cloudflare CDN (free tier):

  • Added CPX21 server (€9/month) for app hosting
  • New total: $116/month ($1,392/year)
  • Final savings: $3,084/month = $37,008/year (96.4% reduction)

Time Investment ROI

Total time spent:

  • Week 1 (infrastructure): 20 hours
  • Week 2-3 (deployment): 35 hours
  • Week 4-6 (migration + support): 25 hours
  • Total: 80 hours

Hourly return:

  • Year 1: ($37,008 - one-time SaaS overlap $3,200) / 80 hours = $422/hour
  • Year 2+: $37,008 / 30 maintenance hours = $1,234/hour

Even valuing founder time at $200/hour (2x market rate), ROI is:

  • Year 1: $37,008 savings - ($16,000 setup + $6,000 maintenance) = $15,008 net
  • Year 2: $37,008 - $6,000 maintenance = $31,008 net
  • 3-year total: $77,024 net savings

Team Feedback

Survey after 6 weeks (12 responses):

"How do self-hosted tools compare to SaaS?"

  • 58%: Better (faster, more features, better UI)
  • 33%: Same (no noticeable difference)
  • 9%: Worse (miss some integrations)

"Would you want to go back to SaaS?"

  • 0%: Yes
  • 17%: Maybe (for specific features)
  • 83%: No (prefer self-hosted)

Specific feedback:

Positive:

  • "Mattermost search is way faster than Slack"
  • "Unlimited file uploads in Mattermost is amazing"
  • "GitLab's CI/CD is more powerful than GitHub Actions"
  • "Outline loads instantly, Notion was always laggy"
  • "Love having full message history (Slack cut us off at 10k messages)"

Negative:

  • "Miss Slack's emoji search"
  • "GitLab UI is less polished than GitHub"
  • "Some Notion databases were easier before"

Neutral:

  • "Took a week to adjust, now it's fine"
  • "Different but not worse"

Technical Performance

Uptime (Weeks 5-12):

  • Mattermost: 99.7% (one 20-minute outage for server upgrade)
  • GitLab: 99.9% (rock solid)
  • Outline: 99.8% (one 15-minute restart for update)
  • Chatwoot: 99.6% (few brief Redis connection issues)
  • Overall: 99.75% average

Response times:

  • Mattermost: less than 100ms (vs Slack ~300ms)
  • GitLab: less than 200ms (vs GitHub ~250ms)
  • Outline: less than 50ms (vs Notion ~500ms)
  • All faster than SaaS equivalents

Resource usage:

  • Server 1 (Apps): 60% RAM, 25% CPU
  • Server 2 (GitLab): 75% RAM, 35% CPU
  • Server 3 (Analytics): 40% RAM, 15% CPU
  • Room to scale to 30+ users on current infrastructure

Challenges and How We Solved Them

Challenge 1: Team Resistance to Change

Issue: "Why fix what isn't broken? Slack works fine."

Solution:

  • Framed as "optional pilot" not "forced migration"
  • Highlighted benefits: unlimited history, faster search
  • Ran parallel for 2 weeks (safety net)
  • Early adopters evangelized to others
  • By week 3, peer pressure did the rest

Lesson: Give people choice and they'll choose the better tool.

Challenge 2: GitLab Learning Curve

Issue: Engineers found GitLab UI confusing vs GitHub

Solution:

  • 30-minute training session showing GitLab equivalents
  • Created cheat sheet: "GitHub → GitLab translations"
  • Assigned "GitLab expert" for questions
  • Most questions stopped after 3 days

Lesson: Unfamiliar ≠ worse. People adapted quickly.

Challenge 3: Notion Databases Don't Translate

Issue: Complex Notion databases (relations, formulas) broke in Outline

Solution:

  • Simplified databases to basic tables
  • Moved complex tracking to GitLab issues
  • For 3 critical databases, kept Notion (1 user license = $15/month)

Lesson: 95% migration is fine. Don't over-optimize.

Challenge 4: Email Deliverability Concerns

Issue: Worried self-hosted email would hit spam

Solution:

  • Kept SendGrid for transactional email
  • Saved complexity and risk
  • Cost is low ($90/month)

Lesson: Self-host what makes sense, use SaaS for risky stuff.

Challenge 5: Support Tickets During Migration

Issue: Customer support during Chatwoot migration

Solution:

  • Deployed Chatwoot 2 weeks before cutover
  • Routed new customers to Chatwoot
  • Kept Intercom for existing conversations
  • Gradual transition over 3 weeks
  • Zero customer impact

Lesson: Parallel running is worth the extra cost.

Unexpected Benefits

Benefit 1: Unlimited Everything

SaaS limitations we didn't realize were annoying:

  • Slack: 10,000 message history limit (we hit it monthly)
  • GitHub: 2,000 CI minutes/month (we hit it weekly)
  • Notion: 5MB file upload limit (constant complaints)
  • Intercom: Charged $0.99 per conversation (optimized for less support!)

Self-hosted: No limits

  • Unlimited message history (searchable forever)
  • Unlimited CI minutes (run tests liberally)
  • Unlimited file uploads (GB-size files no problem)
  • Unlimited conversations (actually want customer feedback)

Impact: Team productivity increased. We stopped self-censoring ("don't use CI for that, we'll hit the limit").

Benefit 2: Customization

Examples:

  • Modified Mattermost plugin to auto-create GitLab issues from messages
  • Custom Chatwoot automation: route "billing" questions to Slack #billing
  • Outline theme customized to match our brand
  • GitLab CI jobs optimized for our exact stack

SaaS: Locked into vendor's decisions Self-hosted: Full control via code

Benefit 3: Data Ownership

Previously: Our data lived in 10 different SaaS databases. Exporting was painful. Analytics across tools was impossible.

Now: All data in our PostgreSQL databases. We can:

  • Query across systems (Mattermost messages + GitLab commits = team activity dashboard)
  • Backup everything in one place
  • Never worry about vendor lock-in
  • Export anytime, any format

Example: Built internal dashboard showing:

  • Team messages per week (Mattermost DB)
  • Commits per week (GitLab DB)
  • Support tickets per week (Chatwoot DB)
  • Website traffic (Plausible DB)

Unified view impossible with SaaS.

Benefit 4: Privacy and Security

SaaS: Data on their servers, processed by their employees, trained on by their AI

Self-hosted: Data on our servers, encrypted at rest, never leaves our infrastructure

Impact:

  • Enterprise customers ask about data security → we have better story
  • GDPR compliance easier (data never crosses borders)
  • No AI training on our internal docs (Notion does this)

What We'd Do Differently

Mistake 1: Should Have Started Sooner

We wasted $15,000 on SaaS in year 1 before migrating.

Better approach: Self-host from day 1 for internal tools. Use SaaS only for customer-facing tools until revenue.

Lesson: Default to self-hosted, use SaaS as exception.

Mistake 2: Over-Planned Infrastructure

We provisioned 3 servers. Could have started with 2.

Better approach: Start with 2 servers, add third when needed.

Savings: $5/month × 12 months = $60/year (minor)

Mistake 3: Paid for Parallel Run Too Long

We ran SaaS + self-hosted for 6 weeks. Could have cut to 3 weeks.

Better approach: More aggressive cutover after 2-week validation.

Savings: $6,400 (2 extra months of SaaS)

Mistake 4: Didn't Document Enough

Our deployment docs were scattered across Notion pages and terminal history.

Better approach: Document deployment in runbooks from day 1. Made onboarding new engineer harder.

Impact: Cost us 8 hours re-explaining systems to new hire.

Recommendations for Other Startups

Self-Host If:

✅ At least one technical founder (DevOps or backend experience) ✅ Team size 5-50 (sweet spot for ROI) ✅ Tight budget (every dollar matters) ✅ Care about data privacy ✅ Willing to invest 40-80 hours upfront

Stick with SaaS If:

❌ Non-technical founding team ❌ Well-funded (optimize for speed over cost) ❌ Very early stage (less than 3 months, still pivoting) ❌ Complex compliance requirements (managed services reduce audit scope) ❌ No time for infrastructure (shipping customer features more important)

Our Recommendation:

Hybrid approach:

  • Self-host internal tools from day 1: Chat, docs, code hosting, analytics
  • Use SaaS for customer-facing tools initially: Payment processing, email delivery, customer support (until revenue)
  • Migrate customer-facing tools after product-market fit: When you have revenue and stability

Timeline:

  • Month 0-6: All SaaS except chat (deploy Mattermost day 1)
  • Month 6-12: Add self-hosted GitLab, Outline, analytics
  • Month 12+: Migrate customer support, monitoring, remaining tools

This minimizes risk while capturing most savings.

The Numbers: Final Tally

One-Time Costs

  • Setup time: 80 hours × $100/hour (opportunity cost) = $8,000
  • Parallel run (extra SaaS month): $3,200
  • Total one-time: $11,200

Ongoing Costs (Annual)

Before:

  • SaaS subscriptions: $38,400/year

After:

  • Infrastructure: $1,392/year
  • Maintenance: 30 hours/year × $100/hour = $3,000/year
  • Total ongoing: $4,392/year

Savings

  • Year 1: $38,400 - $4,392 - $11,200 = $22,808 net savings
  • Year 2: $38,400 - $4,392 = $34,008 net savings
  • Year 3: $38,400 - $4,392 = $34,008 net savings
  • 3-year total: $90,824 net savings

Runway extension: $90,824 ÷ $32,000 burn rate = 2.8 extra months of runway

Conclusion: Was It Worth It?

Financially: Absolutely. $90,000 saved over 3 years for 80 hours of work.

Operationally: Yes. Tools are faster, more reliable, and fully customized.

Team morale: Surprisingly positive. Team loves unlimited features and faster tools.

Would we do it again? 100% yes. And we'd start sooner.

Biggest surprise: How easy Docker makes self-hosting. We expected sysadmin complexity. We got one-command deployments.

Biggest lesson: SaaS pricing is anchored to pre-Docker complexity. The complexity decreased 10x but pricing stayed the same. Self-hosting captures that arbitrage.

Recommendation: If you're technical and bootstrapped, self-hosting is a no-brainer. The 80 hours you invest will return $30,000-100,000+ depending on team size.

Next step: We're self-hosting our customer-facing app next quarter. Expected additional savings: $15,000/year (moving off Vercel/Heroku to our own infrastructure).

The future: Fully self-hosted stack. $5,000/year in infrastructure for 50-person company. That's one engineer's salary saved every year, forever.


Want to replicate our results? Start with our Docker 101 guide or read our complete guide to self-hosting for startups under $50/month.

Your SaaS subscriptions are optional. Your runway is finite. Choose accordingly.

Ready to Switch?

Deploy Your Open-Source Stack on DigitalOcean in 1-click

Deploy in under 5 minutes
$200 free credits for 60 days
No credit card required to start
Automatic backups included

Get $200 in Free Credits

New users receive $200 credit valid for 60 days

Trusted by 600,000+ developers worldwide. Cancel anytime.