
MLOps on a Shoestring: A Complete Stack for Under $200/Month
The pragmatic MLOps stack for solo builders and small teams — model registry, experiment tracking, feature store, drift monitoring, and CI/CD — all under $200/month with open-source and free tiers.
Enterprise MLOps stacks cost $10k+/month and require a platform team. For solo builders and small startups, you can assemble a complete MLOps stack — experiment tracking, model registry, feature store, batch and online inference, drift monitoring, CI/CD — for under $200/month using MLflow, DVC, Feast, Evidently, and one small cloud VM. This article is the exact stack, exact configs, and the trade-offs you accept in exchange for the savings.
- MLflow + DVC + Postgres covers experiment tracking + model registry + versioning.
- Feast in local mode + Postgres = free feature store good enough for <1M rows.
- Evidently + a cron job replaces $2k/mo drift monitoring platforms.
- GitHub Actions runs CI/CD training + eval pipelines for free.
- One $40/month VM hosts MLflow, Postgres, and a small model serving layer.
- Total spend: $180/month all-in for a stack that carries you to Series A.
The three MLOps stacks — pick the right one
| Stack | Cost/mo | For |
|---|---|---|
| Shoestring (this article) | $180 | Solo builders, seed-stage startups, side projects |
| Mid (SageMaker/Vertex AI managed pieces) | $2k–$8k | Series A/B teams, one ML engineer |
| Enterprise (Databricks, dedicated platform) | $20k+ | Series C+, dedicated ML platform team |
The shoestring stack is not 'toy'. It ran the first two years of several profitable ML products. It graduates cleanly to the mid stack when justified by team size or scale.
The complete stack
| Concern | Tool | Runs where |
|---|---|---|
| Experiment tracking | MLflow | One VM |
| Model registry | MLflow | Same VM |
| Data + model versioning | DVC + S3-compatible (Backblaze B2) | Local + B2 |
| Feature store | Feast (local mode) | Same VM + Postgres |
| Feature DB | Postgres (Cloud SQL / Neon) | Managed |
| Training compute | GitHub Actions (2-core) or one spot VM | GHA |
| Batch inference | Cron on the VM | Same VM |
| Online inference | FastAPI on Cloud Run | Cloud Run |
| Drift monitoring | Evidently + cron + Slack webhook | Same VM |
| Dashboarding | Metabase or Grafana | Same VM |
The $40 VM that runs everything
Rent a 4-core, 8GB VM from Hetzner, DigitalOcean, or OVH. Install Docker + docker-compose. This one machine hosts MLflow, Postgres (for MLflow), Metabase, and cron jobs.
# docker-compose.yml
services:
mlflow:
image: ghcr.io/mlflow/mlflow:v2.16.0
command: mlflow server --host 0.0.0.0 --backend-store-uri postgresql://mlflow:...@db/mlflow --default-artifact-root s3://ml-artifacts/
environment:
AWS_ACCESS_KEY_ID: ${B2_KEY_ID}
AWS_SECRET_ACCESS_KEY: ${B2_APP_KEY}
MLFLOW_S3_ENDPOINT_URL: https://s3.eu-central-003.backblazeb2.com
ports: ["5000:5000"]
db:
image: postgres:16
volumes: [pgdata:/var/lib/postgresql/data]
metabase:
image: metabase/metabase:v0.50
ports: ["3000:3000"]
volumes: { pgdata: {} }Reverse proxy via Caddy for HTTPS + basic auth. Total setup: 90 minutes.
MLflow: experiment tracking + registry in one
import mlflow
mlflow.set_tracking_uri("https://mlflow.example.com")
mlflow.set_experiment("churn-v3")
with mlflow.start_run():
mlflow.log_params({"lr": 0.01, "depth": 6})
mlflow.log_metrics({"auc": 0.87, "f1": 0.72})
mlflow.sklearn.log_model(model, "model", registered_model_name="churn")
# Promote to staging/production via UI or:
mlflow.register_model("runs:/<run_id>/model", "churn")
client.transition_model_version_stage("churn", 3, "Production")Serve the production model:
model = mlflow.pyfunc.load_model("models:/churn/Production")
prediction = model.predict(features_df)DVC for data + model versioning
DVC tracks large files in Git without bloating the repo. It stores actual bytes in your S3-compatible bucket.
dvc init
dvc remote add -d origin s3://ml-artifacts/dvc \
--endpointurl https://s3.eu-central-003.backblazeb2.com
dvc add data/raw/customers.parquet # creates .dvc file
git add data/raw/customers.parquet.dvc
git commit -m "add raw customers snapshot"
dvc pushEvery commit now pins the exact data + model bytes used. Reproducibility for free.
Feast: feature store in local mode
Feast's local registry writes to Postgres. Online store lives in Postgres too. Enough for <1M entities and sub-100ms serving.
# feature_repo/customer_features.py
from feast import Entity, FeatureView, Field, ValueType
from feast.types import Float32, Int64
customer = Entity(name="customer_id", value_type=ValueType.INT64)
customer_stats_fv = FeatureView(
name="customer_stats",
entities=[customer],
schema=[Field(name="ltv_90d", dtype=Float32),
Field(name="orders_90d", dtype=Int64)],
source=customer_stats_source,
)Materialize nightly via cron:
feast materialize-incremental $(date -u +%FT%TZ)GitHub Actions as a training runner
For models that train in <6h on 2 cores + 16GB, GitHub Actions is free enough (2000 min/mo on free tier, 50k on Pro).
name: train
on: { workflow_dispatch: {}, schedule: [{ cron: "0 3 * * *" }] }
jobs:
train:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: pip install -r requirements.txt
- run: dvc pull
- run: python train.py
env:
MLFLOW_TRACKING_URI: ${{ secrets.MLFLOW_URI }}
MLFLOW_TRACKING_USERNAME: ${{ secrets.MLFLOW_USER }}
MLFLOW_TRACKING_PASSWORD: ${{ secrets.MLFLOW_PASS }}Heavier training? Spin up a spot GPU VM on Lambda Labs (~$0.60/h) triggered by GH Actions — pay only for training minutes.
Evidently for drift, no SaaS needed
from evidently import ColumnMapping
from evidently.report import Report
from evidently.metric_preset import DataDriftPreset, TargetDriftPreset
report = Report(metrics=[DataDriftPreset(), TargetDriftPreset()])
report.run(reference_data=ref_df, current_data=today_df)
report.save_html("reports/drift-{today}.html")
if report.as_dict()["metrics"][0]["result"]["dataset_drift"]:
post_to_slack("Drift detected in churn features")Cron this nightly; publish HTML reports to S3. Total incremental cost: $0.
Online inference via Cloud Run
FastAPI wrapper around mlflow.pyfunc.load_model, containerized, deployed to Cloud Run — the pattern in Cloud Run + Cloud SQL blueprint.
Cost breakdown
| Component | Monthly cost |
|---|---|
| VM (Hetzner 4C/8GB) | $8 |
| Postgres for app/feature store (Neon free → paid) | $25 |
| Backblaze B2 (500GB) | $3 |
| Cloud Run inference | $10–50 |
| Domain + Caddy TLS | $1 |
| Slack (free) | $0 |
| Occasional GPU spot VM (10h/mo) | $6 |
| Total | ~$70–100/mo |
Even doubling for redundancy, you're under $200 — vs $2k+ for the managed equivalent.
What you give up (and when to graduate)
- One VM = one bus factor. Automate backups; run monthly restore drills — see self-hosting n8n on Kubernetes for backup discipline.
- No auto-scaling training — beyond ~4h training runs, move to a managed platform.
- You are the SRE. Budget 2h/month for maintenance.
- Graduate when: >2 ML engineers, >10 models in production, or when compliance requires SOC 2 with a managed control plane.
Learning path
If you're starting from zero, sequence:
- AI + data engineer roadmap for foundations.
- evaluating LLMs and classical ML for eval discipline.
- observability for AI systems once you have models in prod.
- BigQuery cost control when analytics spend starts appearing.
Building something similar?
I help teams ship production-grade AI agents, n8n workflows, and data platforms. Let's talk about what you're building.
Work with me
Islam Gamal
AI, Data & Automation Engineer. I design and ship production AI agents, n8n workflows, and cloud data platforms — with a focus on reliability, cost, and measurable business impact. Founder of Tashghil and Tek bil Arabi.
More from Islam Gamal
Evaluating LLMs and Classical ML: A Practical Metrics Guide
The metric you pick decides the model you ship. A deep field guide to choosing, computing, and defending metrics for classification, ranking, generation, RAG, and agents — with the traps that catch senior teams.
Observability for AI Systems: Traces, Prompts, Tokens, and the SLOs That Actually Matter
A 30-minute production guide to instrumenting LLM applications — what to log (and what never to), how to trace agent calls end-to-end, the four golden signals for AI, drift detection on outputs, and the dashboards you actually check at 2 a.m.
Cloud Run + Cloud SQL: The Boring Blueprint That Runs Half My Production Systems
A complete production blueprint for Cloud Run + Cloud SQL on GCP — connection pooling, IAM, secrets, migrations, blue/green deploys, cost control, and the failure modes to prevent before they hit.
Browse every article by Islam Gamal on the author page.