The Practical Guide to Nomad, Consul, and OpenTofu for 90% of Startups

Sensyze
Jan 17, 2026 · 5 min read
The Practical Guide to Nomad, Consul, and OpenTofu for 90% of Startups

Introduction

In this post, we dive deep into You Don’t Need Kubernetes: The Practical Guide to Nomad, Consul, and OpenTofu for 90% of Startups. As the landscape of Startups continues to evolve, staying ahead of the curve is crucial for businesses and developers alike.

You Don’t Need Kubernetes: The Practical Guide to Nomad, Consul, and OpenTofu for 90% of Startups

In the modern DevOps world, Kubernetes (K8s) has become the “default” choice. But for 90% of startups—yes, even those scaling to millions of users—Kubernetes is a massive, expensive tax that slows you down.

When we built Sensyze DataFlow, a complex engine involving FastAPI, Next.js, Temporal workflows, and Dask distributed computing, we initially looked at GKE (Google Kubernetes Engine). We quickly realized that the operational overhead would swallow our small team whole.

Instead, we chose the Slim Stack: Nomad + Consul + OpenTofu. This post explains why, and how you can build a production-grade infrastructure that is pocket-friendly and highly maintainable.


1. The Kubernetes Tax vs. The Slim Stack

Before we dive into the code, let’s talk about the “Default Choice” fallacy.

FeatureGKE / EKS / AKSNomad + Consul
Control Plane Cost$70-$144/mo (base fee)$0 (Runs on your own nodes)
Minimum RAM~2GB just for K8s agents~512MB for Nomad + Consul
Learning CurveMonths (YAML hell, CRDs, RBAC)Days (HCL, simple binaries)
NetworkingComplex (CNI, CoreDNS, Ingress)Simple (Consul DNS + Traefik)
MaintenanceHigh (Upgrades are terrifying)Low (Single-binary upgrades)

The Reality: Unless you have 50+ microservices and a dedicated platform team of 5 people, Kubernetes is likely hurting your velocity.


2. Step 1: Declarative Infrastructure with OpenTofu

We use OpenTofu (the open-source fork of Terraform) to define everything. We start with the virtual machines and use Spot Instances to save up to 90% on compute costs.

Nomad is exceptionally good at handling “preemption” (when the cloud provider takes your node back) because its scheduler is lightning fast. While K8s can take minutes to reschedule pods, Nomad does it in milliseconds.

Real-world Snippet: Provisioning a Spot Node on GCP

# main.tf (OpenTofu)
resource "google_compute_instance" "nomad_worker" {
  name         = "nomad-worker-spot"
  machine_type = "e2-medium"
  zone         = "us-central1-a"

  # We use a simple startup script to install the binaries
  metadata_startup_script = file("install_dependencies.sh")

  scheduling {
    preemptible       = true 
    automatic_restart = false
    provisioning_model = "SPOT"
  }

  network_interface {
    network = "default"
    access_config {} # Ephemeral public IP
  }
}

3. Step 2: The Nervous System (Consul) & The Brain (Nomad)

In K8s, you need complex service discovery and often a bulky Service Mesh (like Istio). With Consul, you get high-performance DNS and a Key-Value store for secrets out of the box.

Maintaining Secrets without “Secret Managers”

Instead of paying for GCP Secret Manager or managing K8s Secrets via complex kubectl commands, we store them in Consul KV and inject them into our containers at runtime using Nomad templates.

Code Snippet: Injecting Secrets via OpenTofu

# consul.tf
resource "consul_keys" "app_secrets" {
  key {
    path  = "secrets/dataflow-api/database_url"
    value = var.database_url 
  }
}

4. Step 3: Deploying Your First Job (The Nomad Way)

Nomad uses HCL (HashiCorp Configuration Language). It is significantly more readable than the 400-line YAML files required for a simple K8s Deployment.

In Sensyze, we run a multi-component stack. Here is how we define our FastAPI backend:

Code Snippet: The API Job Specification

job "dataflow" {
  datacenters = ["dc1"]
  type        = "service"

  group "api" {
    count = 2 # High availability

    network {
      port "http" { to = 8000 }
    }

    service {
      name = "api"
      port = "http"
      tags = [
        "traefik.enable=true",
        "traefik.http.routers.api.rule=Host(`api.sensyze.com`)"
      ]
      check {
        type     = "http"
        path     = "/health"
        interval = "10s"
        timeout  = "2s"
      }
    }

    task "server" {
      driver = "docker"
      config {
        image = "sensyze/dataflow-api:latest"
        ports = ["http"]
      }

      # MAGIC: The Template Block
      # This pulls the secret from Consul and writes it to a .env file
      # that only exists in the container's memory.
      template {
        data = <<EOH
DATABASE_URL="{{key "secrets/dataflow-api/database_url"}}"
REDIS_URL="{{key "secrets/common/redis_url"}}"
EOH
        destination = "local/.env"
        env         = true
      }
    }
  }
}

5. Step 4: Observability and the “Zero-Maintenance” Goal

Startups need to know what’s happening now without spending 40 hours a week configuring Grafana dashboards.

  1. Real-time Stats: Nomad’s UI gives you per-second CPU/RAM usage for every task without any extra configuration.
  2. Logs: nomad alloc logs -f <alloc_id> works exactly like docker logs but across your entire cluster.
  3. Health Checks: Consul automatically pulls nodes out of the load balancer if they fail a health check, ensuring your users never see a 502.

What about Scaling?

When we need to scale our Dask workers for a heavy data processing job, we don’t need to learn K8s Horizontal Pod Autoscaler (HPA). We simply update the count in our Nomad file (or use the Nomad Autoscaler) and apply. Because Nomad doesn’t have the “Pod” abstraction overhead, containers spin up nearly instantly.


6. Why Nomad + Consul Wins for Sensyze (and You)

  1. Environmental Parity: We run Nomad in “dev mode” on our laptops. The exact same HCL file that runs in production runs locally. No more “it worked in Docker Compose but failed in K8s” moments.
  2. Resource Efficiency: On a $20/mo VM, we can run our API, Frontend, Redis, Temporal, and Dask. K8s would use half that RAM just for its own “system” overhead.
  3. Single Binary Simplicity: If a server dies, we just run our OpenTofu script. It installs the nomad binary, joins the cluster, and starts running jobs in under 2 minutes.
  4. Flexible Orchestration: Nomad isn’t just for Docker. If you have a legacy Java app or a binary script, Nomad can orchestrate it side-by-side with your modern containers.

Conclusion: Stay Slim, Go Fast

If you are a startup, your goal is Velocity. Kubernetes is a tool for managing scale once you have it, but Nomad is a tool for getting to scale while staying lean.

By using OpenTofu for declarative infra, Nomad for scheduling, and Consul for service discovery, you build a “Slim Stack” that is:

  • 70% cheaper to run.
  • 5x faster to deploy.
  • Maintainable by a single developer.

Stop trying to be Google before you have Google’s problems. Choose the Slim Stack.