Module 1: Understanding Deployment Options

7. Project Stage and Deployment

Overview

In this capsule you'll understand how your project's stage (MVP, Growth, Scale) changes the recommended deployment strategy. The same AI app may need a different strategy when it has 10 users than when it has 10,000. By the end, you'll know when and how to evolve your deployment without rewriting everything.

Context: The previous capsule's decision matrix evaluates your current situation. But situations change. An MVP that starts on Railway may need to migrate to AWS as it grows. This capsule prepares you for those transitions — and tells you when NOT to migrate (because many migrate prematurely).


The Three Stages of an AI Project

MVP (Minimum Viable Product)

Users:        1-100
Traffic:      <1K requests/day
Team:         1-2 developers
Budget:       $0-50/month
Objective:    Validate that the idea works
Duration:     1-3 months

At MVP, your priority is iteration speed. You're not optimizing for scale — you're discovering whether your product makes sense. Every hour you spend configuring infrastructure is an hour you don't spend talking to users or improving prompts.

Growth

Users:        100-10,000
Traffic:      1K-50K requests/day
Team:         2-5 developers
Budget:       $50-500/month
Objective:    Scale what already works
Duration:     3-12 months

At Growth, your priority is stability + controlled scalability. The product works, you have real users, and you need it to not go down. You start thinking about monitoring, informal SLAs, and capacity.

Scale

Users:        10,000+
Traffic:      50K+ requests/day
Team:         5+ developers + ops
Budget:       $500+/month
Objective:    Operate reliably at volume
Duration:     12+ months

At Scale, your priority is reliability + operational efficiency. You have a dedicated team, formal SLAs, and the cost of downtime is high. You invest in infrastructure because the ROI justifies it.


Deployment Strategy by Stage

MVP: Speed above all

Recommended strategy: MANAGED (Railway, Render)

Why:
├── Deploy in minutes (git push → online)
├── Free tier covers the volume
├── Zero ops (you don't waste time on infra)
├── If the product fails, you didn't invest in infra
└── Easy to migrate later (Docker is portable)

Alternative: LOCAL (Docker Compose on a laptop)
├── For demo and development
├── Before having a public domain
└── If the data can't leave your machine
# MVP deployment: as simple as possible
# main.py — Everything in one file
from fastapi import FastAPI
from openai import OpenAI
import os

app = FastAPI()
client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])

@app.get("/health")
def health():
    return {"status": "ok"}

@app.post("/ask")
def ask(prompt: str):
    r = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[{"role": "user", "content": prompt}],
        max_tokens=500
    )
    return {"answer": r.choices[0].message.content}
# Deploy on Railway: 3 commands
railway login
railway init
railway up
# Public URL in 2 minutes

What you do NOT do at MVP:

  • ❌ Kubernetes
  • ❌ Multi-region
  • ❌ Complex auto-scaling
  • ❌ Infrastructure as Code (Terraform)
  • ❌ SageMaker
  • ❌ Microservices

Growth: Stability + controlled scalability

Recommended strategy: MANAGED (pro) or LOCAL (VPS with Docker)

Why:
├── Predictable traffic, you need uptime
├── Health checks and monitoring are necessary
├── Docker Compose gives you control without complexity
├── A VPS with fixed cost is predictable
└── You can add Redis, workers, databases

Alternative: SERVERLESS (Lambda)
├── If traffic is very variable (peaks)
├── For asynchronous components (batch processing)
└── If you want zero ops on specific components
# Growth: Docker Compose multi-service
# docker-compose.yml
services:
  api:
    build: ./api
    ports:
      - "8000:8000"
    environment:
      - OPENAI_API_KEY=${OPENAI_API_KEY}
      - REDIS_URL=redis://cache:6379
    depends_on:
      cache:
        condition: service_healthy
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
      interval: 30s
      timeout: 10s
      retries: 3

  cache:
    image: redis:7-alpine
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s

  worker:
    build: ./worker
    environment:
      - REDIS_URL=redis://cache:6379
    depends_on:
      - cache

What you add at Growth:

  • ✅ Health checks
  • ✅ Caching (Redis)
  • ✅ Environment config (dev/staging/prod)
  • ✅ Basic monitoring (UptimeRobot, logs)
  • ✅ Automated deploys (GitHub Actions)
  • ✅ Error tracking (Sentry)

Scale: Reliability + efficiency

Recommended strategy: SELF-HOSTED (AWS) or SERVERLESS (Lambda) or HYBRID

Why:
├── Traffic justifies the infra investment
├── An ops team can maintain the complexity
├── Formal SLAs require redundancy
├── Cost optimization has significant ROI
└── Multi-region if you have global users

The ops team absorbs the complexity that at MVP/Growth was unacceptable.

What you add at Scale:

  • ✅ Auto-scaling (horizontal)
  • ✅ Load balancing
  • ✅ Multi-region (if needed)
  • ✅ Full observability (metrics, traces, logs)
  • ✅ Disaster recovery and automated backups
  • ✅ Infrastructure as Code (Terraform/Pulumi)
  • ✅ Detailed operational runbooks

When to Migrate Stage

Signs that you need to migrate

MVP → Growth (migrate when):
├── You have real users who depend on the service
├── Downtime causes impact (not just inconvenience)
├── The free tier falls short (RAM, CPU, requests)
├── You need features the platform doesn't have
└── The product is validated and you're going to keep investing in it

Growth → Scale (migrate when):
├── Traffic exceeds a single server's capacity
├── You need formal SLAs (99.9% uptime)
├── You have an ops team (or budget to hire one)
├── Cost optimization of >$500/month justifies the migration
└── Compliance or regulation requires full control

Signs that you should NOT migrate (premature migration)

Do NOT migrate if:
├── "AWS is what serious companies use" → That's not a requirement
├── "We need Kubernetes" with 50 users → Extreme overkill
├── "We should be multi-region" with local traffic → Unnecessary
├── "The free tier has limits" → Are you reaching them?
└── "I want to learn AWS in production" → Learn on LocalStack, not with real money

Premature migration is one of the most costly mistakes in startups: weeks of engineering work to migrate to infra you don't need. That time could have been invested in improving the product.


Migration Patterns by Stage

Pattern 1: Railway → VPS with Docker

When: Traffic exceeds the Railway plan, or you need more control (custom networking, persistent volumes, SSH access).

# Step 1: Your app already has a Dockerfile (Railway uses it)
# No code change — just hosting

# Step 2: Provision a VPS
# DigitalOcean, Linode, or Hetzner ($12-48/month)

# Step 3: Setup on the VPS
ssh root@your-vps
apt update && apt install docker.io docker-compose-plugin
git clone your-repo
cp .env.production .env
docker compose up -d

# Step 4: Domain and SSL
# Caddy as a reverse proxy (auto-SSL)

Effort: 2-4 hours. Risk: low (same Docker container).

Pattern 2: VPS → AWS (Lambda + S3)

When: You need specific AWS services (S3 for storage, Lambda for event-driven processing, SageMaker for models).

# Your code with an abstraction layer (Module 6)
import os

ENVIRONMENT = os.environ.get("ENVIRONMENT", "local")

def get_storage_client():
    """Return a storage client based on the environment."""
    import boto3

    if ENVIRONMENT == "local":
        return boto3.client("s3", endpoint_url="http://localhost:4566")
    else:
        return boto3.client("s3")  # Real AWS

Effort: 1-2 weeks. Risk: medium (new services, IAM, networking).

Pattern 3: Managed → Hybrid (Container + Lambda)

When: Your main API runs well on managed, but you need asynchronous batch processing that doesn't fit in the request/response cycle.

Before (all on Railway):
  User → Railway (FastAPI) → processes everything synchronously

After (hybrid):
  User → Railway (FastAPI) → immediate response
                            → SQS → Lambda → batch processing
                            → S3 → result available

Effort: 1 week. Risk: low-medium (adds complexity, but Railway keeps running).


The "Don't Migrate Until It Hurts" Rule

The principle

Migrate deployment strategy when the current one causes you real pain — not anticipated pain.

Real pain:
├── "The service goes down 2 times/week due to memory limits"
├── "Requests time out because the VPS can't handle the traffic"
├── "The Railway bill is $200/month and a VPS would do the same for $48"
└── "Compliance forces us to have the data on our own server"

Anticipated pain (don't migrate for this):
├── "Someday we'll have millions of users"
├── "Serious companies use AWS"
├── "I don't want growth to catch us off guard"
└── "My friend migrated and it went well"

Premature optimization kills startups

The time you spend migrating to AWS is time you don't spend improving your product. If your product doesn't have product-market fit, the infrastructure is irrelevant. First validate, then optimize.

Time lost on premature migration:
├── Learning AWS/IAM/Lambda:            20-40 hrs
├── Migrating code and CI/CD:           10-20 hrs
├── Testing and debugging:              10-20 hrs
├── Documentation and runbooks:         5-10 hrs
├── Total:                              45-90 hrs

Things you could do in 45-90 hrs:
├── Interview 30 users
├── Implement 5 new features
├── Improve 100 prompts
├── Reduce inference latency 50%
└── Launch 3 product experiments

Decision Matrix by Stage

Quick template

CriterionMVPGrowthScale
Priority #1Iteration speedStabilityReliability
Priority #2Minimal costControlled scalabilityOperational efficiency
Typical strategyManagedManaged/LocalSelf-hosted/Hybrid
InfrastructureRailway freeRailway Pro / VPSAWS / Multi-region
MonitoringUptimeRobotSentry + logsFull observability
Team ops0 (the dev does it)0.5 (dev spends partial time)1+ (dedicated)
SLA"best effort"99% informal99.9% formal
Recovery"re-deploy""manual rollback""automated rollback"

Troubleshooting

Problem 1: "My manager wants AWS from day 1"

Solution: Present numbers. "Railway costs $0/month at MVP and gets us online in 2 hours. AWS costs $200+/month (including my setup time) and takes 2 weeks. I propose Railway for the MVP, with a documented migration path to AWS if we validate the product."

Problem 2: "I migrated prematurely and now everything is more complex"

Solution: Evaluate whether you can simplify. If you migrated to AWS but only use EC2 (no Lambda, S3, SageMaker), a VPS with Docker Compose does the same with less complexity. Reverse migration (simplifying) is also a valid option.

Problem 3: "I don't know if I'm in MVP or Growth"

Solution: Ask yourself: "Does anyone complain if my service goes down for 1 hour?" If the answer is nobody (or just you), you're in MVP. If real users complain, you're in Growth.


Hands-On Exercises

Exercise 1: Identify your stage

Classify your current project (or one you know) as MVP, Growth, or Scale. Justify it with real metrics.

See solution

Example:

Project: Q&A app about internal documentation
Stage: MVP → Growth (transition)

Evidence:
- Users: 45 active (we went from 10 two months ago)
- Traffic: ~800 req/day (growing 20%/month)
- Team: 1 developer
- Downtime impact: Medium (support teams use it daily)
- Budget: $0 current (Railway free tier)

Diagnosis: We're in the MVP → Growth transition
- We already have users who depend on the service
- The free tier is still enough but we're at 70% of the limit
- We need health checks and basic monitoring

Plan: Migrate to Railway Pro ($5/month) and add UptimeRobot.
Don't migrate to AWS — there's no justification yet.

Exercise 2: 12-month migration plan

Create a 12-month timeline for your project, indicating in which month you would do each migration (if applicable) and why.

See solution
Timeline: Documentation RAG app

Months 1-3 (MVP):
  Deployment: Railway free tier
  Trigger to migrate: Free tier limits

Months 4-6 (Growth early):
  Deployment: Railway Pro ($5/month)
  Add: Redis cache, health checks
  Trigger to migrate: >200 users or >5K req/day

Months 7-9 (Growth):
  Deployment: VPS Docker Compose ($24/month)
  Add: Monitoring (UptimeRobot + Sentry), CI/CD
  Trigger to migrate: >500 concurrent users or need for AWS services

Months 10-12 (Growth → Scale):
  Evaluation: Do we need AWS?
  If yes: Migration with LocalStack (Modules 4-6 of this guide)
  If no: Stay on the VPS, optimize
  Add: Load balancing if there are peaks

Key: Each migration has a measurable trigger, not an arbitrary date.

Exercise 3: "Premature optimization" calculation

Your team wants to migrate to AWS now (at MVP stage). Calculate: (a) hours of work to migrate, (b) value of those hours in product improvements, (c) when the migration would have positive ROI.

See solution
(a) Hours to migrate to AWS:
  - Learning Lambda + API Gateway + IAM:     15 hrs
  - Configuring CI/CD for AWS:               8 hrs
  - Migrating code and testing:              12 hrs
  - Documenting:                             5 hrs
  Total:                                     40 hrs

(b) Alternative value (40 hrs of improvements):
  - 15 user interviews
  - 3 new features
  - Reduce latency 30% with prompt optimization
  - Implement caching (30% savings in API costs)

(c) Migration ROI:
  Railway Pro: $20/month
  AWS Lambda: $5/month (at our volume)
  Savings: $15/month
  Hours invested: 40 hrs × $50/hr = $2,000

  Break-even: $2,000 / $15 = 133 months = 11 YEARS

  Conclusion: Migrating to AWS does NOT have ROI at MVP.
  Migrate only when Railway causes real pain.

Exercise 4: "Real pain" checklist

Create a checklist of 5 real-pain signs that would justify migrating from your current strategy. Be specific with metrics.

See solution
## Migration checklist: Railway → VPS/AWS

Migrate when AT LEAST 2 of these are met:

- [ ] Memory limit reached (>90% of the plan's 512MB)
- [ ] Requests time out >5% of the total (cold starts or CPU limit)
- [ ] Railway bill > $50/month (a VPS would do the same for $24)
- [ ] Feature blocked by the platform (e.g.: WebSockets, volumes)
- [ ] Compliance requires data control (SOC2, HIPAA)

Do NOT migrate if:
- Only one sign is met (optimize first)
- The sign is anticipated, not current
- You don't have time to do the migration well (>20 hrs)

Summary

  • The 3 stages (MVP, Growth, Scale) have fundamentally different deployment priorities.
  • MVP: Speed above all. Managed platforms (Railway/Render). Zero ops.
  • Growth: Stability + controlled scalability. Docker Compose on a VPS or managed pro.
  • Scale: Reliability + efficiency. AWS, hybrid, or self-hosted with an ops team.
  • Don't migrate prematurely. Premature migration is one of the most costly mistakes in startups.
  • Migrate when there's real pain (metrics, not feelings): downtime, limits reached, excessive costs.
  • Document migration triggers with specific metrics in your decision matrix.
  • The ROI of migrating is almost never positive at MVP. Time is better invested in the product.

Additional Resources

  1. The Twelve-Factor App — Principles for cloud-native apps that ease migration between stages
  2. Startup CTO's Handbook — Guide for CTOs on infrastructure decisions
  3. Choose Boring Technology — Classic essay on why to choose boring tech
  4. The Pragmatic Engineer — Blog on engineering and infrastructure decisions
  5. Running in Production Podcast — Real cases of deployment in production
  6. Railway Blog — Scaling Stories — Scaling stories on Railway