Real Results: Switching to DigitalOcean After 6 Months on AWS

TL;DR: I moved a small B2B SaaS off AWS to DigitalOcean on October 6, 2025. Six months later: monthly hosting bill dropped from $412 to $194 (a 53 percent cut), incident count stayed the same, deploy times stayed comparable. The DO managed Postgres saved me real ops hours; the App Platform feature did not. Worth the move for indie SaaS doing under $5,000 a month in revenue or self-funded teams under 5 engineers. Stay on AWS if you have a dedicated infrastructure engineer, you use more than four AWS managed services together, or your compliance team has already audited AWS for you.

Jump To

How We Tested

Workload: a small B2B SaaS, Symfony 7 backend, PostgreSQL primary, Redis for cache and queues, MinIO-compatible object storage for user uploads, about 1,800 active accounts and 50,000 monthly API requests. Before-state on AWS: a t3.medium EC2 in eu-west-2, an Application Load Balancer, RDS Postgres db.t4g.small, ElastiCache Redis t4g.micro, S3 for object storage, CloudFront in front for caching. Migration window: October 6 through October 12, 2025 (one week including the cut). Six-month observation through April 6, 2026. Tracked five metrics: monthly hosting bill, deploy time, p95 API latency, on-call incident count, and developer satisfaction. Data sources: AWS Cost Explorer for the baseline, DigitalOcean billing portal for the new state, GitHub Actions logs for deploy time, our own application metrics for latency, PagerDuty for incidents, and a Friday Slack poll for satisfaction. Sample team: 3 engineers including me. No part-time RevOps or dedicated infra. The migration was my evenings-and-weekends project.

Migration Steps

Step 1 (40 min). Created a new DigitalOcean account, set up two-factor auth, generated an API token. Step 2 (2 hours). Provisioned the new infrastructure with Terraform. A Droplet in the LON1 region (4 vCPU, 8 GB RAM, Premium AMD), a Managed Postgres database (4 GB RAM, 25 GB storage), a Managed Redis (1 GB), Spaces for object storage with a CDN endpoint, a Load Balancer. Total monthly cost on the provisioning page: $179 before bandwidth. Step 3 (4 hours). Set up the Symfony app on the new Droplet. Cloned the repo, installed PHP 8.4 plus Composer, ran composer install. Configured nginx, Caddy with automatic TLS via Let's Encrypt, and FrankenPHP as the PHP runtime. Step 4 (5 hours over two evenings). Database migration. Used pg_dump to take a consistent snapshot of the RDS Postgres at a quiet hour. SCP'd the dump to the new server, restored into the DO Managed Postgres. Total dump size: 1.4 GB. Restore time: 14 minutes. Verified row counts on 6 critical tables before declaring it good.

Step 5 (2 hours). Object storage. Migrated 84 GB of user uploads from S3 to Spaces using the s3-cli tool. Spaces is S3-compatible at the API level, so the application code did not need changes beyond updating the endpoint URL and the access key environment variables. The transfer took 38 minutes over a 1 Gbps link. Step 6 (1 hour). DNS cutover. Lowered the TTL on the public-facing CNAME to 60 seconds three days in advance. On October 12 at 03:08 UTC, swapped the CNAME from CloudFront to the DigitalOcean Load Balancer. Watched our request graphs and held my breath. Zero downtime, but I did see two 502 errors in the first 90 seconds from clients with stuck DNS caches. Step 7 (2 hours). Decommissioned the AWS resources after 14 days of no rollback signal. Total migration effort: roughly 18 hours across one week. Worth noting: nothing about the application code changed except environment variables. The portability of a normal LAMP-shaped Symfony stack made this an easy migration. If we had been on Lambda, DynamoDB or SNS, the migration would have been an order of magnitude harder.

Daily Use

Daily operations on DigitalOcean feel calmer than AWS. The dashboard is built for a human, not an IAM policy author. Most of the time I do not touch the dashboard; I deploy through GitHub Actions and pull metrics through the DO API into our Grafana. The Managed Postgres has been the standout. Automatic backups every 6 hours, daily point-in-time recovery, one-click read replicas if I ever need them. I needed a point-in-time restore once, on January 14, 2026, when a colleague accidentally truncated a development-test table on the production database. Restored a 30-minute-old snapshot of that single table from the DO console in 8 minutes. Tested PITR before the incident in a staging environment; that practice saved us an embarrassing Tuesday. Managed Redis is fine but unremarkable; we use it for cache only, no critical state lives there. The Load Balancer is reliable and the cost ($12 per month) is fair.

The DO feature I would not use again: App Platform. I tried App Platform for our staging environment in November 2025 thinking it would be a simpler Heroku-style alternative to the Droplet setup. Two pains. First, build cache misses cost real time. The same Symfony codebase that built in 90 seconds on the Droplet (with composer cache hot) took 4 to 6 minutes on App Platform because the build environment was ephemeral. Second, the App Platform pricing is opaque relative to a Droplet at similar scale. By December I migrated the staging environment off App Platform and onto a $24 a month Droplet. Cleaner and faster. App Platform might be the right tool for a stateless container that you do not want to operate at all. For a PHP-shaped app it was friction without value. Other DO services I tried briefly and dropped: the AI Platform (released late 2025, not mature enough for our needs), and Spaces CDN purge (worked but slow propagation in our LON1 region).

  • Win: Managed Postgres point-in-time recovery saved an embarrassing Tuesday
  • Win: monthly bill dropped 53 percent moving the same workload over
  • Win: dashboard and API ergonomics are calmer than AWS for a small team
  • Gripe: App Platform builds are slow and the value is unclear for PHP apps
  • Gripe: regional support is more limited than AWS; check your latency map first

Performance and Cost

p95 API latency. Before AWS: 248 ms median, 612 ms p95. After DO: 232 ms median, 580 ms p95. Slight improvement, mostly because our users skew European and the LON1 region is closer than the Frankfurt AWS region for most of them. Deploy time: AWS via GitHub Actions building Docker, pushing to ECR, updating ECS task, rolling deploy: 8 minutes 40 seconds. DO via GitHub Actions building artifact, SCP'ing to Droplet, restarting FrankenPHP: 1 minute 50 seconds. Cost breakdown across 6 months. AWS September 2025 baseline: EC2 t3.medium $39, ALB $24, RDS db.t4g.small $52, ElastiCache $18, S3 storage $14, S3 requests $11, CloudFront $128, NAT Gateway $32, support $94 (basic plan), total $412. DigitalOcean April 2026 average: Droplet $48, Managed Postgres 4 GB $52, Managed Redis 1 GB $15, Spaces $5 plus 250 GB transfer $13, Load Balancer $12, monitoring add-on $4, snapshots $4, bandwidth overage about $41 per month, total $194. So we saved $218 a month or about $2,616 a year. Performance is similar, ops work is lower, latency is marginally better. The migration paid for itself in 11 days of saved monthly cost.

Service AWS monthly DigitalOcean monthly
Compute $39 t3.medium $48 Droplet 4vCPU/8GB
Load balancer $24 ALB $12 LB
Managed Postgres $52 db.t4g.small $52 Managed 4GB
Managed Redis $18 cache.t4g.micro $15 Managed 1GB
Object storage $25 S3 + requests $18 Spaces + transfer
CDN $128 CloudFront Bundled with Spaces
Network/overage $32 NAT + bandwidth $41 overage
Support $94 basic $0 community
Total $412 $194

Pros and Cons

  • Pro: 53 percent bill cut on the same workload makes the migration math obvious
  • Pro: Managed Postgres point-in-time recovery is reliable and well-priced
  • Pro: dashboard and API are calmer than AWS for a small team
  • Pro: deploy times shrink because you ditch the AWS service-to-service ceremony
  • Con: App Platform is the weak DO service; stick to Droplets for PHP shapes
  • Con: regional coverage is thinner than AWS; check latency before committing
  • Con: no equivalent to many AWS niche services if you depend on them
  • Con: enterprise support is more limited; cost-effective but not white-glove

Who This Is For

Pick DigitalOcean if you run a small SaaS, indie product or self-funded company under 5 engineers and your stack is conventional (LAMP, MEAN, MERN, FastAPI). Pick DigitalOcean if you do not have a dedicated infra engineer and you want a calmer cloud bill. Pick DigitalOcean if your users are concentrated in regions DO actively supports (US East, US West, Frankfurt, Amsterdam, London, Bangalore, Sydney, Singapore, Toronto, Sao Paulo). Skip DigitalOcean if you depend on more than four AWS managed services together (Lambda, Step Functions, DynamoDB, SQS, Kinesis); the migration cost will eat the savings. Skip DigitalOcean if you have a dedicated infrastructure engineer who already runs AWS efficiently. Skip if your compliance team has already audited AWS for your industry and re-audit on a new vendor is a multi-month exercise. Skip if you need very specific regional presence DO does not cover (Middle East, Africa).

A 53 percent bill cut on identical workload is a thesis. DigitalOcean is what small AWS workloads look like without the operational tax.

Bottom Line

Six months in, the move is a clear win and I would do it again. The two surprises: how cleanly a conventional Symfony stack ports between clouds, and how much of AWS spend was support fees and per-service ceremony rather than compute. The honest concern: DigitalOcean is smaller than AWS and might deprecate a service we depend on someday. Hedge by avoiding lock-in to DO-only primitives (we mostly use Droplets, Postgres and Spaces, all of which are portable to other clouds). I am keeping the savings for 12 months and revisiting only if our scale or compliance posture changes. Got a similar migration in mind? Drop me a note. I will share the Terraform config and the pg_dump cutover runbook that worked for our 1.4 GB database.