<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Moksh Gupta</title>
    <description>The latest articles on DEV Community by Moksh Gupta (@moksh).</description>
    <link>https://dev.to/moksh</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2457679%2F32485ee6-614e-4050-bd8e-e22536e1f2b5.png</url>
      <title>DEV Community: Moksh Gupta</title>
      <link>https://dev.to/moksh</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/moksh"/>
    <language>en</language>
    <item>
      <title>AI Release Management in 2026: Which Tools Actually Take an Action</title>
      <dc:creator>Moksh Gupta</dc:creator>
      <pubDate>Mon, 07 Sep 2026 18:29:52 +0000</pubDate>
      <link>https://dev.to/moksh/ai-release-management-in-2026-which-tools-actually-take-an-action-2fal</link>
      <guid>https://dev.to/moksh/ai-release-management-in-2026-which-tools-actually-take-an-action-2fal</guid>
      <description>&lt;p&gt;Shipping the artifact stopped being the interesting problem a while ago. What still hurts is the window right after rollout, where the 5xx rate has moved by half a percent, the p99 chart has a new shape, and one person has to call it: noise, or the leading edge of a regression that needs pulling.&lt;/p&gt;

&lt;p&gt;Google's DORA team put numbers on that window. The 2025 State of AI-assisted Software Development report surveyed close to 5,000 practitioners and found 90 percent using AI at work, with over 80 percent reporting a productivity gain. It also found that AI adoption correlates &lt;strong&gt;negatively&lt;/strong&gt; with software delivery stability, even though its correlation with throughput finally turned positive this year. Faster shipping, more breakage. I dug into the whole category and wrote it up in full &lt;a href="https://devtoollab.com/blog/best-ai-release-management-tools" rel="noopener noreferrer"&gt;on DevToolLab&lt;/a&gt;; this is the compressed version.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two Different Products, One Label
&lt;/h2&gt;

&lt;p&gt;Vendors put "AI release management" on two things that behave nothing alike, and telling them apart is most of the buying decision.&lt;/p&gt;

&lt;p&gt;One is statistical deployment verification, which is older than the current AI hype cycle. It records what your metrics and logs looked like before the change, routes a fraction of traffic to the new build, runs tests against that recorded baseline, and then either advances or reverts on its own. That is a closed loop, and it is the thing that keeps an incident short. Harness, Argo Rollouts, Flagger and Kayenta from the Spinnaker project all sit here.&lt;/p&gt;

&lt;p&gt;The other is a language model wired into a deploy tool: it summarizes a broken pipeline, drafts release notes, proposes a fix. Genuinely handy during a postmortem, and completely passive. It will not touch traffic at 3 AM. So the question to ask a vendor is not "is there a model in here" but "what is it allowed to do without me".&lt;/p&gt;

&lt;h2&gt;
  
  
  The Short Version
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Behavior during a release&lt;/th&gt;
&lt;th&gt;Reverts on its own&lt;/th&gt;
&lt;th&gt;License and cost, checked September 2026&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Harness&lt;/td&gt;
&lt;td&gt;Baselines logs and metrics, correlates drift across endpoints&lt;/td&gt;
&lt;td&gt;Yes, or gates for review&lt;/td&gt;
&lt;td&gt;Proprietary, no public pricing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Argo Rollouts&lt;/td&gt;
&lt;td&gt;Executes metric queries as rollout steps&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Apache 2.0, free, v1.10.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Flagger&lt;/td&gt;
&lt;td&gt;Canary analysis plus per-step conformance webhooks&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Apache 2.0, free, v1.45.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LaunchDarkly&lt;/td&gt;
&lt;td&gt;Sequential testing against guardrail metrics&lt;/td&gt;
&lt;td&gt;Yes, if enabled&lt;/td&gt;
&lt;td&gt;Proprietary, free tier then metered&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Octopus Deploy&lt;/td&gt;
&lt;td&gt;Explains a failed deployment, suggests recovery&lt;/td&gt;
&lt;td&gt;No, diagnosis only&lt;/td&gt;
&lt;td&gt;Proprietary, $2,080/yr self-hosted&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Statsig&lt;/td&gt;
&lt;td&gt;Experiment analysis via CUPED and sequential testing&lt;/td&gt;
&lt;td&gt;Through a flag, not a deploy&lt;/td&gt;
&lt;td&gt;Proprietary, free to roughly $150/mo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unleash&lt;/td&gt;
&lt;td&gt;Kill switches and staged rollout, no analysis engine&lt;/td&gt;
&lt;td&gt;Manual flip&lt;/td&gt;
&lt;td&gt;AGPL-3.0, free to self-host&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Harness
&lt;/h2&gt;

&lt;p&gt;Harness has stopped being coy about this: the relevant product page is called AI Verification and leads with "Rollback before customers know it's broken."&lt;/p&gt;

&lt;p&gt;Mechanically it snapshots logs and metrics before the release, diffs them against live telemetry from your observability vendor, and correlates findings across endpoints before reaching a verdict. You pick the consequence: revert automatically, hold at a review gate, or page a named engineer. It ingests metrics from AppDynamics, Datadog, Prometheus and CloudWatch plus roughly fifteen more, and logs from Splunk, Elasticsearch, Grafana Loki and Google Cloud Ops, so an existing APM contract does most of the integration work. The friction is procurement: Harness lists tiers and quotas, 60 concurrent pipeline executions on Essentials against 500 on Enterprise, but publishes no dollar figures anywhere.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnrgkl0v0dx2l7h6sd9af.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnrgkl0v0dx2l7h6sd9af.webp" alt="Harness AI Verification page headlined " width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Argo Rollouts
&lt;/h2&gt;

&lt;p&gt;If Argo CD is already in your cluster, this is the cheapest possible way to get automated reverts, because you are adding a controller rather than a vendor. Argo Rollouts ships a set of CRDs that give blue-green and canary strategies, with analysis, to workloads that would otherwise only get a rolling update. Release 1.10.0 landed on August 27, 2026 under Apache 2.0, and the repo sits around 3,600 stars.&lt;/p&gt;

&lt;p&gt;What turns it from a traffic splitter into a verifier is the AnalysisTemplate, bundling a metric query with a success condition and a failure tolerance, then plugging in as a rollout step. Recent work has concentrated on the Kubernetes Gateway API plugin, collapsing per-mesh integrations into one standard surface.&lt;/p&gt;

&lt;h2&gt;
  
  
  Flagger
&lt;/h2&gt;

&lt;p&gt;Flagger is the equivalent operator from the Flux ecosystem, and the obvious answer if your GitOps flow is Flux rather than Argo. Version 1.45.0 came out on September 1, 2026, also Apache 2.0, with the repo near 5,400 stars.&lt;/p&gt;

&lt;p&gt;It ramps traffic in stages while sampling metrics and running conformance checks, aborting the moment thresholds fail. Canary, A/B and blue/green mirroring work across App Mesh, Istio, Linkerd and Kuma, or ingress controllers such as Contour, NGINX, Traefik and APISIX, with analysis from Prometheus, InfluxDB, Datadog, New Relic, CloudWatch or Graphite. Its edge over Argo Rollouts is the webhook: any HTTP endpoint can run at any step, so a smoke test lives inside the promotion gate rather than a separate CI job.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fua4qrrtppf8kjmq47sdb.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fua4qrrtppf8kjmq47sdb.webp" alt="Flagger docs diagram: ingress traffic split 90 percent to primary, 10 percent to canary, with Flagger reading Prometheus" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  LaunchDarkly
&lt;/h2&gt;

&lt;p&gt;LaunchDarkly solves the same problem one layer up, at the flag rather than the deployment, and its guarded rollout genuinely closes the loop. It steps traffic onto a new variation while sampling metrics you choose, applying sequential testing to judge whether the gap is a real regression rather than noise. Once the confidence interval lands wholly on the bad side of your criteria, it marks the regression, pings the flag owner, and reverts by itself if you switched that on. Guardrails can be built from errors, latency, clicks or conversions, fed by integrations, SDK events, the metric import API, or OpenTelemetry traces.&lt;/p&gt;

&lt;p&gt;Billing moved off seats. Developer costs nothing: unlimited seats, 5 service connections, 1,000 client-side MAU and 5,000 AI runs monthly. Foundation meters at $10 per service connection plus $8.33 per 1,000 client-side MAU, with 5,000 AI runs bundled and $5 per extra 1,000. Enterprise is quoted. Guarded rollouts exist on every tier, but the fuller Release Monitoring capability is a Guardian add-on restricted to Enterprise, and that is the line item that changes the quote.&lt;/p&gt;

&lt;h2&gt;
  
  
  Octopus Deploy
&lt;/h2&gt;

&lt;p&gt;Octopus is the cleanest illustration of category two, and refreshingly upfront about it. Recovery Agent identifies the root cause of a failed deployment in a click, the Octopus AI Assistant is a Chrome extension that spins up projects from prompts and reads deployment logs, and the Octopus MCP Server exposes change management and auditing to outside agents. All of it compresses the gap between breakage and comprehension. None of it stands between a bad build and your users.&lt;/p&gt;

&lt;p&gt;What Octopus is genuinely good at is governed orchestration over many environments and tenants, a separate discipline from canary analysis, and it publishes real numbers. Cloud runs $0, $4,330 and $24,600 per year across Free, Professional and Enterprise; the self-hosted server is $0, $2,080 and $15,600. Projects are the unit of scale, Free stops at 10 projects, tenants, machines and users, and more headroom costs $770 per year.&lt;/p&gt;

&lt;h2&gt;
  
  
  Statsig
&lt;/h2&gt;

&lt;p&gt;Statsig is a strong product that mostly belongs here as a reminder about a criterion nobody puts on the evaluation sheet. It runs warehouse-native against Snowflake, BigQuery or Databricks, leans on CUPED and sequential testing, and costs between nothing and about $150 a month before overages.&lt;/p&gt;

&lt;p&gt;The awkward part is who owns it. OpenAI bought Statsig for $1.1 billion in all stock, announced September 2025, and founder Vijaye Raji moved over as CTO of Applications. By May 2026 Amplitude had absorbed the brand and customer base while OpenAI kept the engineers, a split the site now advertises with a "Statsig is part of the Amplitude family" banner. Optimizely CEO Alex Atzberger called it "a race car without a driver." Anything holding a gate in front of production deserves a boring ownership story.&lt;/p&gt;

&lt;h2&gt;
  
  
  Unleash
&lt;/h2&gt;

&lt;p&gt;Unleash runs no analysis engine and makes no claim to, yet its homepage frames the problem better than any competitor: "Friends don't let friends ship AI-generated code without feature flags," sold as governance for machine-written software. That is essentially the DORA result rendered as marketing copy.&lt;/p&gt;

&lt;p&gt;In practice it hands you the bluntest and most dependable revert available, a switch that kills a feature with no deploy, plus staged rollout through activation strategies. Licensing is AGPL-3.0-or-later, the repo is near 13,800 stars, and it self-hosts anywhere on PostgreSQL. Two constraints before you standardize on it: the open-source build caps you at 1 project, 2 environments and 5,000 flags per instance, and open-source Unleash Edge hits end of life on December 31, 2026, after which edge evaluation is Enterprise-only.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff2ndsab4ay6acbdpbr3v.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff2ndsab4ay6acbdpbr3v.webp" alt="Unleash homepage headlined " width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Wiring Up a Gate in Two Manifests
&lt;/h2&gt;

&lt;p&gt;None of this requires replatforming. With Argo Rollouts installed, automated reverts are two YAML files. The first encodes your definition of healthy as a query, a threshold and a failure budget.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;argoproj.io/v1alpha1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AnalysisTemplate&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;error-rate&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;service-name&lt;/span&gt;
  &lt;span class="na"&gt;metrics&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;error-rate&lt;/span&gt;
      &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1m&lt;/span&gt;
      &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
      &lt;span class="na"&gt;successCondition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;result[0] &amp;lt; &lt;/span&gt;&lt;span class="m"&gt;0.01&lt;/span&gt;
      &lt;span class="na"&gt;failureLimit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
      &lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;prometheus&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http://prometheus.monitoring.svc.cluster.local:9090&lt;/span&gt;
          &lt;span class="na"&gt;query&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
            &lt;span class="s"&gt;sum(rate(http_requests_total{service="{{args.service-name}}",status=~"5.."}[2m]))&lt;/span&gt;
            &lt;span class="s"&gt;/&lt;/span&gt;
            &lt;span class="s"&gt;sum(rate(http_requests_total{service="{{args.service-name}}"}[2m]))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second drops that template between two traffic weights, so 10 percent of users get the new build for five minutes, the analysis runs, and 50 percent only happens if errors stayed below 1 percent across all five samples.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;argoproj.io/v1alpha1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Rollout&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;checkout-api&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;6&lt;/span&gt;
  &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;canary&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;setWeight&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;pause&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;duration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;5m&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;analysis&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;templates&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;templateName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;error-rate&lt;/span&gt;
            &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;service-name&lt;/span&gt;
                &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;checkout-api&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;setWeight&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;pause&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;duration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;10m&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both files parse, and the strategy resolves to five canary steps ordered &lt;code&gt;setWeight, pause, analysis, setWeight, pause&lt;/code&gt;. Three settings decide whether this earns its keep. Choose a signal that genuinely fails when the service fails, usually 5xx rate or tail latency and almost never CPU. Leave &lt;code&gt;failureLimit&lt;/code&gt; above zero, or one bad scrape discards a healthy release. And multiply &lt;code&gt;interval&lt;/code&gt; by &lt;code&gt;count&lt;/code&gt;, because that is exactly how long every gate parks your traffic. The &lt;a href="https://devtoollab.com/tools/latency-percentile-calculator" rel="noopener noreferrer"&gt;Latency Percentile Calculator&lt;/a&gt; turns raw samples into a defensible p99 threshold, and the &lt;a href="https://devtoollab.com/tools/uptime-sla-calculator" rel="noopener noreferrer"&gt;Uptime SLA Calculator&lt;/a&gt; converts an availability target into the error budget that failure limit spends. The &lt;a href="https://devtoollab.com/blog/best-ai-release-management-tools" rel="noopener noreferrer"&gt;longer DevToolLab writeup&lt;/a&gt; covers how each vendor's analysis differs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Picking One
&lt;/h2&gt;

&lt;p&gt;Running Argo CD already? Argo Rollouts. Apache 2.0, no procurement, and AnalysisTemplate replicates most of what the commercial tier charges for.&lt;/p&gt;

&lt;p&gt;On Flux? Flagger, using conformance webhooks so smoke tests gate promotion directly.&lt;/p&gt;

&lt;p&gt;Off Kubernetes? LaunchDarkly guarded rollouts. The free Developer tier validates the idea, but price Guardian before building a process around it.&lt;/p&gt;

&lt;p&gt;Windows, .NET or tenant sprawl? Octopus Deploy for orchestration and governance, with Recovery Agent treated as postmortem acceleration, nothing more.&lt;/p&gt;

&lt;p&gt;Enterprise with an APM bill already paid? Harness AI Verification consumes telemetry you own and reverts unattended. Open the procurement thread early, given the absent pricing.&lt;/p&gt;

&lt;p&gt;Nothing to spend and no mesh? Self-host Unleash and put a kill switch behind anything risky. It needs a human, but a flag flip still beats a rollback pipeline.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;Sort this market by capability, not by whether "AI" appears in the copy. Harness, Argo Rollouts, Flagger and LaunchDarkly take an action against a metric you defined. Octopus Recovery Agent, and the broader wave of assistants and MCP servers, shortens the distance from failure to understanding, which is worth paying for but solves a different problem.&lt;/p&gt;

&lt;p&gt;Since DORA still shows AI adoption pulling stability down while throughput climbs, the highest-leverage move in 2026 is not another assistant. It is one metric-gated canary step in front of whichever service would hurt most, and the open-source controllers hand you that for nothing.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://devtoollab.com/blog/best-ai-release-management-tools" rel="noopener noreferrer"&gt;Original article on DevToolLab&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cloud.google.com/blog/products/ai-machine-learning/announcing-the-2025-dora-report" rel="noopener noreferrer"&gt;DORA 2025 State of AI-assisted Software Development&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.harness.io/products/continuous-delivery/ai-assisted-deployment-verification" rel="noopener noreferrer"&gt;Harness AI-assisted deployment verification&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://argo-rollouts.readthedocs.io/en/stable/" rel="noopener noreferrer"&gt;Argo Rollouts documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://fluxcd.io/flagger/" rel="noopener noreferrer"&gt;Flagger documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://launchdarkly.com/pricing/" rel="noopener noreferrer"&gt;LaunchDarkly pricing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://octopus.com/ai-tools" rel="noopener noreferrer"&gt;Octopus Deploy AI tools&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Unleash/unleash" rel="noopener noreferrer"&gt;Unleash on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devtoollab.com/blog/best-ci-cd-tools" rel="noopener noreferrer"&gt;Best CI/CD Tools in 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devtoollab.com/blog/best-launchdarkly-alternatives" rel="noopener noreferrer"&gt;Best LaunchDarkly Alternatives in 2026&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devops</category>
      <category>kubernetes</category>
      <category>ai</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Transactional Email APIs in 2026: The Same 50,000 Sends Cost $5 or $66</title>
      <dc:creator>Moksh Gupta</dc:creator>
      <pubDate>Mon, 07 Sep 2026 17:13:20 +0000</pubDate>
      <link>https://dev.to/moksh/transactional-email-apis-in-2026-the-same-50000-sends-cost-5-or-66-47eh</link>
      <guid>https://dev.to/moksh/transactional-email-apis-in-2026-the-same-50000-sends-cost-5-or-66-47eh</guid>
      <description>&lt;p&gt;Sending an email is a POST request. Getting it into an inbox is a reputation problem, and reputation depends on your SPF, DKIM and DMARC records, plus how aggressively your provider retires addresses that bounce or complain before Gmail decides your domain is the issue.&lt;/p&gt;

&lt;p&gt;So the API is not what you are choosing between. Price and bounce handling are. And the price range is wider than anyone expects: at 50,000 emails a month the same workload runs $5.00 on Amazon SES and $66.00 on Postmark, both computed from the vendors' own published rates. The &lt;a href="https://devtoollab.com/blog/best-email-api-providers" rel="noopener noreferrer"&gt;full comparison lives on DevToolLab&lt;/a&gt; with every tier, add-on and screenshot; this is the compressed version.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjmz7sgiege78ec6z9kgs.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjmz7sgiege78ec6z9kgs.webp" alt="Banner reading Best Email API Providers in 2026 with the logos of Resend, Postmark, Twilio SendGrid, Amazon SES and Mailgun" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The spread, in one table
&lt;/h2&gt;

&lt;p&gt;Prices below were read from each vendor's pricing page on September 5, 2026.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Provider&lt;/th&gt;
&lt;th&gt;Free tier&lt;/th&gt;
&lt;th&gt;Entry plan&lt;/th&gt;
&lt;th&gt;Overage per 1,000&lt;/th&gt;
&lt;th&gt;Owned by&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Resend&lt;/td&gt;
&lt;td&gt;3,000/mo, 100/day&lt;/td&gt;
&lt;td&gt;$20/mo, 50,000 included&lt;/td&gt;
&lt;td&gt;$0.90&lt;/td&gt;
&lt;td&gt;Independent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Postmark&lt;/td&gt;
&lt;td&gt;100/mo, no overage&lt;/td&gt;
&lt;td&gt;$15/mo, 10,000 included&lt;/td&gt;
&lt;td&gt;$1.80 down to $1.20&lt;/td&gt;
&lt;td&gt;ActiveCampaign&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SendGrid&lt;/td&gt;
&lt;td&gt;60-day trial, 100/day&lt;/td&gt;
&lt;td&gt;Essentials from $19.95/mo&lt;/td&gt;
&lt;td&gt;Unpublished&lt;/td&gt;
&lt;td&gt;Twilio&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Amazon SES&lt;/td&gt;
&lt;td&gt;AWS credit only&lt;/td&gt;
&lt;td&gt;$0.10 per 1,000, no minimum&lt;/td&gt;
&lt;td&gt;$0.10&lt;/td&gt;
&lt;td&gt;AWS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mailgun&lt;/td&gt;
&lt;td&gt;100/day&lt;/td&gt;
&lt;td&gt;$15/mo, 10,000 included&lt;/td&gt;
&lt;td&gt;$1.80 down to $1.10&lt;/td&gt;
&lt;td&gt;Sinch&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mailtrap&lt;/td&gt;
&lt;td&gt;4,000/mo, 150/day&lt;/td&gt;
&lt;td&gt;$15/mo, 10,000 included&lt;/td&gt;
&lt;td&gt;$1.00&lt;/td&gt;
&lt;td&gt;Railsware&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Loops&lt;/td&gt;
&lt;td&gt;1,000 contacts, 4,000 sends&lt;/td&gt;
&lt;td&gt;Per subscribed contact&lt;/td&gt;
&lt;td&gt;Sends not metered&lt;/td&gt;
&lt;td&gt;Astrodon&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Plunk&lt;/td&gt;
&lt;td&gt;1,000/mo hosted&lt;/td&gt;
&lt;td&gt;$0.001 per email&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;td&gt;AGPL-3.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Postal&lt;/td&gt;
&lt;td&gt;Self-host&lt;/td&gt;
&lt;td&gt;Your hardware&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;td&gt;MIT&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Notice these are not the same unit. Resend, Mailgun and Mailtrap sell a monthly bucket and bill overflow. SES sells thousands with no bucket at all. Loops meters stored contacts and stops caring how much you send. Postmark quotes off a volume slider, so its "price" depends where you drag the handle.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resend
&lt;/h2&gt;

&lt;p&gt;Resend is where new Node and Next.js projects land right now, and the adoption numbers explain why: it announced 3,000,000 users on June 3, 2026, three times what it had six months earlier, with 6.8 million weekly npm downloads on its SDK. It also maintains React Email, now at 6.0, so your templates are just components.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F86z4kobucw8bq0w50hy3.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F86z4kobucw8bq0w50hy3.webp" alt="Resend pricing page showing Free at $0 for 3,000 emails a month, Pro at $20 a month for 50,000 emails with $0.90 per 1,000 overage, and Scale at $90 a month for 100,000 emails" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Free covers 3,000 a month with a 100/day ceiling and 3 domains. Pro is $20 for 50,000 with no daily cap. Scale is $90 for 100,000. Overage sits at $0.90 per 1,000 on both paid tiers, and the add-on sheet is public rather than sales-gated: $30 a month buys a dedicated IP, though only from Scale upward, and SSO is $150.&lt;/p&gt;

&lt;p&gt;Two caveats. That dedicated IP gate means a Pro customer shares reputation. And Resend publishes its own incident reports, with entries from November 18, 2025 and February 15, 2026, which is a healthy habit and also a reminder that a provider tripling in size has rough days.&lt;/p&gt;

&lt;h2&gt;
  
  
  Postmark
&lt;/h2&gt;

&lt;p&gt;Postmark, now an ActiveCampaign property, sells deliverability rather than volume and does not apologize for the premium. At the 10,000 mark on its slider, Basic runs $15, Pro $16.50 with inbound processing and retention stretchable to 365 days, and Platform $18 with unlimited sending domains. Overage lands at $1.80, $1.30 and $1.20 per 1,000, which is the steepest entry rate in this group alongside Mailgun.&lt;/p&gt;

&lt;p&gt;What earns the price is operational visibility: transactional and broadcast traffic run as separate message streams, and per-inbox-provider delivery statistics are published on the status page. The free tier is 100 emails a month, never expires, and refuses overage entirely.&lt;/p&gt;

&lt;p&gt;One thing to be careful with when you compare: because Postmark quotes per slider position rather than a flat plan plus overage, any calculation that models it as "10,000-email tier plus published overage" overstates what you would really pay at higher volume.&lt;/p&gt;

&lt;h2&gt;
  
  
  SendGrid, which now lives on twilio.com
&lt;/h2&gt;

&lt;p&gt;SendGrid still carries more mail than anything else listed here, with Twilio claiming north of 200 billion emails a month. The change this year is administrative: every sendgrid.com pricing URL redirected to a Twilio product page when checked on September 5, 2026, and sendgrid.com now displays a notice that the two sites are merging.&lt;/p&gt;

&lt;p&gt;The current card reads: a 60-day trial at 100 emails a day, Essentials "starting at $19.95/mo", Pro "starting at $89.95/mo" with dedicated IPs bundled, and Premier on request. Note what is missing. There is no permanent free tier anymore, and no exact price, because it "depends on email send volume, features." If you built on the old free plan, budget for a migration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mailgun and Mailtrap
&lt;/h2&gt;

&lt;p&gt;Mailgun is the API-first original, now inside Sinch. Free gives 100 a day with a single day of log retention. Basic is $15 for 10,000, Foundation $35 for 50,000, Scale $90 for 100,000 with 30-day logs, and overage falls from $1.80 to $1.10 across those tiers. The trap is retention: one day of logs on Free and Basic is precisely the window in which you need to explain a bounce.&lt;/p&gt;

&lt;p&gt;Mailtrap arrived from the other direction, as the staging inbox developers used to catch test mail, and its production pricing is sharp in the middle of the range. Free is 4,000 a month at 150 a day, then Basic scales $15 to $30 for 10,000 to 100,000 emails with $1.00 overage. Business starts at $85 for the same 100,000 and bundles dedicated IPs. Read those two carefully, because Basic at $30 and Business at $85 both deliver 100,000 emails; what separates them is retention, seats and the IP.&lt;/p&gt;

&lt;h2&gt;
  
  
  Amazon SES, the number everyone prices against
&lt;/h2&gt;

&lt;p&gt;SES charges &lt;strong&gt;$0.10 per 1,000&lt;/strong&gt; outbound emails a la carte, with no minimum and no contract, plus $0.12 per GB of attachments. Dedicated IPs are $24.95 a month.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fewn15p6kf672m6xy16sj.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fewn15p6kf672m6xy16sj.webp" alt="Amazon SES pricing page showing the tiered plans table with Essentials, Pro and Enterprise columns starting at $0.16 per 1,000 emails" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The wrinkle is new. From July 21, 2026, fresh accounts, along with any account-region pair with no metered activity since June 1, 2025, land on tiered plans instead: Essentials at $0.16 per 1,000 for the first 10 million monthly emails, Pro at $0.22 per 1,000 plus $105 per account per region with an IP bundled, Enterprise at $0.23 plus $500. The $0.10 a la carte rate has not gone away, but it is no longer the automatic default.&lt;/p&gt;

&lt;p&gt;What you are not buying at that price is a product. SES hands over an SMTP endpoint and a reputation dashboard. Templates, suppression logic and support are yours to build, and deliverability analytics cost another $0.07 per 1,000 unless a plan includes them. The SES pricing page carries eighteen footnotes across three tables, and the &lt;a href="https://devtoollab.com/blog/best-email-api-providers" rel="noopener noreferrer"&gt;longer write-up&lt;/a&gt; unpacks the add-on sheet properly, including the Virtual Deliverability Manager surcharge and both dedicated IP models.&lt;/p&gt;

&lt;h2&gt;
  
  
  Loops, priced by contact
&lt;/h2&gt;

&lt;p&gt;Loops is structurally different and worth knowing exists. It bills for stored subscribers, not sends. Free holds 1,000 contacts and 4,000 monthly sends; paid tiers stop metering sends altogether, up to 1,000 emails a second, and fold transactional mail in at no extra cost. If you already want Loops driving onboarding sequences, your password resets ride along free. If you have a handful of contacts firing enormous transactional volume, the model works against you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running it yourself
&lt;/h2&gt;

&lt;p&gt;Plunk is the open-source answer shaped like Resend: AGPL-3.0, 5,400 GitHub stars, transactional plus campaigns and automations, Docker-deployable. Hosted is free to 1,000 emails a month then a flat $0.001 each, so 50,000 sends is roughly $50. Self-hosting still leaves you needing delivery infrastructure or a relay behind it.&lt;/p&gt;

&lt;p&gt;Postal is the serious version: MIT-licensed, 16,800 stars, and an actual MTA. You operate the servers, warm the IP addresses and answer to Gmail's postmaster tools directly. Below a few hundred thousand emails a month that is more labor than the SES invoice it displaces.&lt;/p&gt;

&lt;h2&gt;
  
  
  Compute your own unit rate
&lt;/h2&gt;

&lt;p&gt;Comparing buckets against per-thousand metering in your head does not work. This prints what each provider actually costs at a given volume, and the effective rate per 1,000 once included volume is exhausted:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// unit-rate.mjs - effective cost per 1,000 emails at a given monthly volume.&lt;/span&gt;
&lt;span class="c1"&gt;// Prices read from vendor pricing pages on September 5, 2026.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;volume&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;250&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// [monthly USD, emails included, overage USD per 1,000]&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;plans&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;Resend&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.90&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.90&lt;/span&gt;&lt;span class="p"&gt;]],&lt;/span&gt;
  &lt;span class="na"&gt;Postmark&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.80&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;16.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.30&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.20&lt;/span&gt;&lt;span class="p"&gt;]],&lt;/span&gt;
  &lt;span class="na"&gt;Mailgun&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.80&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;35&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.30&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.10&lt;/span&gt;&lt;span class="p"&gt;]],&lt;/span&gt;
  &lt;span class="na"&gt;Mailtrap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.00&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.00&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;85&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.88&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;250&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.88&lt;/span&gt;&lt;span class="p"&gt;]],&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;metered&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Amazon SES&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;per1k&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;free&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;Plunk&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;per1k&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;1.00&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;free&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cheapest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tiers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;tiers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;best&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;incl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;over&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;incl&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;over&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;best&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;incl&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;price&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;price&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ceil&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;incl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;over&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;best&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;cost&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;best&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;cost&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;best&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;tiers&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;plans&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;cheapest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tiers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;volume&lt;/span&gt;&lt;span class="p"&gt;)])&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;metered&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;volume&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;free&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;per1k&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;usd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLocaleString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en-US&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;currency&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;currency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;USD&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`\n&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;volume&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLocaleString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en-US&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt; emails/month\n`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cost&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;unit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cost&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;volume&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`  &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;padEnd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;usd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cost&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;padStart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;   &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;usd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;unit&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt; per 1,000`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;cheap&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dear&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`\n  spread: &lt;/span&gt;&lt;span class="p"&gt;${(&lt;/span&gt;&lt;span class="nx"&gt;dear&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;cheap&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;x\n`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At 50,000 emails a month:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;50,000 emails/month

  Amazon SES       $5.00   $0.10 per 1,000
  Resend          $20.00   $0.40 per 1,000
  Mailtrap        $30.00   $0.60 per 1,000
  Mailgun         $35.00   $0.70 per 1,000
  Plunk           $49.00   $0.98 per 1,000
  Postmark        $66.00   $1.32 per 1,000

  spread: 13.2x
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And at 250,000, where the buckets start to matter more than the sticker price:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;250,000 emails/month

  Amazon SES      $25.00   $0.10 per 1,000
  Mailtrap       $180.00   $0.72 per 1,000
  Resend         $200.00   $0.80 per 1,000
  Plunk          $249.00   $1.00 per 1,000
  Mailgun        $255.00   $1.02 per 1,000
  Postmark       $306.00   $1.22 per 1,000

  spread: 12.2x
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Read that gap honestly. The $155 to $280 a month separating SES from the managed providers at 250,000 emails buys suppression handling, templates, a dashboard and somebody else's IP reputation. Whether that is a bargain depends entirely on whether you have an engineer who wants to own bounce processing.&lt;/p&gt;

&lt;p&gt;Before your first production send, two things matter more than which vendor you picked: check your &lt;a href="https://devtoollab.com/tools/spf-record-checker" rel="noopener noreferrer"&gt;SPF record&lt;/a&gt; actually includes the provider, and confirm your &lt;a href="https://devtoollab.com/tools/dmarc-checker" rel="noopener noreferrer"&gt;DMARC policy&lt;/a&gt; has a valid reporting address, which every mailbox provider now expects from bulk senders.&lt;/p&gt;

&lt;h2&gt;
  
  
  Picking one
&lt;/h2&gt;

&lt;p&gt;New product, Node or Next.js, under 100,000 a month: Resend, for the SDK and a price sheet that fits on one screen. Transactional mail where a late password reset becomes a support ticket: Postmark, checked against its slider at your real volume. Already inside AWS with someone willing to own suppression lists and IP warming: SES, at a fraction of everything else. Millions of sends and dedicated IP pools: SendGrid, through twilio.com now. Onboarding sequences and transactional from one tool: Loops. Determined to self-host: Plunk for the product shape, Postal if you genuinely want to be the mail server.&lt;/p&gt;

&lt;p&gt;The APIs converged. The prices did not. Choose on the unit you actually consume, then go spend the afternoon on DNS, because no provider can deliver mail your own records declare forged.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://devtoollab.com/blog/best-email-api-providers" rel="noopener noreferrer"&gt;Best Email API Providers in 2026: Resend vs Postmark vs SendGrid vs Amazon SES vs Mailgun&lt;/a&gt; - the full version on DevToolLab, with every tier and add-on&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devtoollab.com/blog/email-authentication-developers-guide" rel="noopener noreferrer"&gt;Email Authentication for Developers: SPF, DKIM, DMARC, BIMI and MTA-STS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://resend.com/pricing" rel="noopener noreferrer"&gt;Resend pricing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://postmarkapp.com/pricing" rel="noopener noreferrer"&gt;Postmark pricing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.twilio.com/en-us/products/email-api/pricing" rel="noopener noreferrer"&gt;Twilio SendGrid Email API pricing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/ses/pricing/" rel="noopener noreferrer"&gt;Amazon SES pricing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.mailgun.com/pricing/" rel="noopener noreferrer"&gt;Mailgun pricing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mailtrap.io/pricing/" rel="noopener noreferrer"&gt;Mailtrap pricing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://loops.so/pricing" rel="noopener noreferrer"&gt;Loops pricing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.useplunk.com" rel="noopener noreferrer"&gt;Plunk&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://postalserver.io" rel="noopener noreferrer"&gt;Postal&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>javascript</category>
      <category>devops</category>
    </item>
    <item>
      <title>SOC 2 Type 2, Explained Without the Compliance Marketing</title>
      <dc:creator>Moksh Gupta</dc:creator>
      <pubDate>Sun, 06 Sep 2026 17:44:59 +0000</pubDate>
      <link>https://dev.to/moksh/soc-2-type-2-explained-without-the-compliance-marketing-bcd</link>
      <guid>https://dev.to/moksh/soc-2-type-2-explained-without-the-compliance-marketing-bcd</guid>
      <description>&lt;p&gt;Sooner or later an enterprise deal stalls on a security questionnaire, and the line holding it up asks for a SOC 2 Type 2. Most explanations of what that means are written by companies selling you one, which is a bad place to start.&lt;/p&gt;

&lt;p&gt;The short version: Type 2 is about a stretch of time. Type 1 is about a day. Everything else follows from that. I published a longer treatment of this over on &lt;a href="https://devtoollab.com/blog/what-is-soc-2-type-2" rel="noopener noreferrer"&gt;DevToolLab&lt;/a&gt;, including the full report-reading procedure, so this is the condensed pass.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvpl3xl76bxgybkdz9jsr.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvpl3xl76bxgybkdz9jsr.webp" alt="Diagram contrasting a SOC 2 Type 1 single point in time against a Type 2 timeline with six sample markers, next to a report card stamped OPINION and the five Trust Services Criteria" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The distinction the whole thing rests on
&lt;/h2&gt;

&lt;p&gt;A SOC 2 Type 2 is an examination by a licensed CPA firm asking two questions at once: were the controls designed properly, and did they actually run that way across a stated window of time. The dates are printed on the report and every conclusion inside is bounded by them.&lt;/p&gt;

&lt;p&gt;A Type 1 asks only the first question, as of one calendar date.&lt;/p&gt;

&lt;p&gt;Why that gap matters is easiest to see with a broken control. Suppose employee offboarding works fine in January, quietly breaks in April, and gets repaired in July. A Type 1 stamped August looks at a healthy control and says so, correctly. A Type 2 spanning January through August pulls samples from the whole run and surfaces the April failures. Buyers ask for Type 2 because it is the only one of the two that can find something.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Type 1&lt;/th&gt;
&lt;th&gt;Type 2&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Question asked&lt;/td&gt;
&lt;td&gt;Are controls designed well&lt;/td&gt;
&lt;td&gt;Designed well &lt;strong&gt;and&lt;/strong&gt; operating&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Window&lt;/td&gt;
&lt;td&gt;One date&lt;/td&gt;
&lt;td&gt;A start date and an end date&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Evidence&lt;/td&gt;
&lt;td&gt;Snapshot&lt;/td&gt;
&lt;td&gt;Samples drawn across the window&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Finds&lt;/td&gt;
&lt;td&gt;Design gaps&lt;/td&gt;
&lt;td&gt;Design gaps and runtime failures&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Nobody is SOC 2 certified
&lt;/h2&gt;

&lt;p&gt;There is no such thing as a SOC 2 certificate, and the language matters more than it sounds. What a CPA firm issues is an opinion, and opinions come in four flavors: unqualified, qualified, adverse, or disclaimed. The Journal of Accountancy, which is the AICPA's own publication, made the point sharply in February 2026 when it described vendors promising "compliance" and noted in the same breath that this is "a term never used in SOC 2 examinations."&lt;/p&gt;

&lt;p&gt;SOC reports date to 2011 and are performed under the AICPA's Statements on Standards for Attestation Engagements. Current reporting requirements for service auditor reports come from SSAE-21.&lt;/p&gt;

&lt;p&gt;One more thing that catches people out: a SOC 2 is a restricted-use document, released to specified parties who understand the system being described. That is why companies put a SOC 3 or a trust page on their marketing site and keep the SOC 2 itself behind an NDA.&lt;/p&gt;

&lt;h2&gt;
  
  
  The five criteria, and why most reports only use one
&lt;/h2&gt;

&lt;p&gt;The control criteria come from the AICPA's 2017 Trust Services Criteria with Revised Points of Focus, 2022. Five categories exist:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Security&lt;/strong&gt; is the common criteria and appears in every SOC 2 examination&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Availability&lt;/strong&gt; applies once you sell an uptime promise&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Processing integrity&lt;/strong&gt; applies when you transform or transact on customer data&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Confidentiality&lt;/strong&gt; applies to information contractually marked confidential&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Privacy&lt;/strong&gt; applies to personal information, and gets confused with confidentiality constantly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The other four are elected, not mandatory. Every category you add drags in more controls, more evidence gathering, and more audit hours, which is why a first report is usually security and nothing else.&lt;/p&gt;

&lt;h2&gt;
  
  
  How long does the window have to be?
&lt;/h2&gt;

&lt;p&gt;The honest answer is that no rule fixes it. The report declares the period it covers, and the length gets decided by management together with the service auditor. It is not written down in the Trust Services Criteria.&lt;/p&gt;

&lt;p&gt;That is worth saying plainly because an enormous amount of published guidance states a mandatory three, six, or twelve month window as though quoting the standard. It is not in there. What is real is the commercial pressure: a longer window means more samples across more time, which buys more confidence, and procurement teams generally want unbroken coverage year over year. First-time reports often run short to unblock a deal, then settle into a rolling annual cycle.&lt;/p&gt;

&lt;p&gt;Two adjacent things you will meet. The gap between a report period ending and today is normal and gets covered by a bridge letter, which is management asserting nothing has changed, not an auditor opinion. And a report whose period closed a year and a half ago is describing a system that may not exist anymore.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the AICPA said about fast reports in 2026
&lt;/h2&gt;

&lt;p&gt;This is the part that changed, and the part the &lt;a href="https://devtoollab.com/blog/what-is-soc-2-type-2" rel="noopener noreferrer"&gt;full article&lt;/a&gt; digs into properly.&lt;/p&gt;

&lt;p&gt;Across 2026 the AICPA published an unusual run of material questioning SOC 2 report quality: FAQs on software tools used in SOC 2 examinations dated March 31, ethics guidance covering business arrangements with SOC tool providers dated April 13, and peer reviewer guidance on SOC 2 risks dated May 14. Its SOC landing page also carries a notice that it is looking into allegations about a compliance vendor's business practices.&lt;/p&gt;

&lt;p&gt;Sean Linton, CPA/CITP, an audit partner at EisnerAmper LLP who chairs the AICPA Assurance Services Executive Committee's SOC 2 Working Group, told the Journal of Accountancy that SOC "professionals are seeing indications that 'fast and easy' may come at the expense of quality and objectivity." The same reporting notes that tool vendors now number in the dozens, market compliance in weeks or hours, and through heavy SEO spending dominate search results for SOC 2 services.&lt;/p&gt;

&lt;p&gt;The structural issue is that most of these vendors are not CPA firms and cannot attest to anything, so some have assembled referral networks of accounting firms, with marketing that gestures at thousands of reports a year. Terry O'Brien, CPA/CITP, a director at Schellman and a Working Group member, described the result bluntly: "You just know it's a template. You can compare any five of their reports, and they're all exactly the same, with a different client logo on it."&lt;/p&gt;

&lt;p&gt;Jeff Cook, CPA, of Fortreum Associates LLC pointed out the practical cost, that a report rejected by a business partner is "not worth the paper it's on." Jeff Krull, CPA/CITP, of Baker Tilly US framed the collective risk: "Even if there are 100 good SOC 2 reports, the one bad one that people get their hands on, they're posting it on LinkedIn, they're posting on social media."&lt;/p&gt;

&lt;p&gt;Worth being fair here: the same CPAs credit these tools for replacing screenshot-and-spreadsheet evidence collection with direct system integrations, which genuinely is better. The complaint is narrow and specific. Marketing built on speed and audit rigor pull against each other.&lt;/p&gt;

&lt;h2&gt;
  
  
  Seven checks before you trust a report someone hands you
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Verify the auditor is a licensed CPA firm.&lt;/strong&gt; Nobody else can issue the opinion. Look them up.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Read the opinion paragraph.&lt;/strong&gt; Unqualified, qualified, adverse, or disclaimed. A qualified opinion is not automatically disqualifying, but it is a conversation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Measure the gap.&lt;/strong&gt; Note the end date, count forward to today, and request a bridge letter past roughly three months.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Read the exceptions.&lt;/strong&gt; Zero findings across a full year should raise an eyebrow, not lower one. Findings are evidence somebody actually tested.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Read the scope and system description.&lt;/strong&gt; Confirm the product you are buying is inside it. Scope drift is the quietest way a clean report covers nothing you care about.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check which criteria are included.&lt;/strong&gt; Security only is normal. If availability or privacy was promised, confirm it is really in there.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check subservice organizations and CUECs.&lt;/strong&gt; Note which subprocessors are carved out, and read the complementary user entity controls, because those are obligations landing on you.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you are on the other side of this and building toward a report, two things worth having open while you work: the &lt;a href="https://devtoollab.com/tools/aws-iam-policy-generator" rel="noopener noreferrer"&gt;AWS IAM Policy Generator&lt;/a&gt; for the least-privilege policies that get sampled under the logical access criteria, and the &lt;a href="https://devtoollab.com/tools/security-headers-checker" rel="noopener noreferrer"&gt;Security Headers Checker&lt;/a&gt; for the transport protections you will be evidencing repeatedly across the window.&lt;/p&gt;

&lt;h2&gt;
  
  
  So which one do you need
&lt;/h2&gt;

&lt;p&gt;Selling into enterprise and blocked in procurement, you need a Type 2, and a Type 1 buys you one pass before renewal. Pre-revenue with a single urgent contract, a Type 1 unblocks you and is only defensible if the Type 2 window opens immediately behind it. Evaluating somebody else's report, run the seven checks and spend your attention on scope and exceptions rather than the opinion line. Choosing an audit firm or a platform, treat an unusually fixed short timeline as a question rather than a feature, which is precisely what the AICPA's own working group flagged in 2026.&lt;/p&gt;

&lt;p&gt;SOC 2 Type 2 means an independent CPA firm looked at your controls over a declared period and formed an opinion about whether they worked. Not a badge, not a pass mark, and not a twelve month window anybody mandated.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://devtoollab.com/blog/what-is-soc-2-type-2" rel="noopener noreferrer"&gt;What Is SOC 2 Type 2? Scope and Period&lt;/a&gt; - the full version on DevToolLab, with the complete report-reading procedure&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devtoollab.com/blog/best-soc2-compliance-automation-platforms" rel="noopener noreferrer"&gt;Best SOC 2 Compliance Automation Platforms: Vanta vs Drata vs Secureframe vs Sprinto&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.journalofaccountancy.com/news/2026/feb/promises-of-fast-and-easy-threaten-soc-credibility/" rel="noopener noreferrer"&gt;Journal of Accountancy: Promises of 'fast and easy' threaten SOC credibility&lt;/a&gt; (February 1, 2026)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.aicpa-cima.com/resources/landing/system-and-organization-controls-soc-suite-of-services" rel="noopener noreferrer"&gt;AICPA: System and Organization Controls, SOC Suite of Services&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.aicpa-cima.com/resources/article/faqs-effect-of-the-use-of-software-tools-on-soc-2-r-examinations" rel="noopener noreferrer"&gt;AICPA: FAQs on the effect of the use of software tools on SOC 2 examinations&lt;/a&gt; (March 31, 2026)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.aicpa-cima.com/resources/download/2017-trust-services-criteria-with-revised-points-of-focus-2022" rel="noopener noreferrer"&gt;AICPA: 2017 Trust Services Criteria with Revised Points of Focus, 2022&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>security</category>
      <category>devops</category>
      <category>startup</category>
      <category>programming</category>
    </item>
    <item>
      <title>AI Voice Agents in 2026: The Same Minute Costs $0.03 or $0.31 Depending on Who Meters the Model</title>
      <dc:creator>Moksh Gupta</dc:creator>
      <pubDate>Sat, 05 Sep 2026 19:22:09 +0000</pubDate>
      <link>https://dev.to/moksh/ai-voice-agents-in-2026-the-same-minute-costs-003-or-031-depending-on-who-meters-the-model-304c</link>
      <guid>https://dev.to/moksh/ai-voice-agents-in-2026-the-same-minute-costs-003-or-031-depending-on-who-meters-the-model-304c</guid>
      <description>&lt;p&gt;An AI agent that answers the phone is four systems pretending to be one. Speech-to-text, an LLM, text-to-speech and telephony all have to hand off inside about a second, while the caller interrupts, reads out a policy number one digit at a time, or sits on hold. Someone has to host that chain and charge you for it, and how each vendor slices the bill turns out to matter more than any feature list.&lt;/p&gt;

&lt;p&gt;I priced six platforms against their published September 5, 2026 rates. The headline: a minute of AI phone call runs anywhere from roughly $0.03 to $0.31, and most of that spread is not quality. It is a question of who meters the LLM. The &lt;a href="https://devtoollab.com/blog/best-ai-voice-agent-platforms" rel="noopener noreferrer"&gt;full version of this comparison lives on DevToolLab&lt;/a&gt; with the per-component tables; this is the condensed pass.&lt;/p&gt;

&lt;h2&gt;
  
  
  The three billing models
&lt;/h2&gt;

&lt;p&gt;Everything on the market falls into one of three shapes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Compute plus pass-through.&lt;/strong&gt; You pay for hosting, and the model bills land on your own accounts. Vapi and Pipecat work this way.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fully metered.&lt;/strong&gt; The vendor buys the models wholesale and resells them inside one per-minute rate. Retell and LiveKit Cloud do this.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Flat all-in.&lt;/strong&gt; One talk-time number covering LLM, STT and TTS, priced like a phone company. That is Bland.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Platform&lt;/th&gt;
&lt;th&gt;Published rate&lt;/th&gt;
&lt;th&gt;Included concurrency&lt;/th&gt;
&lt;th&gt;Compliance&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Vapi&lt;/td&gt;
&lt;td&gt;$0.05/min hosting, models at cost&lt;/td&gt;
&lt;td&gt;10, then $10 per line/mo&lt;/td&gt;
&lt;td&gt;HIPAA $2,000/mo, ZDR $1,000/mo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Retell AI&lt;/td&gt;
&lt;td&gt;$0.07 to $0.31/min all-in&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;HIPAA and SSO on Enterprise&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bland AI&lt;/td&gt;
&lt;td&gt;$0.14, $0.12 or $0.11/min&lt;/td&gt;
&lt;td&gt;10, 50 or 100&lt;/td&gt;
&lt;td&gt;SOC 2 Type II, HIPAA, PCI, FedRAMP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ElevenLabs Agents&lt;/td&gt;
&lt;td&gt;$6 to $990/mo, or $0.08/min API&lt;/td&gt;
&lt;td&gt;4 to 40 by plan&lt;/td&gt;
&lt;td&gt;BAAs on Enterprise&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LiveKit Agents&lt;/td&gt;
&lt;td&gt;$0.01/min session, plus inference&lt;/td&gt;
&lt;td&gt;5, 20 or 50+ by plan&lt;/td&gt;
&lt;td&gt;HIPAA on Scale&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pipecat&lt;/td&gt;
&lt;td&gt;$0.01/min active compute&lt;/td&gt;
&lt;td&gt;Unlimited&lt;/td&gt;
&lt;td&gt;Enterprise billing&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Vapi
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9th459hnjj2yc2b36wrb.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9th459hnjj2yc2b36wrb.webp" alt="Vapi pricing comparison table showing Build and Scale plans, with hosting at $0.05 per minute for calls and $0.005 per message, and model provider costs passed through at cost or $0 with your own API key" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Vapi treats the agent as an API object. You describe an assistant, bolt on a phone number, and start placing calls. Hosting is $0.05 a minute, SMS and chat are $0.005 a message, and STT, LLM and TTS are billed at cost, dropping to nothing on Vapi's side when you supply your own provider keys. Ten concurrent lines are included; extras run $10 each per month. Build retains call history for 14 days.&lt;/p&gt;

&lt;p&gt;Here is the server SDK shape, on &lt;code&gt;@vapi-ai/server-sdk&lt;/code&gt; 1.2.0:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;VapiClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@vapi-ai/server-sdk&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;vapi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;VapiClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;VAPI_API_KEY&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;assistant&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;vapi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;assistants&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Appointment reminders&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;firstMessage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hi, this is the clinic calling to confirm your appointment.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;openai&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gpt-4o-mini&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;system&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Confirm, reschedule, or cancel. Keep answers short.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;voice&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;11labs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;voiceId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;burt&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;transcriber&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;deepgram&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nova-3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;call&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;vapi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;calls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;assistantId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;assistant&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;phoneNumberId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;VAPI_PHONE_NUMBER_ID&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;customer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;number&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;+14155550123&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The adoption numbers are not marketing fluff. TechCrunch's May 12, 2026 piece on the $50 million Series B led by Peak XV reported over 1 billion calls processed, 1 to 5 million calls a day, more than 1 million developers, and Amazon Ring, New York Life and Intuit as customers. Ring landed there after evaluating more than 40 vendors.&lt;/p&gt;

&lt;p&gt;The catch is compliance pricing. HIPAA is a $2,000 monthly add-on and Zero Data Retention another $1,000, on either plan. SOC 2, SSO and RBAC require the annual Scale contract. So the same platform costs a side project five cents a minute and costs a clinic $3,000 a month before anyone picks up the phone.&lt;/p&gt;

&lt;h2&gt;
  
  
  Retell AI
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2iwmc6a1rockxm463wkq.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2iwmc6a1rockxm463wkq.webp" alt="Retell AI cost estimator showing $0.115 per minute broken into LLM cost $0.045, Retell voice infrastructure $0.055, TTS $0.015 and telephony $0.000, beside a plan list with 20 free concurrent calls" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Retell sells the inverse of Vapi's deal: hand over key management entirely and let one vendor meter every component. The quoted band is $0.07 to $0.31 per minute, and the component breakdown explains why it is that wide. Voice infrastructure is fixed at $0.055. TTS is $0.015 for Retell's own voices plus Minimax, Fish, Cartesia and OpenAI, or $0.040 if you want ElevenLabs.&lt;/p&gt;

&lt;p&gt;The LLM line is what moves. GPT-5 nano costs $0.003 a minute, GPT-5 mini $0.012, GPT-4.1 $0.045, Claude 5 Sonnet $0.08, and GPT-5.5 $0.16, doubling to $0.32 on the fast tier. Retell's default estimator stack lands at $0.115.&lt;/p&gt;

&lt;p&gt;New accounts get $10 of credit and 20 concurrent calls, the most generous starting concurrency among the metered platforms. The SDK is unremarkable in a good way, on &lt;code&gt;retell-sdk&lt;/code&gt; 5.64.0:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;call&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;call&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createPhoneCall&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;from_number&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;+14155550100&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;to_number&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;+14155550123&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;override_agent_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;agentId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="c1"&gt;// -&amp;gt; { call_id, call_status }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Watch the Enterprise wall: SSO, RBAC, a dedicated server and custom MSA, DPA or BAA terms all sit behind custom pricing. Pay-as-you-go gets a shared server and community support.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bland AI
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffijzz0fbioaagcqwlg3h.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffijzz0fbioaagcqwlg3h.webp" alt="Bland AI pricing page showing Start at $0.14 per minute with no platform fee and 10 concurrent calls, Build at $0.12 per minute with a $299 monthly fee and 50 concurrent calls, and Scale at $0.11 per minute with a $499 fee and 100 concurrent calls" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bland refuses the itemized bill on principle: no token charges, no model pass-throughs. Start is $0.14 a minute with no platform fee, 10 concurrent calls and a 100 call daily cap, and signup includes two credits and an inbound number. Build cuts the rate to $0.12 for $299 a month with 50 concurrent calls and 2,000 daily. Scale is $0.11 for $499 with 100 concurrent and 5,000 daily. Minutes after a handoff to a human are billed separately at $0.05, $0.04 or $0.03.&lt;/p&gt;

&lt;p&gt;Compliance is the strongest of the self-serve group: SOC 2 Type I and II, HIPAA eligibility, GDPR, PCI DSS, and a FedRAMP banner on the pricing page, though the signed BAA is an Enterprise item.&lt;/p&gt;

&lt;p&gt;Do the arithmetic before you upgrade, though. Dividing that $299 fee by the two cents it saves you per minute means Build is a worse deal than Start until you are past roughly 15,000 minutes. And measured against Vapi's hosting fee, Bland costs about three times as much. Simplicity is the product here, and if your model bills are already small because you run cheap models on your own keys, it is a product you may not need.&lt;/p&gt;

&lt;h2&gt;
  
  
  ElevenLabs Agents
&lt;/h2&gt;

&lt;p&gt;ElevenLabs is the voice model vendor selling the whole agent rather than just the speech. Its self-serve tiers bundle minutes instead of metering them:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Plan&lt;/th&gt;
&lt;th&gt;Monthly&lt;/th&gt;
&lt;th&gt;Minutes&lt;/th&gt;
&lt;th&gt;Concurrent&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;$0&lt;/td&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Starter&lt;/td&gt;
&lt;td&gt;$6&lt;/td&gt;
&lt;td&gt;75&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Creator&lt;/td&gt;
&lt;td&gt;$22&lt;/td&gt;
&lt;td&gt;275&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pro&lt;/td&gt;
&lt;td&gt;$99&lt;/td&gt;
&lt;td&gt;1,238&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scale&lt;/td&gt;
&lt;td&gt;$299&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Business&lt;/td&gt;
&lt;td&gt;$990&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Going through the API instead, the Agents speech engine is $0.08 a minute and handles both STT and TTS in a single low-latency pipeline across more than 70 languages. Which model does the thinking is left to you.&lt;/p&gt;

&lt;p&gt;If recognizable voice quality is the actual product, this is the shortest route to it, and the balance sheet is the deepest in the category at $781 million raised. Two things to keep in mind: the $0.08 excludes the LLM entirely, and bundled minutes evaporate faster than they read. Pro's 1,238 minutes is about 20 hours of talk time, which is not a call center.&lt;/p&gt;

&lt;h2&gt;
  
  
  LiveKit Agents and Pipecat
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftvb13bgt50mweiorp5zk.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftvb13bgt50mweiorp5zk.webp" alt="LiveKit Cloud pricing with Build at $0 per month, Ship from $50, Scale from $500 with HIPAA and security reports, alongside the GitHub badge showing the livekit/agents repository at 14.0K stars" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Both open-source options let you own the pipeline, and both sell a cloud so you do not have to at first.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LiveKit Agents&lt;/strong&gt; is Apache 2.0, 14,000 GitHub stars, Python and Node, with turn detection, telephony and native MCP tool support built in. Cloud pricing is itemized: Build is free, Ship starts at $50 a month, Scale starts at $500 and unlocks HIPAA plus security reports. The calculator's default phone stack adds up to &lt;strong&gt;$0.0672 a minute&lt;/strong&gt;: agent session $0.0100, US number $0.0100, Gemma 4 31B $0.0014, Deepgram Nova-3 $0.0058, Cartesia Sonic 3 $0.0300, observability $0.0100. Switching the model to GPT-5 mini drops that LLM line to $0.0011.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pipecat&lt;/strong&gt; is BSD-2, 15,200 stars, maintained by Daily. Its abstraction is the frame: audio and text move down a chain of Python processors, one per stage, so transport, transcription, the model and speech synthesis are each a swappable link. Dozens of providers plug into those slots, OpenAI, Anthropic, Gemini, Deepgram, ElevenLabs and Cartesia included. Pipecat Cloud matches LiveKit's compute rate: the agent-1x profile (0.5 vCPU, 1 GB) is $0.01 a minute active, $0.0005 reserved, with no concurrency cap. WebRTC is free for one-to-one voice, PSTN dial-in and dial-out is $0.018, SIP runs $0.003 to $0.02, and Krisp noise cancellation is bundled up to 10,000 session minutes monthly. Model providers bill you directly.&lt;/p&gt;

&lt;p&gt;Both carry the same tradeoff: what you get is a toolkit, not a finished product. Anything a managed platform hands you out of the box, cloned voices, staged rollouts, a dashboard to actually see what your calls are doing, becomes a line item on your own roadmap. If none of that appeals, Synthflow occupies the fully managed end of the market, where contracts open at $30,000 a year.&lt;/p&gt;

&lt;h2&gt;
  
  
  Price your own volume
&lt;/h2&gt;

&lt;p&gt;Per-minute headline numbers hide six different bundles, so the only honest comparison is against your own traffic. This uses the rates above:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// voice-agent-cost.mjs - what a month of AI phone calls costs on each platform.&lt;/span&gt;
&lt;span class="c1"&gt;// Usage: node voice-agent-cost.mjs 20000   (minutes of talk time per month)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;minutes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// Published rates, read from each vendor's pricing page on September 5, 2026.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PLATFORMS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Vapi (BYO model keys)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;fixed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;perMin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.05&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;note&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;models at cost, $0 if you bring your own API keys&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Retell (GPT-5 mini)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;fixed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;perMin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.055&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.015&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.012&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;note&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;infra + platform voice + LLM, all Retell-metered&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Bland Start&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;fixed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;perMin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;note&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;all-in, 10 concurrent calls&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Bland Build&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;fixed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;299&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;perMin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;note&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;all-in, 50 concurrent calls&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Bland Scale&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;fixed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;499&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;perMin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;note&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;all-in, 100 concurrent calls&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ElevenLabs Agents&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;fixed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;perMin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.08&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;note&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;speech engine only, LLM extra&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;LiveKit Cloud (example stack)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;fixed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;perMin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.0672&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;note&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;calculator default: Gemma 4 31B, Deepgram Nova-3, Cartesia Sonic 3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Pipecat Cloud (agent-1x + PSTN)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;fixed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;perMin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.01&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.018&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;note&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;STT/LLM/TTS billed by your providers&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;usd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLocaleString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en-US&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;currency&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;currency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;USD&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;maximumFractionDigits&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`\n&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLocaleString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en-US&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt; talk minutes per month\n`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;PLATFORMS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fixed&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;perMin&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;minutes&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`  &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;padEnd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;usd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;padStart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;   &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;note&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;breakEven&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ceil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;299&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.14&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mf"&gt;0.12&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`\n  Bland Build beats Bland Start above &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;breakEven&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLocaleString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en-US&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt; minutes/month\n`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At 20,000 minutes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;20,000 talk minutes per month

  Vapi (BYO model keys)               $1,000   models at cost, $0 if you bring your own API keys
  Retell (GPT-5 mini)                 $1,640   infra + platform voice + LLM, all Retell-metered
  Bland Start                         $2,800   all-in, 10 concurrent calls
  Bland Build                         $2,699   all-in, 50 concurrent calls
  Bland Scale                         $2,699   all-in, 100 concurrent calls
  ElevenLabs Agents                   $1,600   speech engine only, LLM extra
  LiveKit Cloud (example stack)       $1,344   calculator default: Gemma 4 31B, Deepgram Nova-3, Cartesia Sonic 3
  Pipecat Cloud (agent-1x + PSTN)       $560   STT/LLM/TTS billed by your providers

  Bland Build beats Bland Start above 14,950 minutes/month
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do not read those totals without the notes. Vapi's $1,000 and Pipecat's $560 leave out the OpenAI and Deepgram invoices you still receive. Retell's and LiveKit's include them. Bland's include everything plus a compliance posture. Push it to 100,000 minutes and the gap runs from $2,800 to $14,000. The &lt;a href="https://devtoollab.com/blog/best-ai-voice-agent-platforms" rel="noopener noreferrer"&gt;original article walks through the per-component tables&lt;/a&gt; each of these rates comes from.&lt;/p&gt;

&lt;p&gt;If you are prototyping before you commit to a TTS bill, DevToolLab's &lt;a href="https://devtoollab.com/tools/text-to-speech" rel="noopener noreferrer"&gt;Text to Speech tool&lt;/a&gt; will read your agent's opening line back in a browser voice, and the &lt;a href="https://devtoollab.com/tools/wav-file-generator" rel="noopener noreferrer"&gt;WAV File Generator&lt;/a&gt; produces silence or white noise for testing how your STT endpoint handles dead air.&lt;/p&gt;

&lt;h2&gt;
  
  
  Picking one
&lt;/h2&gt;

&lt;p&gt;Shipping a product where voice is one feature and you already hold model keys, take &lt;strong&gt;Vapi&lt;/strong&gt; for the itemized bill and the SDK. Want a single vendor metering everything with no keys to rotate, take &lt;strong&gt;Retell&lt;/strong&gt;, and use the 20 free concurrent calls to load test. Regulated deployment where HIPAA, PCI or FedRAMP paperwork outweighs five cents a minute, take &lt;strong&gt;Bland&lt;/strong&gt;, or Vapi Scale if you need model flexibility and can absorb $2,000 a month for HIPAA. Voice quality as the whole product at modest volume, &lt;strong&gt;ElevenLabs Agents&lt;/strong&gt;. Engineers who want the cost curve under their own control, &lt;strong&gt;LiveKit Agents&lt;/strong&gt; or &lt;strong&gt;Pipecat&lt;/strong&gt;, on the vendor cloud until self-hosting pays off.&lt;/p&gt;

&lt;p&gt;Three pricing shapes, then, and a funding round every few weeks to keep pushing them around. Every figure above is a September 5, 2026 snapshot with a short shelf life, so re-run the script yourself before you sign anything annual. The underlying question survives the repricing, though. Find whoever is metering your LLM minute, because that is the party holding your margin.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://devtoollab.com/blog/best-ai-voice-agent-platforms" rel="noopener noreferrer"&gt;Best AI Voice Agent Platforms in 2026: Vapi vs Retell vs Bland vs ElevenLabs Agents&lt;/a&gt; - the original, with full per-component pricing tables&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://devtoollab.com/blog/best-speech-to-text-apis" rel="noopener noreferrer"&gt;Best Speech-to-Text and AI Voice APIs&lt;/a&gt; - what the underlying transcription and synthesis vendors charge when nobody is reselling them to you&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://devtoollab.com/blog/best-llm-gateways" rel="noopener noreferrer"&gt;Best LLM Gateways and API Routers&lt;/a&gt; - how to add failover and routing to the model that sits in the middle of the call&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://devtoollab.com/blog/prompt-caching-guide" rel="noopener noreferrer"&gt;Prompt Caching&lt;/a&gt; - the technique that attacks the biggest line item on a long conversation&lt;/li&gt;
&lt;li&gt;&lt;a href="https://vapi.ai/pricing" rel="noopener noreferrer"&gt;Vapi pricing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.retellai.com/pricing" rel="noopener noreferrer"&gt;Retell AI pricing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.bland.ai/pricing" rel="noopener noreferrer"&gt;Bland AI pricing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://elevenlabs.io/pricing/api" rel="noopener noreferrer"&gt;ElevenLabs API pricing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/livekit/agents" rel="noopener noreferrer"&gt;LiveKit Agents on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/pipecat-ai/pipecat" rel="noopener noreferrer"&gt;Pipecat on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.daily.co/pricing/pipecat-cloud/" rel="noopener noreferrer"&gt;Pipecat Cloud pricing&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>programming</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Web Scraping APIs for AI in 2026: What 100,000 Pages Really Cost</title>
      <dc:creator>Moksh Gupta</dc:creator>
      <pubDate>Fri, 04 Sep 2026 18:46:33 +0000</pubDate>
      <link>https://dev.to/moksh/web-scraping-apis-for-ai-in-2026-what-100000-pages-really-cost-52em</link>
      <guid>https://dev.to/moksh/web-scraping-apis-for-ai-in-2026-what-100000-pages-really-cost-52em</guid>
      <description>&lt;p&gt;Feed an LLM anything current and you run into the same problem within a week. The URL you want returns a consent modal, a skeleton loader, or 200KB of JavaScript where the article should be. From there it is a build-or-rent decision: stand up your own headless browser fleet, or pay somebody per API call to keep one running.&lt;/p&gt;

&lt;p&gt;I priced the five options I keep seeing in production against a single workload, and published the long version of this comparison on DevToolLab: &lt;a href="https://devtoollab.com/blog/best-web-scraping-apis-for-ai" rel="noopener noreferrer"&gt;Best Web Scraping APIs for AI in 2026&lt;/a&gt;. This is the compressed take.&lt;/p&gt;

&lt;p&gt;Two data points frame the market. Firecrawl's repository crossed 176,000 GitHub stars, more than the open source projects of Bright Data, Zyte and Apify put together. And Apify's State of Web Scraping Report 2026, out January 29, 2026, found 62.5 percent of scraping teams spending more on infrastructure than a year earlier. Demand is not the constraint. Price is.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who Actually Runs This
&lt;/h2&gt;

&lt;p&gt;The Apify survey is worth reading for the buyer profile alone. Proxy spend rose year over year for 58.3 percent of respondents, total infrastructure spend for 62.5 percent, and nearly a quarter saw that bill climb by more than 30 percent, mostly because target sites keep hardening their anti-bot layers.&lt;/p&gt;

&lt;p&gt;AI adoption inside these teams is still ahead of its own hype: 54.2 percent have not put AI anywhere in the workflow yet, though 66.2 percent intend to try, and of the minority already using an AI-assisted tool, 72.7 percent said it measurably helped. The population is also smaller than the enterprise sales pitch implies. 35.8 percent freelance, 49.1 percent sit inside a startup or SMB.&lt;/p&gt;

&lt;h2&gt;
  
  
  One Workload, Five Bills
&lt;/h2&gt;

&lt;p&gt;No vendor publishes what the others charge, so pick a workload and price it yourself. Mine: 100,000 pages a month into a RAG index, priced from each vendor's own rate card as of September 3, 2026.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Per-page cost of a 100,000-page/month RAG ingestion job.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PAGES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="c1"&gt;// Firecrawl Standard covers exactly 100k credits; 1 credit = 1 page.&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;vendor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Firecrawl Standard (annual prepay)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;monthly&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;83&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;vendor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Firecrawl Standard (month to month)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;monthly&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;99&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="c1"&gt;// Bright Data bills per successfully delivered record, not per attempt.&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;vendor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Bright Data (standard $1.00/1k)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;monthly&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PAGES&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;vendor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Bright Data (promo $0.75/1k)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;monthly&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PAGES&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.75&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="c1"&gt;// Zyte prices by site-difficulty tier; these are HTTP responses.&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;vendor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Zyte pay-as-you-go, simple sites&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;monthly&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PAGES&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.13&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;vendor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Zyte pay-as-you-go, hard sites&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;monthly&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PAGES&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;1.27&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;vendor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Zyte $500 commitment, simple sites&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;monthly&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PAGES&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.06&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;vendor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Zyte $500 commitment, hard sites&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;monthly&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PAGES&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.61&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="c1"&gt;// Crawl4AI is free; you rent the box that runs headless Chromium.&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;vendor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Crawl4AI self-hosted (4GB VPS)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;monthly&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;o&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;perPage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;monthly&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;PAGES&lt;/span&gt; &lt;span class="p"&gt;}))&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;perPage&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;perPage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vendor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vendor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;padEnd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;  $&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;monthly&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;padStart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;/mo   $&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;perPage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;/page`&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;spread&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;at&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;perPage&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;perPage&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`\nCheapest to most expensive: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;spread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;x, same 100,000 pages.`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Zyte $500 commitment, simple sites   $   6.00/mo   $0.00006/page
Zyte pay-as-you-go, simple sites     $  13.00/mo   $0.00013/page
Crawl4AI self-hosted (4GB VPS)       $  24.00/mo   $0.00024/page
Zyte $500 commitment, hard sites     $  61.00/mo   $0.00061/page
Bright Data (promo $0.75/1k)         $  75.00/mo   $0.00075/page
Firecrawl Standard (annual prepay)   $  83.00/mo   $0.00083/page
Firecrawl Standard (month to month)  $  99.00/mo   $0.00099/page
Bright Data (standard $1.00/1k)      $ 100.00/mo   $0.00100/page
Zyte pay-as-you-go, hard sites       $ 127.00/mo   $0.00127/page
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A 21x spread on identical volume, and the ordering is doing something sneaky. Two caveats before you read anything into it. Zyte's commitment rows assume you are already spending $500 a month, so the $6 line is a marginal rate, not a bill. And Firecrawl's $83 only exists if you prepay twelve months; month to month it is $99, which puts it beside Bright Data's standard rate rather than under it.&lt;/p&gt;

&lt;p&gt;Apify is missing from the list because it cannot be on it. It meters compute units, not pages, so the number depends on your actor's code rather than your page count.&lt;/p&gt;

&lt;h2&gt;
  
  
  Firecrawl
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.firecrawl.dev/" rel="noopener noreferrer"&gt;Firecrawl&lt;/a&gt; takes a URL and hands back clean Markdown or structured JSON in one call. Scrape, Crawl and Map each cost 1 credit per page with JavaScript rendering already included, which is the part that usually carries a surcharge elsewhere.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fipxep85xh8dzhfc4w831.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fipxep85xh8dzhfc4w831.webp" alt="The Firecrawl homepage headlined " width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Version 2.11.0, shipped June 19, 2026, added a research index over 3 million arXiv papers, automatic PII redaction, and a &lt;code&gt;deterministicJson&lt;/code&gt; format that caches a per-site extractor so repeat crawls stop paying an LLM to re-learn the same page shape.&lt;/p&gt;

&lt;p&gt;The catches: Stealth Mode costs 5 credits a page, Search and Interact bill above the base rate, and credits expire monthly on everything except Scale. The self-hosted repo is also behind the hosted product, since the managed anti-bot layer is not in the open source code.&lt;/p&gt;

&lt;p&gt;Priced yearly: free tier at 1,000 credits, Hobby $16/month, Standard $83/month for 100,000, Scale $599/month for a million. Month to month those are $19, $99 and $749. AGPL-3.0 core, MIT SDKs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Apify
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://apify.com/" rel="noopener noreferrer"&gt;Apify&lt;/a&gt; is a marketplace rather than a single endpoint. You run Actors, small scraping programs you write yourself or pull from the 67,000 already published, and you are billed for compute: one CU equals 1GB of RAM for an hour, at $0.20 down to $0.13 depending on plan.&lt;/p&gt;

&lt;p&gt;That model rewards good code and punishes lazy code. A Cheerio actor parsing static HTML is genuinely cheap. Swap in Playwright to render the pages Cheerio skipped and the same job burns CU several times faster. There is no per-page figure to budget from until you have written the actor and watched it run.&lt;/p&gt;

&lt;p&gt;Two dates matter. Apify went live on x402 in June 2026, so an agent can pay per run instead of holding a prepaid balance. And monthly actor rental retires October 1, 2026, with anything unmigrated moved automatically to pay-per-usage.&lt;/p&gt;

&lt;p&gt;Plans: free with $5 usage, Starter $19/month, Scale $199/month, Business $999/month. The platform is proprietary; its Crawlee library is Apache-2.0.&lt;/p&gt;

&lt;h2&gt;
  
  
  Crawl4AI
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/unclecode/crawl4ai" rel="noopener noreferrer"&gt;Crawl4AI&lt;/a&gt; is what the managed vendors sell, unbundled and unmetered. Point it at a URL, get LLM-ready Markdown, no key, no invoice.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffr6z7i3xdkud8riqmqfa.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffr6z7i3xdkud8riqmqfa.webp" alt="The unclecode/crawl4ai GitHub repository showing 81.2k stars, 8.4k forks and an Apache-2.0 license" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It is past 81,000 stars, runs headless Chromium, handles CSS-selector and LLM-guided extraction, and ships a Docker image, so nothing has to leave your infrastructure. Version 0.9.3, released August 31, 2026, was a security release closing five coordinated-disclosure bugs including an arbitrary file write and an SSRF in the PDF path. Worth noting if you are pinned to something older.&lt;/p&gt;

&lt;p&gt;What it does not solve is the reason the paid tiers exist. No managed proxy pool, no SLA. The first time a target fingerprints your IP you are shopping for proxies, and that bill is now yours to negotiate.&lt;/p&gt;

&lt;p&gt;Free, Apache-2.0, your own compute.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bright Data
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://brightdata.com/products/web-scraper" rel="noopener noreferrer"&gt;Bright Data&lt;/a&gt; is the oldest name here, built on a residential proxy network it advertises at 400 million monthly IPs across 195 countries, with a Web Scraper API sitting on top.&lt;/p&gt;

&lt;p&gt;Its best property is billing per successfully delivered record, so blocked attempts cost nothing. It ships more than 1,500 site-specific scrapers that handle parsing for you, and bulk jobs take up to 5,000 URLs per request. Standard pricing is $1.00 per 1,000 records, or $0.75 with promo code APIS25 for six months.&lt;/p&gt;

&lt;p&gt;No self-hosted path exists, and the catalog is sprawling: proxies, SERP API, Unlocker and datasets are all separate line items.&lt;/p&gt;

&lt;h2&gt;
  
  
  Zyte
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.zyte.com/" rel="noopener noreferrer"&gt;Zyte&lt;/a&gt; was Scrapinghub until February 2021 and still employs the team maintaining Scrapy, which means a lot of this industry's existing spiders were written against their work.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F18ksdyvplrfh1ssvz53j.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F18ksdyvplrfh1ssvz53j.webp" alt="The Zyte pricing page headlined " width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Zyte prices by difficulty, not volume: five tiers from Simple to Advanced, different rates for plain HTTP versus browser-rendered responses, and a lower rate at every tier once you commit to a monthly spend. A $5 trial credit runs for 30 days.&lt;/p&gt;

&lt;p&gt;The tradeoff is that you cannot budget in advance, because Zyte classifies your targets, not you. The same 1,000 requests land anywhere between $0.06 and $16.08 depending on tier, commitment and render mode. That is a 268x range inside one rate card. Existing Scrapy users also get Scrapy Cloud, which is usually the cheaper migration than rewriting spiders.&lt;/p&gt;

&lt;h2&gt;
  
  
  Side by Side
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Billing model&lt;/th&gt;
&lt;th&gt;Entry price&lt;/th&gt;
&lt;th&gt;Self-host&lt;/th&gt;
&lt;th&gt;License&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Firecrawl&lt;/td&gt;
&lt;td&gt;Credits per page&lt;/td&gt;
&lt;td&gt;$16/month yearly, $19 monthly&lt;/td&gt;
&lt;td&gt;Core only&lt;/td&gt;
&lt;td&gt;AGPL-3.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Apify&lt;/td&gt;
&lt;td&gt;Compute units&lt;/td&gt;
&lt;td&gt;$19/month plus usage&lt;/td&gt;
&lt;td&gt;Via Crawlee&lt;/td&gt;
&lt;td&gt;Proprietary&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Crawl4AI&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;$0&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Apache-2.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bright Data&lt;/td&gt;
&lt;td&gt;Per successful record&lt;/td&gt;
&lt;td&gt;$0.75 to $1.00 per 1,000&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Proprietary&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Zyte&lt;/td&gt;
&lt;td&gt;Per response, by tier&lt;/td&gt;
&lt;td&gt;$0.06 to $16.08 per 1,000&lt;/td&gt;
&lt;td&gt;Scrapy only&lt;/td&gt;
&lt;td&gt;Proprietary&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Choosing Once Instead of Twice
&lt;/h2&gt;

&lt;p&gt;Sort your real domain list before you look at any pricing page. Split it into static HTML, JavaScript-rendered, and CAPTCHA or login-walled. That distribution moves your bill far more than raw page count does, and it is the input every vendor's rate card quietly depends on.&lt;/p&gt;

&lt;p&gt;Then decide who owns the anti-bot problem. Renting it from Firecrawl, Bright Data or Zyte buys you a bill that scales with target difficulty. Owning it with Crawl4AI buys a flat server cost plus a proxy budget that arrives unannounced the first time you get blocked.&lt;/p&gt;

&lt;p&gt;Check the license before you modify anything you plan to redistribute: AGPL-3.0 on Firecrawl's core obliges you to publish modifications offered as a network service, while Apache-2.0 and BSD do not. Then test your single hardest target, not the vendor demo. Advertised entry pricing describes the easiest tier, and easy sites are not why you are shopping. The &lt;a href="https://devtoollab.com/blog/best-web-scraping-apis-for-ai" rel="noopener noreferrer"&gt;full DevToolLab guide&lt;/a&gt; works through each of these steps with the per-tier numbers.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Short Answer
&lt;/h2&gt;

&lt;p&gt;Building a RAG pipeline or agent and want Markdown without plumbing: Firecrawl. Predictable credits, JS rendering at base rate, and the deterministic JSON caching pays for itself on recrawls.&lt;/p&gt;

&lt;p&gt;Thousands of sites at unpredictable volume: Apify if you will tune actor code, Bright Data if you would rather pay flat per record and use its prebuilt scrapers.&lt;/p&gt;

&lt;p&gt;Data cannot leave your infrastructure, or there is no budget: Crawl4AI, accepting that you are now the proxy team.&lt;/p&gt;

&lt;p&gt;No commitment and tolerance for variance: Zyte, whose $5 trial is the cheapest way to learn what your specific sites actually cost.&lt;/p&gt;

&lt;p&gt;Already running Scrapy: Scrapy Cloud, same maintainers, no rewrite.&lt;/p&gt;

&lt;p&gt;Whichever you pick, the raw HTML arriving at your ingestion step is rarely what you want in a context window. &lt;a href="https://devtoollab.com/tools/html-cleaner" rel="noopener noreferrer"&gt;HTML Cleaner&lt;/a&gt; strips inline styles and markup noise before it burns tokens, and &lt;a href="https://devtoollab.com/tools/json-to-csv-converter" rel="noopener noreferrer"&gt;JSON to CSV Converter&lt;/a&gt; turns a scrape result into a spreadsheet when you just need to eyeball what came back.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Firecrawl's star count and Apify's survey point the same way: this category grew because AI pipelines need it, not because scraping became easier. Apify killing rental pricing in October 2026 and Firecrawl shipping an arXiv index rather than more output formats both read like a market still deciding what it sells. Before you renew anything, answer one question. Are you billed per page or per unit of compute, and does that match the axis your workload grows along?&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://devtoollab.com/blog/best-web-scraping-apis-for-ai" rel="noopener noreferrer"&gt;Best Web Scraping APIs for AI in 2026: Firecrawl vs Apify vs Bright Data vs Zyte&lt;/a&gt; - the original, with the full pricing script and per-vendor detail&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://apify.com/" rel="noopener noreferrer"&gt;Apify State of Web Scraping Report 2026&lt;/a&gt; - January 29, 2026&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.firecrawl.dev/pricing" rel="noopener noreferrer"&gt;Firecrawl pricing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://brightdata.com/products/web-scraper" rel="noopener noreferrer"&gt;Bright Data Web Scraper API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.zyte.com/pricing/" rel="noopener noreferrer"&gt;Zyte pricing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/unclecode/crawl4ai" rel="noopener noreferrer"&gt;Crawl4AI on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://devtoollab.com/blog/best-rag-platforms-and-tools" rel="noopener noreferrer"&gt;Best RAG Platforms and Tools&lt;/a&gt; - where these pages end up indexed&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://devtoollab.com/blog/best-ai-browser-automation-tools" rel="noopener noreferrer"&gt;Best AI Browser Automation Tools&lt;/a&gt; - the layer above extraction&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>programming</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Stop Writing try/except Around Your LLM Calls: Structured Outputs in 2026</title>
      <dc:creator>Moksh Gupta</dc:creator>
      <pubDate>Thu, 03 Sep 2026 18:26:03 +0000</pubDate>
      <link>https://dev.to/moksh/stop-writing-tryexcept-around-your-llm-calls-structured-outputs-in-2026-2j27</link>
      <guid>https://dev.to/moksh/stop-writing-tryexcept-around-your-llm-calls-structured-outputs-in-2026-2j27</guid>
      <description>&lt;p&gt;Anyone who shipped an LLM feature before 2026 knows the ritual. Write "return valid JSON only" in the prompt. Wrap the parse in a try block. Add a retry for the runs where the model opened with "Sure! Here's your JSON:" and wrapped everything in a markdown fence. Maybe strip fences with a regex. That whole layer is now dead weight.&lt;/p&gt;

&lt;p&gt;Anthropic shipped &lt;a href="https://claude.com/blog/structured-outputs-on-the-claude-developer-platform" rel="noopener noreferrer"&gt;Structured Outputs&lt;/a&gt; to GA on February 4, 2026, which made it the last major provider to support this natively. OpenAI has offered it since August 2024, Gemini does it through &lt;code&gt;response_schema&lt;/code&gt;, and the open-source serving stack (vLLM, Ollama, SGLang) has shipped grammar-constrained decoding for well over a year. Parsing and praying is now a decision you are making, not a constraint you are living under.&lt;/p&gt;

&lt;p&gt;I wrote a longer version of this on DevToolLab, &lt;a href="https://devtoollab.com/blog/llm-structured-outputs-guide" rel="noopener noreferrer"&gt;LLM Structured Outputs: Get JSON That Always Parses&lt;/a&gt;, with more provider detail. This is the compressed take: the three things people mean by "structured output," the token-level mechanism behind the guarantee, the per-provider API, and the schema rules that quietly break your requests.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three Different Things Share the Name
&lt;/h2&gt;

&lt;p&gt;Conflating these is where most confusion begins.&lt;/p&gt;

&lt;p&gt;Prompt-only JSON means you describe the shape in the prompt and hope for the best. Nothing is guaranteed, and the failure rate rises with schema complexity and falls with model size.&lt;/p&gt;

&lt;p&gt;JSON mode is a flag, OpenAI's &lt;code&gt;json_object&lt;/code&gt; being the canonical example, that forces the output to be syntactically parseable. That is all it forces. Required fields can go missing, types can be wrong, extra keys can appear. OpenAI labels it legacy now.&lt;/p&gt;

&lt;p&gt;Schema-constrained generation is the real thing: you supply a JSON Schema and the response is guaranteed to conform, every required key present, every type right, every enum value drawn from your list. When OpenAI, Anthropic and Google say "Structured Outputs," this is what they mean.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;Parses as JSON&lt;/th&gt;
&lt;th&gt;Conforms to your schema&lt;/th&gt;
&lt;th&gt;Needs retry logic&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Prompt-only&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JSON mode (&lt;code&gt;json_object&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Sometimes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Schema-constrained (&lt;code&gt;json_schema&lt;/code&gt;, &lt;code&gt;strict&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Only the last one lets you delete code rather than accumulate it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Math That Kills Agent Loops
&lt;/h2&gt;

&lt;p&gt;A single call failing to parse 1% of the time reads as acceptable. Put it in an agent that makes ten tool calls and the run has roughly a 10% chance of dying somewhere in the middle. Chain two or three agents together and you have built something that fails often enough to be unshippable.&lt;/p&gt;

&lt;p&gt;The failure modes are dull and repetitive: a trailing comma, an unexpected code fence, an enum value the model invented, a number returned as a string, a required field that just is not there. Calling these model errors misses the point. Unconstrained sampling draws from the entire vocabulary at every step, and no part of that process knows your structure exists.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Constrained Decoding Actually Does
&lt;/h2&gt;

&lt;p&gt;The guarantee comes from constrained decoding, sometimes called guided or grammar-constrained generation, and the concept is straightforward even though the implementation is not.&lt;/p&gt;

&lt;p&gt;Generation is token by token. At each step the model produces a probability distribution across a vocabulary that often exceeds 100,000 tokens, then samples one. Constrained decoding inserts itself between those two steps: your JSON Schema gets compiled into a formal grammar, the decoder tracks the current position within that grammar, and any token that would produce invalid output has its probability driven to zero. Broken JSON is not merely unlikely, it is unreachable. Anthropic's framing is that the schema becomes a formal grammar constraining generation token by token.&lt;/p&gt;

&lt;p&gt;Open source got there first. &lt;a href="https://github.com/dottxt-ai/outlines" rel="noopener noreferrer"&gt;Outlines&lt;/a&gt; made grammar-based generation practical for open weights, and &lt;a href="https://github.com/mlc-ai/xgrammar" rel="noopener noreferrer"&gt;XGrammar&lt;/a&gt; made it fast enough to be free, using adaptive token-mask caching. That is why XGrammar is &lt;a href="https://blog.vllm.ai/2025/01/14/struct-decode-intro.html" rel="noopener noreferrer"&gt;the default backend in vLLM&lt;/a&gt; from v0.7.0 on, and why SGLang, TensorRT-LLM and MLC-LLM use it too. Overhead on JSON generation is effectively nil. The mechanism is identical everywhere; only the API surface and the accepted slice of JSON Schema differ.&lt;/p&gt;

&lt;h2&gt;
  
  
  Provider by Provider
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;OpenAI&lt;/strong&gt; supports it from &lt;code&gt;gpt-4o-2024-08-06&lt;/code&gt; forward, including the GPT-5 models. You pass a JSON Schema with &lt;code&gt;strict: true&lt;/code&gt;, via &lt;code&gt;response_format&lt;/code&gt; in Chat Completions or &lt;code&gt;text.format&lt;/code&gt; in the Responses API. The Python SDK wraps all of it in a &lt;code&gt;parse&lt;/code&gt; helper that accepts a Pydantic model and hands back a typed object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Reference: requires OPENAI_API_KEY
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OpenAI&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pydantic&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BaseModel&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Ticket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;estimate_hours&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;

&lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;responses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt-5&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Open a ticket: login redirect broken, high priority, ~3.5h&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;text_format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Ticket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output_parsed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# Ticket(title=..., priority='high', ...)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Watch two things. Legacy &lt;code&gt;json_object&lt;/code&gt; guarantees syntax only, never your schema. And because the output is grammar-constrained, a safety refusal cannot arrive as ordinary content, so OpenAI returns it in a separate &lt;code&gt;refusal&lt;/code&gt; field that you must check before touching the payload.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Anthropic&lt;/strong&gt; has been GA since February 2026 across the current lineup, Opus 4.8, Sonnet 5 and Haiku 4.5, with the beta header no longer required. The pattern matches:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Reference: requires ANTHROPIC_API_KEY
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;anthropic&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Anthropic&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pydantic&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BaseModel&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Contact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;plan_interest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;

&lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Anthropic&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;claude-opus-4-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;max_tokens&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;John Smith (john@example.com) wants the Enterprise plan.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;
    &lt;span class="n"&gt;output_format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Contact&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parsed_output&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# Contact(name='John Smith', ...)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At the raw HTTP level the schema rides in an &lt;code&gt;output_config.format&lt;/code&gt; object. Claude covers two cases: JSON against a schema, shown above, and tool use, where a tool call's arguments are automatically constrained to that tool's input schema. The second is what stops agent function calls from arriving malformed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gemini&lt;/strong&gt; takes a config object instead. Set &lt;code&gt;response_mime_type&lt;/code&gt; to &lt;code&gt;application/json&lt;/code&gt; and supply &lt;code&gt;response_schema&lt;/code&gt;, which accepts a Pydantic model, a dict, or an enum:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Reference: requires a Gemini API key
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;google&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;genai&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pydantic&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BaseModel&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Recipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;ingredients&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;genai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate_content&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gemini-3.5-flash&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;contents&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Give me a simple pancake recipe.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;response_mime_type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;response_schema&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Recipe&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parsed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Gemini takes a subset of JSON Schema and will reject schemas that are very large or deeply nested, so keep the structure flat.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Local models&lt;/strong&gt; need no hosted API at all. Ollama has accepted a JSON Schema in &lt;code&gt;format&lt;/code&gt; since 0.3.0, constraining the local model's decoding and dropping fences and preamble on its own:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Reference: requires a running Ollama server + a pulled model
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;ollama&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;chat&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pydantic&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BaseModel&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Country&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;capital&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;population&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;

&lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;llama3.1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Tell me about Japan.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;
            &lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Country&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;model_json_schema&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Country&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;model_validate_json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On self-hosted vLLM or SGLang the parameter is &lt;code&gt;guided_json&lt;/code&gt;, with XGrammar underneath. Identical guarantee, running on hardware you control.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wiring It Into an Application
&lt;/h2&gt;

&lt;p&gt;Four steps, and they are the same regardless of provider.&lt;/p&gt;

&lt;p&gt;Start by defining the shape exactly once, in Pydantic for Python or Zod for TypeScript. That single definition serves as both the schema you transmit and the type you validate against.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pydantic&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Field&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;enum&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Enum&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Priority&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Enum&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;low&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;low&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;medium&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;medium&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;high&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;high&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Ticket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Priority&lt;/span&gt;
    &lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;default_factory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;estimate_hours&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Ticket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;model_json_schema&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;indent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look closely at what that emits. The &lt;code&gt;required&lt;/code&gt; array contains &lt;code&gt;title&lt;/code&gt;, &lt;code&gt;priority&lt;/code&gt; and &lt;code&gt;estimate_hours&lt;/code&gt;, but not &lt;code&gt;tags&lt;/code&gt;, because &lt;code&gt;tags&lt;/code&gt; carries a default. Hold that thought, it causes real pain shortly.&lt;/p&gt;

&lt;p&gt;Second, send it, either as a raw schema or as a Pydantic model handed to a &lt;code&gt;parse&lt;/code&gt; helper, and receive a conforming typed object.&lt;/p&gt;

&lt;p&gt;Third, validate locally anyway. It costs microseconds and it protects you from SDK quirks, proxy rewrites, and whichever endpoint in your stack lacks native support:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;jsonschema&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ValidationError&lt;/span&gt;

&lt;span class="n"&gt;schema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Ticket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;model_json_schema&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;good&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;title&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Fix login redirect&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;,&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;priority&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;high&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;,&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tags&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;:[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;auth&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;],&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;estimate_hours&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;:3.5}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="nf"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;good&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;schema&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# raises if wrong
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Ticket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;model_validate_json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;good&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;              &lt;span class="c1"&gt;# typed object
&lt;/span&gt;
&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;title&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;x&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;priority&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;urgent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;estimate_hours&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;schema&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;ValidationError&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rejected:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# 'urgent' is not one of ['low', 'medium', 'high']
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fourth, deal with refusals and gaps in support. Branch on OpenAI's &lt;code&gt;refusal&lt;/code&gt; field before reading data, and for any endpoint without native support keep a repair-then-retry fallback rather than counting braces by hand. &lt;a href="https://devtoollab.com/tools/json-repair" rel="noopener noreferrer"&gt;DevToolLab's JSON Repair tool&lt;/a&gt; is the browser version of that fallback when you are debugging by hand instead of in code.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Schema Rules That Cost You an Afternoon
&lt;/h2&gt;

&lt;p&gt;This is where the 400 responses come from, because every provider accepts a different subset of JSON Schema.&lt;/p&gt;

&lt;p&gt;OpenAI's strict mode requires every field. You cannot simply omit a property from &lt;code&gt;required&lt;/code&gt;. Every declared property must appear there, and every object needs &lt;code&gt;additionalProperties: false&lt;/code&gt;. Making something optional means keeping it in &lt;code&gt;required&lt;/code&gt; while giving it a nullable type such as &lt;code&gt;"type": ["string", "null"]&lt;/code&gt;. Combine that with the earlier detail, Pydantic excluding defaulted fields from &lt;code&gt;required&lt;/code&gt;, and any model with defaults fails strict mode untouched. This helper repairs any schema in place:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;make_strict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;additionalProperties:false + every key required, at every level.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;object&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;properties&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;additionalProperties&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
            &lt;span class="n"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;required&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;properties&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;values&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="nf"&gt;make_strict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;make_strict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;schema&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Certain keywords get dropped or refused. OpenAI strict mode does not enforce &lt;code&gt;minLength&lt;/code&gt;, &lt;code&gt;maxLength&lt;/code&gt;, &lt;code&gt;pattern&lt;/code&gt; or &lt;code&gt;format&lt;/code&gt;, and it rejects &lt;code&gt;default&lt;/code&gt; outright. Anything depending on a regex &lt;code&gt;pattern&lt;/code&gt; has to be checked after the fact. Claude and Gemini each define their own subset, so portability across providers is not automatic. Depth and size limits apply on all three hosted providers, so flatten aggressively and split oversized schemas into separate calls. Checking a response against your schema in &lt;a href="https://devtoollab.com/tools/json-schema-validator" rel="noopener noreferrer"&gt;the JSON Schema Validator&lt;/a&gt; is faster than guessing which keyword the provider silently ignored. The &lt;a href="https://devtoollab.com/blog/llm-structured-outputs-guide" rel="noopener noreferrer"&gt;original post&lt;/a&gt; goes through each provider's subset in more detail.&lt;/p&gt;

&lt;p&gt;TypeScript teams get the same rules through Zod, defining once and validating identically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;zod&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Ticket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enum&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;low&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;medium&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;high&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
  &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
  &lt;span class="na"&gt;estimateHours&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;number&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;parsed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Ticket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawModelOutput&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;// throws on mismatch&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What This Does Not Fix
&lt;/h2&gt;

&lt;p&gt;Constrained decoding enforces shape, never truth. Nothing prevents &lt;code&gt;"estimate_hours": 400&lt;/code&gt; on a two-line fix, or a confidently extracted email address belonging to the wrong person. Schema conformance is the floor of output quality, not the ceiling, and evals remain the only way to measure the rest.&lt;/p&gt;

&lt;p&gt;There is a modest cost too. Forcing the grammar can steer the model down a slightly less natural path, and compiling an unfamiliar complex schema adds a one-time warm-up that gets cached afterward. For extraction, classification and tool calling that trade is obvious. For long-form creative writing it is usually the wrong instrument.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Structured outputs convert "get JSON out of an LLM" from a reliability problem into a schema-design problem, which is a far better problem to own. Define the shape once in Pydantic or Zod, ship it as a JSON Schema, let constrained decoding enforce it, and keep local validation as a cheap backstop. Fences, trailing commas, absent fields and illegal enums all stop at the source.&lt;/p&gt;

&lt;p&gt;Treat the schema as a contract. Get &lt;code&gt;additionalProperties&lt;/code&gt;, &lt;code&gt;required&lt;/code&gt; and nullability right, keep the structure flat, and stay honest that a valid shape is not a correct answer. Then find your single most parse-prone call, the one wrapped in the ugliest error handling you own, and convert it this week. It is usually about ten lines of change that removes a hundred lines of defense.&lt;/p&gt;

&lt;p&gt;Provider availability, model names and API parameters here reflect July 2026. This area moves fast, so confirm field names and the supported JSON Schema subset in each provider's current docs before shipping.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://devtoollab.com/blog/llm-structured-outputs-guide" rel="noopener noreferrer"&gt;LLM Structured Outputs: Get JSON That Always Parses, the original article on DevToolLab&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://claude.com/blog/structured-outputs-on-the-claude-developer-platform" rel="noopener noreferrer"&gt;Structured Outputs on the Claude Developer Platform&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/dottxt-ai/outlines" rel="noopener noreferrer"&gt;Outlines&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/mlc-ai/xgrammar" rel="noopener noreferrer"&gt;XGrammar&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.vllm.ai/2025/01/14/struct-decode-intro.html" rel="noopener noreferrer"&gt;Structured decoding in vLLM&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>python</category>
      <category>programming</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Secrets Management in 2026: The Cheap Vault SaaS Is Gone, So What Now?</title>
      <dc:creator>Moksh Gupta</dc:creator>
      <pubDate>Thu, 03 Sep 2026 18:22:29 +0000</pubDate>
      <link>https://dev.to/moksh/secrets-management-in-2026-the-cheap-vault-saas-is-gone-so-what-now-2j8h</link>
      <guid>https://dev.to/moksh/secrets-management-in-2026-the-cheap-vault-saas-is-gone-so-what-now-2j8h</guid>
      <description>&lt;p&gt;If you were planning to buy Vault as a managed service on a small budget, that option closed last month. HCP Vault Secrets went end of sale on June 30, 2025, and remaining contract customers hit end of life on whichever came first, their contract expiry or July 1, 2026. HashiCorp points you at HCP Vault Dedicated instead, which is hosted Vault Enterprise: a different product with a different bill.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbxl1anxyp9vy7arkhau1.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbxl1anxyp9vy7arkhau1.webp" alt="The HashiCorp Help Center article confirming HCP Vault Secrets is being decommissioned, with end of sale on June 30, 2025 and end of life on the earlier of contract expiry or July 1, 2026" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Two weeks before that cutoff, Vault jumped from 1.21 to 2.0. No rewrite happened. The number now tracks IBM's versioning and its Support Cycle-2 policy, which retires HashiCorp's long-term support labels. At the same time, the fork that appeared when Vault left open source has been shipping features Vault charges for. I published a longer version of this comparison on DevToolLab, &lt;a href="https://devtoollab.com/blog/best-secrets-management-tools" rel="noopener noreferrer"&gt;Best Secrets Management Tools in 2026&lt;/a&gt;, with the full pricing tables and a migration checklist. This is the condensed pass.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Job, and the Two Jobs Next to It
&lt;/h2&gt;

&lt;p&gt;A secrets manager stores credentials, hands them to workloads that can prove identity, and takes them back. Two adjacent categories get confused with it constantly. Secrets scanning hunts for credentials already sitting in your git history. Non-human identity management decides which machine identities should exist and what they may touch. Neither one is this. This is the storage and distribution layer between them.&lt;/p&gt;

&lt;p&gt;The question that actually sorts these tools is whether you need dynamic secrets: credentials minted on request with a lease attached, so a leaked one dies on its own. That single capability is why Vault exists and why it costs more to run than a key-value store behind an API.&lt;/p&gt;

&lt;h2&gt;
  
  
  Four Shapes, Not Eight Products
&lt;/h2&gt;

&lt;p&gt;Everything in this category collapses into four operating models.&lt;/p&gt;

&lt;p&gt;Run your own engine (Vault, OpenBao) and you get dynamic secrets, PKI and encryption as a service, plus a cluster to keep alive at 3am. Buy a SaaS platform (Infisical, Doppler) and you get a solid CLI, environment sync and a bill that meters either seats or identities. Use whatever your cloud already ships (AWS Secrets Manager, Google Secret Manager, Azure Key Vault) and it inherits your existing IAM and audit trail, charged per secret or per call. Or skip servers entirely with SOPS plus age, encrypting values inside files you commit.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Shape&lt;/th&gt;
&lt;th&gt;License&lt;/th&gt;
&lt;th&gt;Dynamic secrets&lt;/th&gt;
&lt;th&gt;Cost&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Vault&lt;/td&gt;
&lt;td&gt;Self-hosted engine&lt;/td&gt;
&lt;td&gt;BUSL 1.1&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Community free, Enterprise quoted&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OpenBao&lt;/td&gt;
&lt;td&gt;Self-hosted engine&lt;/td&gt;
&lt;td&gt;MPL 2.0&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Free, 8 vendors sell support&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Infisical&lt;/td&gt;
&lt;td&gt;SaaS + self-host&lt;/td&gt;
&lt;td&gt;MIT core&lt;/td&gt;
&lt;td&gt;Advanced tier&lt;/td&gt;
&lt;td&gt;Free 5 identities, $20-$40/identity/mo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Doppler&lt;/td&gt;
&lt;td&gt;SaaS&lt;/td&gt;
&lt;td&gt;Proprietary&lt;/td&gt;
&lt;td&gt;Enterprise tier&lt;/td&gt;
&lt;td&gt;Free 3 users, Team $21/user/mo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AWS Secrets Manager&lt;/td&gt;
&lt;td&gt;Cloud native&lt;/td&gt;
&lt;td&gt;Proprietary&lt;/td&gt;
&lt;td&gt;Rotation Lambdas&lt;/td&gt;
&lt;td&gt;$0.40/secret/mo + $0.05/10k calls&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Google Secret Manager&lt;/td&gt;
&lt;td&gt;Cloud native&lt;/td&gt;
&lt;td&gt;Proprietary&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;$0.06/version/mo + $0.03/10k ops&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SOPS + age&lt;/td&gt;
&lt;td&gt;Encrypted in git&lt;/td&gt;
&lt;td&gt;MPL 2.0 / BSD&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;External Secrets Operator&lt;/td&gt;
&lt;td&gt;Kubernetes glue&lt;/td&gt;
&lt;td&gt;Apache 2.0&lt;/td&gt;
&lt;td&gt;Passes through&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two of these shapes in one org is the normal outcome, not a failure. Choosing the boundary on purpose is the part teams skip.&lt;/p&gt;

&lt;h2&gt;
  
  
  Vault Is Now an IBM Product
&lt;/h2&gt;

&lt;p&gt;Vault stays the deepest toolbox here and has not been open source since the Business Source License 1.1 switch in August 2023. Enterprise 2.0 arrived April 13, 2026 carrying workload identity federation for secret distribution, credential rotation targeting RHEL and Ubuntu hosts, envelope encryption for large payloads, a SPIFFE engine that issues JWT SVIDs, public CA support, and SCIM in beta.&lt;/p&gt;

&lt;p&gt;The release cadence changed more than the feature list did. Self-managed Enterprise now ships two feature releases a year, spring and fall, with monthly security patches, and IBM's SC2 policy guarantees at least two years of standard support per release with extended cover reaching year six. The HashiCorp support portal itself folds into IBM's on August 21, 2026.&lt;/p&gt;

&lt;p&gt;Community Edition remains free and still mints dynamic secrets. Skipping Enterprise costs you namespaces, DR replication, HSM auto-unseal and the compliance surface, and buys you a cluster to operate.&lt;/p&gt;

&lt;h2&gt;
  
  
  OpenBao Ships What Vault Bills For
&lt;/h2&gt;

&lt;p&gt;OpenBao branched off Vault's final MPL 2.0 release and now lives under the Linux Foundation with OpenSSF governance. It is maintained, not archived: 2.6.0 landed July 14, 2026 and 2.6.1 followed on July 22.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0ejmy6cz854kncoco3bl.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0ejmy6cz854kncoco3bl.webp" alt="The OpenBao homepage, describing a community-driven secrets manager and fork of Vault managed under the Linux Foundation's OpenSSF, with sponsors including GitLab, SAP and Proton" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The 2.6 line introduced namespace sealing, giving each namespace its own Shamir key material so a single tenant can be sealed off independently. Auto-unseal moved out into external &lt;code&gt;kms&lt;/code&gt; plugin binaries that restart themselves, a &lt;code&gt;sys/workflows&lt;/code&gt; API arrived for wrapping the standard API in simpler interfaces, the old unauthenticated root token generation endpoint was replaced with an authenticated one, and a distroless container image shipped. Version 2.5 had already added horizontal read scaling.&lt;/p&gt;

&lt;p&gt;Compare that list against the Vault price sheet: namespaces and read scaling are Enterprise line items, free here. GitLab, SAP, Proton, Fermilab, ControlPlane and Adfinis sponsor the project, NVIDIA shows up as an adopter, and eight companies sell commercial support.&lt;/p&gt;

&lt;p&gt;The real cost is gravity. Vault has more tutorials, more answered Stack Overflow questions and more engineers who have already survived an outage with it. API compatibility carries most of that knowledge across, but you are the one signing off.&lt;/p&gt;

&lt;h2&gt;
  
  
  SaaS: Read the Meter, Not the Feature List
&lt;/h2&gt;

&lt;p&gt;Infisical and Doppler are both polished, both have a CLI that injects secrets into a running process, both sync into CI and cloud providers, and both self-host on paid tiers. Their feature grids will not decide anything for you. Their billing units will.&lt;/p&gt;

&lt;p&gt;Infisical is MIT at the core with 27,000 GitHub stars and charges per identity. Free covers 5 identities, 3 environments and 10 syncs. Pro runs $20 per identity per month annually ($23 monthly) with access controls, rotation, SAML SSO and 30-day audit logs. Advanced doubles that to $40 and unlocks dynamic secrets, honey tokens, custom roles and 90-day logs. Enterprise adds approvals, LDAP, SCIM, KMIP and self-hosting.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxe580yd1a3g24jn8mpl5.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxe580yd1a3g24jn8mpl5.webp" alt="The Doppler pricing page showing Developer free for three users, Team at $21 per user per month, and a note that AI agents and non-human identities do not count as seats" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Doppler charges per human instead. Developer is free up to 3 users, then $8 a month each. Team is $21 per user per month with change requests, SAML SSO, RBAC, 90-day logs and automatic rotation. Enterprise adds dynamic secrets and log forwarding. Doppler states plainly that AI agents and non-human identities are free and never consume a seat.&lt;/p&gt;

&lt;p&gt;Put a shape to it. Eight engineers running 150 services and agents costs roughly $168 a month on Doppler Team; the same estate on Infisical Pro, if each of those 150 identities bills, lands in four figures. Invert it, three engineers with 10 identities, and Infisical is cheap while both are affordable. So count your machine identities before you open either pricing page. That number is outgrowing your headcount and it is the widest cost gap in the category.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Cloud Manager You Are Already Paying For
&lt;/h2&gt;

&lt;p&gt;Living in one cloud makes the native manager the least work available. It already sits inside your IAM policies, already lands in CloudTrail, and needs no cluster.&lt;/p&gt;

&lt;p&gt;AWS Secrets Manager bills $0.40 per secret per month plus $0.05 per 10,000 API calls. Google Secret Manager bills $0.06 per active version per location per month plus $0.03 per 10,000 access operations, with rotation notifications at $0.05 and destroyed versions free. Azure Key Vault meters per 10,000 operations rather than per stored secret.&lt;/p&gt;

&lt;p&gt;Volume is where this bites. 500 secrets on AWS is $200 a month before anything reads them, and per-secret pricing nudges teams into cramming many values into one JSON blob, which silently deletes per-secret access control. At that scale, Google's per-version rate or your own engine costs less. Anything that is configuration rather than a credential belongs in AWS Systems Manager Parameter Store standard parameters, which are free.&lt;/p&gt;

&lt;h2&gt;
  
  
  SOPS and age: Encryption Without a Server
&lt;/h2&gt;

&lt;p&gt;SOPS is a CNCF sandbox project that encrypts only the values in YAML, JSON or &lt;code&gt;.env&lt;/code&gt; files, leaving keys in the clear so an encrypted file still diffs meaningfully in git. Pair it with age and no cloud KMS is involved at all.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8fc62444z82mz3qlajhy.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8fc62444z82mz3qlajhy.webp" alt="The getsops/sops repository on GitHub, the CNCF sandbox tool for encrypting values inside YAML, JSON, ENV and INI files" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The entire setup, on sops 3.13.3 and age 1.3.1:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;age-keygen &lt;span class="nt"&gt;-o&lt;/span&gt; key.txt                      &lt;span class="c"&gt;# prints the public key to stderr&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; .sops.yaml &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;YAML&lt;/span&gt;&lt;span class="sh"&gt;'
creation_rules:
  - path_regex: &lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="sh"&gt;yaml$
    age: age1v0hwa90c72kq737nmldg25kragalsez390fefpahyu9y8n5tsdcsukz20r
&lt;/span&gt;&lt;span class="no"&gt;YAML
&lt;/span&gt;sops &lt;span class="nt"&gt;--encrypt&lt;/span&gt; &lt;span class="nt"&gt;--in-place&lt;/span&gt; secrets.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What gets committed keeps every structural key and loses every value:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ENC[AES256_GCM,data:VR2SjbbqDZ4tQgE=,iv:p6Vh3yvG1i7hDZVok16lnU5ekraECwG6nA/OSrEKcmM=,tag:cT71TttqKRWcuKkEAY+wtw==,type:str]&lt;/span&gt;
    &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ENC[AES256_GCM,data:fyaQknjAvt2gYR+Ebfr2B64=,iv:1t+3u5JEBvt7B9z9PyrzrkBa4cKX30ALTmiT4MJH+ls=,tag:sLeVLckj0U//drSKrq+10Q==,type:str]&lt;/span&gt;
&lt;span class="na"&gt;stripe&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;secret_key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ENC[AES256_GCM,data:EYm3G333nlxQzRPJrrQD4YFdBotUADQ/d7rH,iv:d4us0HydwkJMzrevJw38Rb0J7Bge736ZiG2FvabuwZU=,tag:HB+hnnJJ8pKLf+QSOsfwPA==,type:str]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Confirming the round trip actually works, against that same file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ grep -c 'database:\|stripe:\|password:\|secret_key:' secrets.yaml
4
$ grep -c 'hunter2\|sk_live_51H' secrets.yaml
0
$ SOPS_AGE_KEY_FILE=key.txt sops --decrypt secrets.yaml
database:
    host: db.internal
    password: hunter2-but-worse
stripe:
    secret_key: sk_live_51Hxxxxxxxxxxxxxxxx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Four keys readable, zero plaintext values, decrypt returns the originals. Missing from this picture: rotation, leases, dynamic secrets and any audit log, and the age key is now your distribution problem. For a homelab, a three-person team or the manifests in a GitOps repo, that is frequently the right trade.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make the Decision Reversible First
&lt;/h2&gt;

&lt;p&gt;External Secrets Operator, another CNCF sandbox project, matters no matter which shape you pick. It runs inside your cluster, pulls from Vault, OpenBao, AWS, Google, Azure, Infisical or Doppler, and turns a declarative &lt;code&gt;ExternalSecret&lt;/code&gt; into a native Kubernetes Secret.&lt;/p&gt;

&lt;p&gt;That layer of indirection is the whole point. Your applications read an ordinary Secret, the operator holds the provider integration, and swapping AWS Secrets Manager for OpenBao edits one resource instead of every deployment. On Kubernetes, install it before you commit to any provider.&lt;/p&gt;

&lt;h2&gt;
  
  
  Picking One
&lt;/h2&gt;

&lt;p&gt;Need dynamic database credentials or internal PKI? OpenBao when license terms or budget block you, Vault when you want the vendor relationship and the ecosystem. Both deliver; one carries a BUSL.&lt;/p&gt;

&lt;p&gt;Single cloud with tens of secrets? Use the native manager and stop there. Bolting a secrets platform onto an estate that already has IAM buys nothing at that size.&lt;/p&gt;

&lt;p&gt;More services and agents than engineers? Price Doppler per seat against Infisical per identity using your real numbers.&lt;/p&gt;

&lt;p&gt;Want self-hosting with a modern UI? Infisical, MIT at the core, unless leases and dynamic secrets outrank the interface, in which case OpenBao.&lt;/p&gt;

&lt;p&gt;Small team on GitOps with no server budget? SOPS with age, and be honest with yourself that you picked encryption over rotation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Out of .env Files
&lt;/h2&gt;

&lt;p&gt;Gather every &lt;code&gt;.env&lt;/code&gt;, CI variable and shared credential note first. A diff across environments catches the variable that somehow only exists in production, and &lt;a href="https://devtoollab.com/tools/env-file-diff-checker" rel="noopener noreferrer"&gt;DevToolLab's Env File Diff Checker&lt;/a&gt; does that in the browser. Lint those files before migrating them, because duplicate keys and unquoted values with spaces surface later as bugs that look like secret-manager failures.&lt;/p&gt;

&lt;p&gt;Treat every value that ever touched git as public and rotate it. Then pick one boundary, write down which system owns application credentials and which owns infrastructure credentials, and hand workloads an identity rather than a token: OIDC federation in CI, IRSA or workload identity in Kubernetes, so short-lived credentials replace static ones.&lt;/p&gt;

&lt;p&gt;Verify what actually landed. A base64 round trip is where mismatched values usually show themselves, and &lt;a href="https://devtoollab.com/tools/kubernetes-secret-decoder" rel="noopener noreferrer"&gt;the Kubernetes Secret Decoder&lt;/a&gt; will tell you what the cluster is really holding. Delete the originals last, then add scanning so they cannot creep back. The &lt;a href="https://devtoollab.com/blog/best-secrets-management-tools" rel="noopener noreferrer"&gt;full guide on DevToolLab&lt;/a&gt; walks through each of those steps with the specific tooling.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;What changed in 2026 is that the open options stopped being compromises, so the license became the deciding variable instead of the capability. OpenBao ships namespaces and horizontal read scaling under MPL 2.0. Infisical is MIT at the core. SOPS costs nothing and runs no server. External Secrets Operator keeps the whole decision reversible. Vault is still the most capable thing here and is now an IBM product on an IBM cadence with no budget SaaS door. Count your non-human identities, settle whether dynamic secrets are genuinely required, and then choose the meter you can live with.&lt;/p&gt;

&lt;p&gt;Prices and versions move fast. Check each vendor's page before committing.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://devtoollab.com/blog/best-secrets-management-tools" rel="noopener noreferrer"&gt;Best Secrets Management Tools in 2026, the original article on DevToolLab&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.hashicorp.com/vault" rel="noopener noreferrer"&gt;HashiCorp Vault&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://openbao.org/" rel="noopener noreferrer"&gt;OpenBao&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://infisical.com/pricing" rel="noopener noreferrer"&gt;Infisical pricing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.doppler.com/pricing" rel="noopener noreferrer"&gt;Doppler pricing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/secrets-manager/pricing/" rel="noopener noreferrer"&gt;AWS Secrets Manager pricing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cloud.google.com/secret-manager/pricing" rel="noopener noreferrer"&gt;Google Secret Manager pricing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/getsops/sops" rel="noopener noreferrer"&gt;SOPS&lt;/a&gt; and &lt;a href="https://github.com/FiloSottile/age" rel="noopener noreferrer"&gt;age&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://external-secrets.io/latest/" rel="noopener noreferrer"&gt;External Secrets Operator&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devops</category>
      <category>security</category>
      <category>opensource</category>
      <category>programming</category>
    </item>
    <item>
      <title>Container Security in 2026: Why One Free Scanner Beats a $32B Acquisition on Half the Job</title>
      <dc:creator>Moksh Gupta</dc:creator>
      <pubDate>Wed, 02 Sep 2026 17:44:54 +0000</pubDate>
      <link>https://dev.to/moksh/container-security-in-2026-why-one-free-scanner-beats-a-32b-acquisition-on-half-the-job-228d</link>
      <guid>https://dev.to/moksh/container-security-in-2026-why-one-free-scanner-beats-a-32b-acquisition-on-half-the-job-228d</guid>
      <description>&lt;p&gt;Every container image is somebody else's OS packages zipped into layers, and whatever base image you picked last quarter is still shipping today, unchanged, every time CI runs. That's the uncomfortable part of container security: it's never a one-time check, because the image you scanned yesterday isn't the image that ships tomorrow.&lt;/p&gt;

&lt;p&gt;Here's a number that makes the point. On September 2, 2026, running Trivy against &lt;code&gt;node:18-alpine&lt;/code&gt; turned up 17 HIGH and CRITICAL OS vulnerabilities. Running it against &lt;code&gt;alpine:3.20&lt;/code&gt; turned up zero. Same scanner, same afternoon, one line changed in a Dockerfile. Meanwhile Google closed its $32 billion purchase of Wiz back in March 2026, the biggest acquisition in company history, buying a platform that solves a problem overlapping heavily with what that free 37,000-star binary just did in under a minute. &lt;a href="https://devtoollab.com/blog/container-security-tools" rel="noopener noreferrer"&gt;I wrote up the full comparison on DevToolLab&lt;/a&gt;, including every tool's current pricing and license.&lt;/p&gt;

&lt;p&gt;Both of those facts are true at once because "container security" isn't one job. It's three.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three jobs, not one
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Build-time scanning&lt;/strong&gt; looks at an image or manifest and checks it against a CVE database. Fast, runs in CI, catches known vulnerabilities and misconfig before deploy. Blind to anything happening at runtime.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Runtime detection&lt;/strong&gt; watches kernel events on live workloads and flags abnormal behavior: a container spawning a shell, reading &lt;code&gt;/etc/shadow&lt;/code&gt;, opening an unexpected connection. This is what catches a zero-day nothing in a database has heard of yet. It can't stop a bad image from shipping in the first place.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Posture and compliance&lt;/strong&gt; checks your cluster config against a framework like CIS Benchmarks or SOC 2. It answers the auditor's question, not the attacker's.&lt;/p&gt;

&lt;p&gt;Most teams need exactly one tool per job. A platform selling you "all three in one" is usually a budget conversation dressed up as a coverage conversation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scanning before it ships
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4hkgzpfj0uswhytnxfhp.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4hkgzpfj0uswhytnxfhp.webp" alt="Trivy scanning CVEs, IaC misconfigurations and secrets across images, filesystems and Kubernetes clusters" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://trivy.dev/" rel="noopener noreferrer"&gt;Trivy&lt;/a&gt; is the default pick for most teams, and for good reason: one Go binary (v0.74.0 as of mid-August 2026) covers container images, filesystems, git repos, Kubernetes manifests and IaC, handling CVEs, secrets, misconfig and SBOM generation in one pass. It reads straight from a registry, so no Docker daemon required.&lt;/p&gt;

&lt;p&gt;The misconfig scanner is underrated. Pointing &lt;code&gt;trivy config&lt;/code&gt; at a deliberately sloppy Dockerfile turned up 4 failures out of 27 checks, including a CRITICAL for a token passed through an &lt;code&gt;ENV&lt;/code&gt; line and a flag on &lt;code&gt;USER root&lt;/code&gt;. Neither of those is a CVE. Both are exactly how containers get popped in practice. What Trivy won't do is prioritize for you: 200 findings get treated the same whether they're on an internet-facing API or a monthly batch job. That triage is on you.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/anchore/grype" rel="noopener noreferrer"&gt;Grype&lt;/a&gt; takes the SBOM-first route: pair it with Syft, generate a bill of materials once, then scan that artifact repeatedly instead of re-reading the image each time. It's narrower than Trivy on purpose, doing vulnerability matching well and staying out of IaC and secrets entirely.&lt;/p&gt;

&lt;p&gt;If your org already pays for Docker, &lt;a href="https://www.docker.com/products/docker-scout/" rel="noopener noreferrer"&gt;Docker Scout&lt;/a&gt; is one command away, but repo limits bite fast: one Scout-enabled repo on Personal, two on Pro at $11/user/month, unlimited only from Team at $16/user/month. Fine for a single flagship image, expensive for a microservice fleet. &lt;a href="https://snyk.io/product/container-vulnerability-management/" rel="noopener noreferrer"&gt;Snyk Container&lt;/a&gt; leans the other direction, leading with base-image remediation advice rather than a flat CVE list, though it's usually sold bundled with Snyk Open Source rather than standalone.&lt;/p&gt;

&lt;h2&gt;
  
  
  What scanning can't see
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Few6g9mwpge9mvxa64yez.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Few6g9mwpge9mvxa64yez.webp" alt="Falco, a CNCF graduated runtime security tool using eBPF to detect abnormal container behavior" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://falco.org/" rel="noopener noreferrer"&gt;Falco&lt;/a&gt; is a CNCF graduated project (the foundation's top maturity tier) using eBPF to watch kernel events in real time. A container that suddenly execs a shell or mounts something it shouldn't triggers an alert immediately, no CVE database required. The catch: it's detection-only, and the default ruleset is noisy enough against real production workloads that an unattended alert stream is worse than useless. Budget actual time for tuning.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://tetragon.io/" rel="noopener noreferrer"&gt;Tetragon&lt;/a&gt;, a Cilium sub-project, goes a step further: because policy runs in-kernel via eBPF, it can enforce, not just observe, killing a process outright rather than just logging it. That enforcement is also the risk. Most teams run it in observation mode first before trusting it to kill anything in prod.&lt;/p&gt;

&lt;h2&gt;
  
  
  Compliance and the paid tier
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffto72vkumamuur8a4yhp.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffto72vkumamuur8a4yhp.webp" alt="Kubescape, an open-source Kubernetes security platform covering configuration scanning, compliance and runtime threat detection" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://kubescape.io/" rel="noopener noreferrer"&gt;Kubescape&lt;/a&gt; (CNCF incubating, v4.0.12) scans clusters, manifests and Helm charts against CIS Benchmarks, NSA-CISA guidance, MITRE ATT&amp;amp;CK and SOC 2, producing the actual artifact an auditor will accept. It also checks network policies and seccomp profiles, which nobody enjoys doing by hand.&lt;/p&gt;

&lt;p&gt;On the commercial side, &lt;a href="https://www.wiz.io/" rel="noopener noreferrer"&gt;Wiz&lt;/a&gt; (now part of Google Cloud) sells correlation: tying a container CVE to cloud IAM exposure and network reachability so you know which of your 200 findings is actually exploitable from the internet. That's genuinely something open-source scanners don't do. Sysdig and Aqua Security play similar territory, both quote-only, both clearly built for a buyer with a procurement department. None of it is detection Trivy and Falco can't already do; what you're buying is prioritization and a support contract. &lt;a href="https://devtoollab.com/blog/container-security-tools" rel="noopener noreferrer"&gt;The original post breaks down where each paid platform actually earns its price&lt;/a&gt; versus where it's just consolidation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wiring it into CI
&lt;/h2&gt;

&lt;p&gt;The highest-value hour here is simple: fail builds on new HIGH/CRITICAL findings with an available fix, ignore everything else until you have a real triage process.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# scan locally first, no daemon needed&lt;/span&gt;
trivy image &lt;span class="nt"&gt;--severity&lt;/span&gt; HIGH,CRITICAL &lt;span class="nt"&gt;--scanners&lt;/span&gt; vuln node:18-alpine
trivy config &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In GitHub Actions, &lt;code&gt;ignore-unfixed: true&lt;/code&gt; matters more than any other flag, since failing a build on a CVE with no patch just trains developers to ignore the scanner entirely:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run Trivy vulnerability scanner&lt;/span&gt;
  &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aquasecurity/trivy-action@v0.36.0&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image-ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;docker.io/my-organization/my-app:${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;github.sha&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}'&lt;/span&gt;
    &lt;span class="na"&gt;exit-code&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;1'&lt;/span&gt;
    &lt;span class="na"&gt;ignore-unfixed&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;severity&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;CRITICAL,HIGH'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pin and update your base image regularly. The 17-versus-zero gap above came entirely from a base image swap, not a code change, and it's the single highest-leverage fix on this whole list.&lt;/p&gt;

&lt;p&gt;If you're auditing what's actually in a Dockerfile, DevToolLab's &lt;a href="https://devtoollab.com/tools/dockerignore-generator" rel="noopener noreferrer"&gt;dockerignore generator&lt;/a&gt; is worth a minute to make sure &lt;code&gt;.env&lt;/code&gt; and &lt;code&gt;.git&lt;/code&gt; never reach the build context a scanner has to find in the first place.&lt;/p&gt;

&lt;h2&gt;
  
  
  Picking a stack
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Solo dev or side project:&lt;/strong&gt; Trivy in CI, nothing else. Fail on fixable HIGH/CRITICAL, bump the base image monthly. Costs nothing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Small team on Kubernetes:&lt;/strong&gt; Trivy in CI plus Kubescape on a weekly cron against the cluster. Add Falco in observation mode once someone's actually committed to reading the alerts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Regulated environment:&lt;/strong&gt; Kubescape for SOC 2/CIS evidence, Trivy for scanning, Tetragon where a control specifically demands prevention over detection. Fully open source, fully auditable, and the cost shows up as configuration time instead of a license line.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Large multi-cloud fleet with a security team:&lt;/strong&gt; This is genuinely where Wiz, Sysdig or Aqua pay for themselves. At thousands of findings across several clouds, knowing which twelve are actually reachable is the product.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://devtoollab.com/blog/container-security-tools" rel="noopener noreferrer"&gt;Container Security Tools Compared, on DevToolLab&lt;/a&gt; - the full comparison with pricing tables, CNCF maturity status, and the complete CI workflow&lt;/li&gt;
&lt;li&gt;&lt;a href="https://trivy.dev/" rel="noopener noreferrer"&gt;Trivy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/anchore/grype" rel="noopener noreferrer"&gt;Grype&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://falco.org/" rel="noopener noreferrer"&gt;Falco&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://tetragon.io/" rel="noopener noreferrer"&gt;Tetragon&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kubescape.io/" rel="noopener noreferrer"&gt;Kubescape&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.wiz.io/" rel="noopener noreferrer"&gt;Wiz&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devops</category>
      <category>security</category>
      <category>docker</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>Browser Agent Tools in 2026: What the Licenses and Benchmarks Actually Say</title>
      <dc:creator>Moksh Gupta</dc:creator>
      <pubDate>Wed, 02 Sep 2026 05:01:10 +0000</pubDate>
      <link>https://dev.to/moksh/browser-agent-tools-in-2026-what-the-licenses-and-benchmarks-actually-say-1ep8</link>
      <guid>https://dev.to/moksh/browser-agent-tools-in-2026-what-the-licenses-and-benchmarks-actually-say-1ep8</guid>
      <description>&lt;p&gt;Anyone who has pointed a scraper at a modern SaaS pricing page knows the failure mode: the request succeeds, the HTML is enormous, and the number you came for is nowhere in it. The page assembles itself in JavaScript after the response lands, so a plain HTTP client sees the scaffolding and none of the content.&lt;/p&gt;

&lt;p&gt;Here is the version of that I measured. Azure's Content Safety pricing page, hit twice inside the same minute: &lt;code&gt;fetch&lt;/code&gt; handed back 212kB of markup with zero dollar figures in it, and a real Chrome instance handed back 6kB of rendered text containing both $0.38 and $0.75.&lt;/p&gt;

&lt;p&gt;That one gap explains why this whole tool category exists. Two other findings from the same afternoon are worth your attention before you pick anything: the WebVoyager percentages that show up in every comparison post are not measured against the same denominator, and one of the four most-starred open frameworks ships under AGPL-3.0. I checked every license, version and price below against the project's own repo or pricing page in August 2026. The fuller writeup, including the complete test script, is &lt;a href="https://devtoollab.com/blog/best-ai-browser-automation-tools" rel="noopener noreferrer"&gt;on DevToolLab&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  One Label, Three Unrelated Products
&lt;/h2&gt;

&lt;p&gt;"AI browser automation" gets stuck on three things that do not compete with each other.&lt;/p&gt;

&lt;p&gt;Consumer AI browsers (Atlas, Comet, Dia) are end-user products, not something you build against. Agent frameworks are libraries that let a model decide what to click. Managed infrastructure runs the browser somewhere else and deals with proxies, fingerprints and concurrency limits, while staying completely indifferent to what your agent does once the page loads.&lt;/p&gt;

&lt;p&gt;Most real deployments pair a framework with infrastructure. That pairing is also why Browserbase sells hosting and gives away Stagehand.&lt;/p&gt;

&lt;h2&gt;
  
  
  First, Prove You Need a Browser
&lt;/h2&gt;

&lt;p&gt;Rendering a page is the slowest and most expensive way to read it, so settle that question before you shop for tooling. You can test it with nothing but Node's built-in &lt;code&gt;fetch&lt;/code&gt; and &lt;code&gt;WebSocket&lt;/code&gt; against a Chrome started with its debugging port exposed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="s2"&gt;"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--remote-debugging-port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;9333 &lt;span class="nt"&gt;--headless&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;new &lt;span class="nt"&gt;--no-first-run&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--user-data-dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/tmp/cdp-demo about:blank
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From there you open a tab over &lt;code&gt;http://localhost:9333/json/new?&amp;lt;url&amp;gt;&lt;/code&gt;, attach to &lt;code&gt;webSocketDebuggerUrl&lt;/code&gt;, call &lt;code&gt;Runtime.enable&lt;/code&gt;, then poll &lt;code&gt;Runtime.evaluate&lt;/code&gt; on &lt;code&gt;document.body.innerText&lt;/code&gt; until a price regex matches instead of sleeping for an arbitrary number of seconds. The &lt;a href="https://devtoollab.com/blog/best-ai-browser-automation-tools" rel="noopener noreferrer"&gt;full script is in the original article&lt;/a&gt; if you want to paste and run it.&lt;/p&gt;

&lt;p&gt;Two of the four runs I logged:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;plain fetch    12208ms  212kB html  prices found: NONE
real browser    2134ms  6kB text  prices found: $0.38, $0.75

plain fetch    11040ms  212kB html  prices found: NONE
real browser    4087ms  6kB text  prices found: $0.38, $0.75
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Treat the timings as incidental. A static page would reverse them. The payload sizes are the finding: 212kB of markup containing nothing a person would read off the screen, versus 6kB of text containing all of it. Hand the fetch output to an agent and it will confidently tell you Azure publishes no pricing, which is exactly the wrong answer I got the first time.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Open Source Field
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqiwicjyye5840k997xfo.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqiwicjyye5840k997xfo.webp" alt="The browser-use homepage, headlined " width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/browser-use/browser-use" rel="noopener noreferrer"&gt;browser-use&lt;/a&gt;&lt;/strong&gt; is MIT, v0.13.7 as of July 27, 2026, and wants Python 3.11 or newer plus an LLM key. It has the largest community and the most sample code, which makes it the reasonable default. Its docs are also candid about the ceiling: CAPTCHAs push you toward their hosted stealth browsers, memory climbs as soon as you run tasks in parallel, and they steer production workloads to their cloud.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbh08cpo5ybbu5eslay4i.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbh08cpo5ybbu5eslay4i.webp" alt="The Stagehand homepage at stagehand.dev, headlined " width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/browserbase/stagehand" rel="noopener noreferrer"&gt;Stagehand&lt;/a&gt;&lt;/strong&gt; is Browserbase's own, MIT, v4.0.0 on August 10, 2026, with SDKs for TypeScript, Python and Go. Instead of dumping a page into a model and hoping for the best, it gives you &lt;code&gt;act&lt;/code&gt;, &lt;code&gt;extract&lt;/code&gt; and &lt;code&gt;observe&lt;/code&gt; as discrete calls. That means each step is something you can log, cache and write an assertion against. If you have ever watched a twelve-step agent quietly do the wrong thing at step seven and had no trace to inspect, this is the design that fixes it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdet4m3s0edf02ysqdiw5.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdet4m3s0edf02ysqdiw5.webp" alt="The Skyvern homepage, headlined " width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/Skyvern-AI/skyvern" rel="noopener noreferrer"&gt;Skyvern&lt;/a&gt;&lt;/strong&gt; sits at v1.0.48 (August 5, 2026) and is the one to read the LICENSE file on first: it is &lt;strong&gt;AGPL-3.0&lt;/strong&gt;, not MIT and not Apache. Internal use is unproblematic. Shipping or hosting it means a conversation with whoever handles licensing at your company. Most roundups file it next to the permissive projects and never mention the difference. Technically it is the vision-first option, working from the rendered page rather than element IDs, which holds up better when a site's markup churns weekly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/microsoft/playwright-mcp" rel="noopener noreferrer"&gt;Playwright MCP&lt;/a&gt;&lt;/strong&gt; is Microsoft's, Apache 2.0, v0.0.79 (August 6, 2026). It hands Playwright to any MCP client, so an existing coding agent picks up a browser with no glue code, navigating via structured accessibility snapshots instead of a vision model. The version string is refreshingly honest about how young it is; the underlying lineage is the strongest in the category.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/steel-dev/steel-browser" rel="noopener noreferrer"&gt;Steel&lt;/a&gt;&lt;/strong&gt; (Apache 2.0) is the outlier: open source browser &lt;em&gt;infrastructure&lt;/em&gt; rather than an agent framework, effectively a self-hostable Browserbase. It is where you start when session data is not allowed to leave your own network.&lt;/p&gt;

&lt;h2&gt;
  
  
  Browserbase, and What "Browser Hours" Bills For
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Feiad3zg7nexxz7jdedhl.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Feiad3zg7nexxz7jdedhl.webp" alt="The Browserbase pricing page showing a Free Plan at $0 per month with 3 concurrent browsers, 1 browser hour and a 15 minute session limit, beside a Developer Plan at $20 per month with 25 concurrent browsers and 100 browser hours" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Credit where it is due: Browserbase &lt;a href="https://www.browserbase.com/pricing" rel="noopener noreferrer"&gt;posts its prices publicly&lt;/a&gt;, which is not universal here.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Free:&lt;/strong&gt; $0, 1 browser hour, 3 concurrent, 15-minute session cap, 3 agent runs · &lt;strong&gt;Developer:&lt;/strong&gt; $20/month, 100 hours, 25 concurrent, $0.12 per additional hour · &lt;strong&gt;Startup:&lt;/strong&gt; $99/month, 500 hours, 100 concurrent, $0.10 per additional hour · &lt;strong&gt;Scale:&lt;/strong&gt; custom&lt;/p&gt;

&lt;p&gt;A single browser hour with a 15-minute ceiling per session is a trial, not a tier, so plan on Developer the moment anything runs on a cron. The pricing detail with real consequences: a browser hour is wall-clock time the session stays open, not compute consumed. An agent blocked on a slow network request bills identically to one doing work, which makes aggressive session teardown your main cost control. On the will-they-still-exist question, they raised a $40 million Series B in June 2025 at a $300 million valuation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Side by Side
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;License&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Self-hosted&lt;/th&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;a href="https://github.com/browser-use/browser-use" rel="noopener noreferrer"&gt;browser-use&lt;/a&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;MIT&lt;/td&gt;
&lt;td&gt;Agent framework, Python&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;v0.13.7, ~109.1k stars&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;a href="https://github.com/browserbase/stagehand" rel="noopener noreferrer"&gt;Stagehand&lt;/a&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;MIT&lt;/td&gt;
&lt;td&gt;Agent framework, TS/Python/Go&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;v4.0.0, ~23.9k stars&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;a href="https://github.com/Skyvern-AI/skyvern" rel="noopener noreferrer"&gt;Skyvern&lt;/a&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;AGPL-3.0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Vision-first agent framework&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;v1.0.48, ~22.7k stars&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;a href="https://github.com/microsoft/playwright-mcp" rel="noopener noreferrer"&gt;Playwright MCP&lt;/a&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Apache 2.0&lt;/td&gt;
&lt;td&gt;MCP server over Playwright&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;v0.0.79, ~36k stars&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;a href="https://github.com/steel-dev/steel-browser" rel="noopener noreferrer"&gt;Steel&lt;/a&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Apache 2.0&lt;/td&gt;
&lt;td&gt;Self-hostable browser infra&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;~7.5k stars&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;a href="https://www.browserbase.com/pricing" rel="noopener noreferrer"&gt;Browserbase&lt;/a&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Commercial&lt;/td&gt;
&lt;td&gt;Managed browser infra&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Free, then $20 or $99/month&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  WebVoyager Is Not a Leaderboard
&lt;/h2&gt;

&lt;p&gt;You will see 89.1 percent for browser-use next to 85.85 for Skyvern, laid out like standings. Both figures are honestly reported. Putting them side by side is still meaningless.&lt;/p&gt;

&lt;p&gt;The task counts do not match: browser-use scored over 586 tasks, Skyvern over 635, Agent-E over 643. The conditions diverge in the direction that flatters whoever is on top, since browser-use ran locally on clean IPs with no bot detection in the way while Skyvern ran in the cloud against live bot protection. In other words the lower number came out of the harder environment. Everything is self-reported, and the benchmark itself covers 643 tasks across 15 sites skewed toward reading, with logins, 2FA, form submission and downloads barely represented.&lt;/p&gt;

&lt;p&gt;That is not a criticism of either project. It just means 89 percent tells you nothing about how either behaves on a Cloudflare-protected target, and the only benchmark that predicts your results is your own task list.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Security Model Is Broken by Design, Not by Bug
&lt;/h2&gt;

&lt;p&gt;Stand back and look at what a browser agent is: private data reachable through your authenticated sessions, untrusted input because it is reading the open web, and outbound communication because filling in forms is the entire point. That is all three legs of the lethal trifecta, aimed at your own logged-in accounts.&lt;/p&gt;

&lt;p&gt;This is not theoretical. Brave published indirect prompt injection against Perplexity Comet, planting instructions in page elements no human would ever see and getting the agent to perform cross-site actions, one-time passcodes lifted out of email included. LayerX showed injected instructions can be persisted into an agent's long-term memory over CSRF and survive into later sessions.&lt;/p&gt;

&lt;p&gt;OpenAI's own security writeup calls prompt injection "one of the most significant risks we actively defend against," and as of late December 2025 their stated position is that it may never be fully solved for browser agents. The UK's National Cyber Security Centre reached the same conclusion. Practical upshot: give the agent a dedicated, narrowly scoped account that cannot move money, rotate credentials or reach a password reset inbox, and treat every page it visits as hostile input.&lt;/p&gt;

&lt;h2&gt;
  
  
  Picking One, and the First Five Steps
&lt;/h2&gt;

&lt;p&gt;Python codebase, take browser-use. Want per-step traces you can assert on, Stagehand. Form-heavy work on unstable markup and the AGPL question already answered, Skyvern. Already running MCP, Playwright MCP. Data cannot leave the building, Steel. Do not want to operate browsers at all, Browserbase starting at $20.&lt;/p&gt;

&lt;p&gt;Then, in this order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Verify a browser is necessary.&lt;/strong&gt; Run the fetch-versus-browser comparison against your actual target. If plain HTTP already has your data, walk away from this category.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check you are permitted to automate the path.&lt;/strong&gt; DevToolLab's &lt;a href="https://devtoollab.com/tools/robots-txt-tester" rel="noopener noreferrer"&gt;Robots.txt Tester&lt;/a&gt; tells you whether a specific URL is allowed for a given user agent.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lock down whatever is deterministic.&lt;/strong&gt; Confirm selectors in the &lt;a href="https://devtoollab.com/tools/xpath-tester" rel="noopener noreferrer"&gt;XPath Tester&lt;/a&gt; and reserve the model for the steps that genuinely need judgment. A selector costs nothing; an LLM call costs every time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shrink pages before they eat your context.&lt;/strong&gt; Raw HTML spends tokens on markup, and the &lt;a href="https://devtoollab.com/tools/html-to-markdown" rel="noopener noreferrer"&gt;HTML to Markdown&lt;/a&gt; converter makes the size difference obvious.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Least-privilege account plus a hard session timeout.&lt;/strong&gt; Both in place before the first scheduled run, not after.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The open source layer here is genuinely good and the marketing around it is not. browser-use owns the community and the MIT license, Stagehand has the most inspectable structure, Playwright MCP has the best pedigree, Steel answers data residency, and Skyvern is an AGPL-3.0 decision that deserves more than a footnote. Skip the WebVoyager table entirely, spend an afternoon running your own tasks, and design the security posture in from the start rather than bolting it on.&lt;/p&gt;

&lt;p&gt;Licenses, versions and prices in this category move fast. Confirm each one against the project's own repo before you commit to anything.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://devtoollab.com/blog/best-ai-browser-automation-tools" rel="noopener noreferrer"&gt;Original article on DevToolLab&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/browser-use/browser-use" rel="noopener noreferrer"&gt;browser-use on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/browserbase/stagehand" rel="noopener noreferrer"&gt;Stagehand on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Skyvern-AI/skyvern" rel="noopener noreferrer"&gt;Skyvern on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/microsoft/playwright-mcp" rel="noopener noreferrer"&gt;Playwright MCP on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/steel-dev/steel-browser" rel="noopener noreferrer"&gt;Steel Browser on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.browserbase.com/pricing" rel="noopener noreferrer"&gt;Browserbase pricing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devtoollab.com/blog/best-llm-guardrails-tools" rel="noopener noreferrer"&gt;Best LLM Guardrails Tools&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devtoollab.com/blog/best-mcp-servers" rel="noopener noreferrer"&gt;Best MCP Servers&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>programming</category>
      <category>opensource</category>
    </item>
    <item>
      <title>CI/CD Pricing in 2026: Why Your Seats Cost More Than Your Builds</title>
      <dc:creator>Moksh Gupta</dc:creator>
      <pubDate>Tue, 01 Sep 2026 18:54:39 +0000</pubDate>
      <link>https://dev.to/moksh/cicd-pricing-in-2026-why-your-seats-cost-more-than-your-builds-5c8m</link>
      <guid>https://dev.to/moksh/cicd-pricing-in-2026-why-your-seats-cost-more-than-your-builds-5c8m</guid>
      <description>&lt;p&gt;Pick a CI platform on features and you will end up comparing four YAML dialects that all do roughly the same thing. Pick one on its billing model and the differences get sharp fast, because these vendors do not meter the same units. One charges you per build minute, one per credit, one per seat with the compute thrown back at you.&lt;/p&gt;

&lt;p&gt;I dug through every vendor's published rates for a longer writeup on DevToolLab, &lt;a href="https://devtoollab.com/blog/best-ci-cd-tools" rel="noopener noreferrer"&gt;Best CI/CD Tools in 2026&lt;/a&gt;. This is the condensed version: what the meters actually cost, and which open-source engines skip them entirely.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Fee That Got Walked Back
&lt;/h2&gt;

&lt;p&gt;December 15, 2025 is the date to remember. GitHub said it would start charging $0.002 a minute as an Actions "cloud platform" fee on private-repo workflows, and critically that included jobs on runners you host and pay a cloud provider for yourself. Developers pushed back hard, and GitHub shelved the self-hosted portion within a couple of days. The hosted-runner discount survived and took effect January 1, 2026, cutting net prices by as much as 39 percent.&lt;/p&gt;

&lt;p&gt;Read that sequence carefully, because it tells you where the industry is heading. Raw compute is commoditizing. The orchestration layer sitting on top of it is what vendors now want to bill for. GitHub called the pause a re-evaluation rather than a cancellation, so anyone running a big self-hosted fleet should treat that fee as deferred, not dead.&lt;/p&gt;

&lt;h2&gt;
  
  
  Nobody Has Standardized
&lt;/h2&gt;

&lt;p&gt;JetBrains surveyed developers for its State of Developer Ecosystem 2025 and found GitHub Actions at 33 percent inside organizations, Jenkins at 28 percent, and GitLab CI at 19 percent. A further 18 percent reported no CI/CD tooling at all. Their follow-up State of CI/CD survey, 805 respondents, found roughly a third of organizations running two CI systems side by side.&lt;/p&gt;

&lt;p&gt;Jenkins holding second place is the surprise. It dates to 2011, runs on the JVM, and carries 2,102 plugins in its update center. It survives because nothing about it counts your seats or your minutes.&lt;/p&gt;

&lt;h2&gt;
  
  
  One Workload, Four Meters
&lt;/h2&gt;

&lt;p&gt;Rather than trust marketing pages, price a single realistic month against each vendor: ten active developers, twelve thousand Linux build minutes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Same workload, four billing models. Rates from vendor pricing pages,&lt;/span&gt;
&lt;span class="c1"&gt;// September 2026. Assumes GitHub Team seats, CircleCI Docker medium&lt;/span&gt;
&lt;span class="c1"&gt;// (10 credits/min), Buildkite 2-vCPU agents.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;devs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;minutes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;12000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;plans&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="c1"&gt;// name,                base, freeSeats, perSeat, freeMin, $/min&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GitHub Actions&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;         &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;         &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;       &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.006&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GitLab Premium&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;         &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;         &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;      &lt;span class="mi"&gt;29&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.010&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;CircleCI Performance&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;         &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;      &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.006&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Buildkite Pro&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;          &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;         &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;      &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.008&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;free&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;perSeat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;freeMin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;plans&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;seats&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;base&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;devs&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;free&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;perSeat&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;compute&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;minutes&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;freeMin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;padEnd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt; $&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;seats&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; seats + $&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;compute&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; compute`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;node ci-cost.mjs
GitHub Actions         &lt;span class="nv"&gt;$40&lt;/span&gt; seats + &lt;span class="nv"&gt;$54&lt;/span&gt; compute
GitLab Premium         &lt;span class="nv"&gt;$290&lt;/span&gt; seats + &lt;span class="nv"&gt;$20&lt;/span&gt; compute
CircleCI Performance   &lt;span class="nv"&gt;$90&lt;/span&gt; seats + &lt;span class="nv"&gt;$54&lt;/span&gt; compute
Buildkite Pro          &lt;span class="nv"&gt;$300&lt;/span&gt; seats + &lt;span class="nv"&gt;$80&lt;/span&gt; compute
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Totals: $94, $310, $144 and $380 a month. Look at which column carries the weight. Compute never breaks $80 anywhere, while seats swing by a factor of seven. GitLab and Buildkite bundle far more than a build runner into that seat, so this is not a fair feature comparison, but it does tell you which number to audit first when finance asks about the CI line.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Four You Pay For
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;GitHub Actions&lt;/strong&gt; wins on being already installed. Free tiers get 2,000 private-repo minutes monthly, Pro and Team 3,000, Enterprise Cloud 50,000, and public repos run free on standard runners. Post-January rates: $0.006 a minute for 2-core Linux x64, $0.005 arm64, $0.010 Windows, $0.062 macOS. Storage bites quietly. Artifacts run $0.25 per GB-month and cache runs $0.07 beyond a free 10 GB per repository.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpw6qgnwe5u5kxp6dxvdl.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpw6qgnwe5u5kxp6dxvdl.webp" alt="GitHub Actions product page showing a matrix build and deploy workflow" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitLab CI/CD&lt;/strong&gt; ships as one slice of a much larger platform. Free grants 400 compute minutes and five users per top-level group. Premium runs $29 per user monthly on an annual term with 10,000 minutes; Ultimate switched to quote-only pricing this year and includes 50,000. Overflow minutes are $10 per thousand as a one-off purchase. The detail worth stealing sits in GitLab's FAQ: your own runners never consume the quota and have no cap, on every tier including Free.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CircleCI&lt;/strong&gt; denominates everything in credits, so translation is mandatory before you can budget. Docker small costs 5 credits a minute, medium 10, large 20. Linux VM pricing varies by generation, with the default x86 medium at 10 and Gen 3 medium at 7. macOS M4 Pro medium sits at 200 credits a minute, which puts an iOS build around forty times a comparable Linux job. The free allotment is real though: 30,000 credits, five users, 30x concurrency.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwpnwf9jwkklbkfobki2w.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwpnwf9jwkklbkfobki2w.webp" alt="CircleCI homepage with the tagline Validate everything, assume nothing" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Buildkite&lt;/strong&gt; splits the job. Their servers handle scheduling, logs, secrets and the interface; your machines execute the work. Free covers five users and 2,000 Linux vCPU-minutes. Pro is $30 per active user monthly for up to fifty users, ten agents included and $3.50 for each one after. Optional managed agents cost $0.004 per vCPU-minute on Linux, so a 2-vCPU box lands at $0.008 of wall-clock time. Agents you own incur no per-minute charge whatsoever.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Four You Host
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Jenkins&lt;/strong&gt; remains MIT-licensed with 26.5k stars and LTS 2.568.2 as of August 5, 2026. Java 21 is mandatory from the 2.555 line forward. There is no meter and no seat count, and in exchange you own a controller, a JVM and a plugin dependency graph that turns into a part-time job somewhere past two hundred plugins. Reach for it when build steps refuse to containerize or when hardware legally cannot leave your premises.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Semaphore Community Edition&lt;/strong&gt; is the newest option worth attention, because Semaphore released its engine under Apache 2.0. Self-hosted means unlimited users and unlimited concurrency, with artifacts, test dashboards and flaky-test detection in the box. Two things to know: the &lt;code&gt;ee&lt;/code&gt; directory carries a separate Enterprise license covering SAML, RBAC and audit logs, and the newest tag is v1.5.0 from October 10, 2025 even though main gets daily commits. Pin your version. Their cloud offering charges $0.0075 a minute for 2-vCPU x64 with no seat fee at all.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyfz1e7bihb6prxe0z02x.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyfz1e7bihb6prxe0z02x.webp" alt="Semaphore Open Source page comparing Community Edition against Enterprise" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Woodpecker CI&lt;/strong&gt; split off from Drone back in 2021 when a licensing change clamped down on self-hosting. It is Apache 2.0, sits at 7.8k stars, and shipped v3.18.0 on August 24, 2026. Architecture is a Go server plus agents, every step is a container, and it speaks GitHub, GitLab, Gitea, Forgejo and Bitbucket. Expect no hosted tier, no test analytics, and plugins numbering in the dozens rather than thousands.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Argo CD&lt;/strong&gt; belongs in a different column entirely. It is a CNCF graduated GitOps reconciler that syncs a cluster against a Git repo, so it substitutes for your deploy stage, not your build stage. CNCF's July 2025 end user survey put it in nearly 60 percent of Kubernetes clusters doing application delivery, with 97 percent of respondents running it in production and an NPS of 79. Currently v3.5.2. Treat CI selection and CD selection as two separate calls.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Meter&lt;/th&gt;
&lt;th&gt;Starting point&lt;/th&gt;
&lt;th&gt;License&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;GitHub Actions&lt;/td&gt;
&lt;td&gt;Seats plus minutes&lt;/td&gt;
&lt;td&gt;2,000 free min, $0.006/min after&lt;/td&gt;
&lt;td&gt;Proprietary&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GitLab CI/CD&lt;/td&gt;
&lt;td&gt;Seats plus minutes&lt;/td&gt;
&lt;td&gt;400 free min, Premium $29/user&lt;/td&gt;
&lt;td&gt;Open core&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CircleCI&lt;/td&gt;
&lt;td&gt;Seats plus credits&lt;/td&gt;
&lt;td&gt;30,000 free credits, $15/mo up&lt;/td&gt;
&lt;td&gt;Proprietary&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Buildkite&lt;/td&gt;
&lt;td&gt;Seats, you supply agents&lt;/td&gt;
&lt;td&gt;5 free users, Pro $30/user&lt;/td&gt;
&lt;td&gt;Proprietary&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Jenkins&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;MIT&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Semaphore CE&lt;/td&gt;
&lt;td&gt;None self-hosted&lt;/td&gt;
&lt;td&gt;Free, cloud $0.0075/min&lt;/td&gt;
&lt;td&gt;Apache 2.0, open core&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Woodpecker&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;Apache 2.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Argo CD&lt;/td&gt;
&lt;td&gt;None, CD only&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;Apache 2.0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Picking One
&lt;/h2&gt;

&lt;p&gt;Start with two numbers off last month's invoice: build minutes consumed and humans who actually committed. Feed them through the script above. Where seats dominate, hunting a lower per-minute rate is wasted effort.&lt;/p&gt;

&lt;p&gt;Confirm the macOS multiplier before committing if you ship mobile, since that single line dwarfs everything else on both CircleCI and GitHub. Ask each vendor what bringing your own runners costs, because the answers genuinely differ: GitLab meters nothing, Buildkite charges no per-minute fee, GitHub charges nothing today with a caveat attached. Then trial on your slowest genuine pipeline instead of a toy repo, and time it with caches cold.&lt;/p&gt;

&lt;p&gt;Keep the definition portable while you are at it. Containerized steps and plain shell survive a migration; vendor orbs, marketplace actions and Groovy pipelines do not. Two utilities that help around the edges: &lt;a href="https://devtoollab.com/tools/dockerfile-linter" rel="noopener noreferrer"&gt;Dockerfile Linter&lt;/a&gt; for catching image build waste before a runner bills you for it, and &lt;a href="https://devtoollab.com/tools/jwt-decoder" rel="noopener noreferrer"&gt;JWT Decoder&lt;/a&gt; for checking the OIDC token your pipeline swaps for cloud credentials.&lt;/p&gt;

&lt;p&gt;The full breakdown, with per-vendor screenshots, the complete credit tables and the reasoning behind each recommendation, lives in &lt;a href="https://devtoollab.com/blog/best-ci-cd-tools" rel="noopener noreferrer"&gt;the original post on DevToolLab&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://devtoollab.com/blog/best-ci-cd-tools" rel="noopener noreferrer"&gt;Best CI/CD Tools in 2026: What They Really Cost and When to Self-Host&lt;/a&gt; - the original, fuller article&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/resources/insights/2026-pricing-changes-for-github-actions" rel="noopener noreferrer"&gt;Pricing changes for GitHub Actions&lt;/a&gt; - GitHub's own December 15, 2025 notice&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.github.com/en/billing/concepts/product-billing/github-actions" rel="noopener noreferrer"&gt;GitHub Actions billing documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://about.gitlab.com/pricing/" rel="noopener noreferrer"&gt;GitLab pricing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://circleci.com/product/features/resource-classes/" rel="noopener noreferrer"&gt;CircleCI resource classes and credit rates&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://buildkite.com/pricing" rel="noopener noreferrer"&gt;Buildkite pricing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://semaphore.io/open-source" rel="noopener noreferrer"&gt;Semaphore Open Source&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://woodpecker-ci.org/" rel="noopener noreferrer"&gt;Woodpecker CI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://argo-cd.readthedocs.io/en/stable/" rel="noopener noreferrer"&gt;Argo CD documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.cncf.io/announcements/2025/07/24/cncf-end-user-survey-finds-argo-cd-as-majority-adopted-gitops-solution-for-kubernetes/" rel="noopener noreferrer"&gt;CNCF end user survey on Argo CD adoption&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://devtoollab.com/blog/github-actions-best-practices" rel="noopener noreferrer"&gt;GitHub Actions Best Practices&lt;/a&gt; - companion guide on securing the pipeline you pick&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devops</category>
      <category>programming</category>
      <category>opensource</category>
      <category>webdev</category>
    </item>
    <item>
      <title>LaunchDarkly Dropped Per-Seat Pricing. Here Are 3 Ways to Skip the Bill Entirely</title>
      <dc:creator>Moksh Gupta</dc:creator>
      <pubDate>Mon, 31 Aug 2026 19:02:14 +0000</pubDate>
      <link>https://dev.to/moksh/launchdarkly-dropped-per-seat-pricing-here-are-3-ways-to-skip-the-bill-entirely-3lpj</link>
      <guid>https://dev.to/moksh/launchdarkly-dropped-per-seat-pricing-here-are-3-ways-to-skip-the-bill-entirely-3lpj</guid>
      <description>&lt;p&gt;Feature flags exist so a bad deploy becomes a config change instead of an incident. That part hasn't changed. What has changed is the bill: LaunchDarkly shipped AgentControl on May 19, 2026, a runtime layer that reconfigures an AI agent's behavior in under 200ms without a redeploy, and quietly dropped per-seat pricing in the process. The current plan meters two things instead: service connections and client-side monthly active users.&lt;/p&gt;

&lt;p&gt;I wrote up the full breakdown, with every number pulled from the live pricing pages, &lt;a href="https://devtoollab.com/blog/best-launchdarkly-alternatives" rel="noopener noreferrer"&gt;on DevToolLab&lt;/a&gt;. Here's the short version, plus a demo proving the "avoid lock-in" pitch for the open standard underneath all of this actually holds up.&lt;/p&gt;

&lt;h2&gt;
  
  
  What changed and why it matters
&lt;/h2&gt;

&lt;p&gt;LaunchDarkly's free Developer tier is still generous: unlimited seats and flags, 5 service connections, 1,000 MAU, 5,000 AI runs, 14-day retention, no card required. The paid Foundation tier is where the new shape shows: $10 per service connection a month plus $8.33 per 1,000 client-side MAU, no seat fee at all. Per Vendr's marketplace data, the median contract still lands between $63,960 and $72,000 a year.&lt;/p&gt;

&lt;p&gt;None of that is unreasonable for what the platform does. But if you're not using agent orchestration, you're paying enterprise rates for flag delivery alone, and that's exactly the gap three open source projects have been eating for years.&lt;/p&gt;

&lt;h2&gt;
  
  
  The three ways out
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Switch vendors.&lt;/strong&gt; Unleash, GrowthBook, and Flagsmith each sell a hosted plan, priced on very different terms than LaunchDarkly. All three matter more for what comes next.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Self-host.&lt;/strong&gt; Each of those three also ships a real, free, open source edition, not a crippled trial. The cost becomes a small VPS instead of a connection meter.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stop caring which vendor you're on.&lt;/strong&gt; &lt;a href="https://openfeature.dev" rel="noopener noreferrer"&gt;OpenFeature&lt;/a&gt; is a CNCF specification, not a product. Your code calls one vendor-neutral API; the provider underneath becomes a config line instead of an architecture decision.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fn7f316oaj7gcwjzxl2ag.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fn7f316oaj7gcwjzxl2ag.webp" alt="OpenFeature homepage" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The three self-hosted options, briefly
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.getunleash.io" rel="noopener noreferrer"&gt;Unleash&lt;/a&gt; is AGPL-3.0, sits around 13,800 GitHub stars, and self-hosting is one &lt;code&gt;docker compose up -d&lt;/code&gt; away. The catch: choosing self-hosted under its Pay-As-You-Go cloud plan carries a 5-seat minimum, and the license means modifications you distribute as a service need to stay open.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frhehn9cwribnzcedqnpo.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frhehn9cwribnzcedqnpo.webp" alt="Unleash homepage" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.growthbook.io" rel="noopener noreferrer"&gt;GrowthBook&lt;/a&gt; licenses most of the repo MIT, with a handful of enterprise directories carved out under a separate license, the exact same shape as several other "open core" tools in this space. Free self-hosting has no user cap, just a one-project ceiling. It also does warehouse-native experimentation, not just flags, which the other two don't.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkwhoe2oyuvzu8c5miqbj.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkwhoe2oyuvzu8c5miqbj.webp" alt="GrowthBook homepage" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.flagsmith.com" rel="noopener noreferrer"&gt;Flagsmith&lt;/a&gt; is BSD-3-Clause and, unusually, publishes no request ceiling at all on self-hosted deployments. Its hosted free tier is a real but small 50,000 requests a month for one seat.&lt;/p&gt;

&lt;h2&gt;
  
  
  Proving OpenFeature actually avoids lock-in
&lt;/h2&gt;

&lt;p&gt;The claim is easy to make and worth testing instead of trusting. Here's business logic that only imports the OpenFeature client, never a vendor SDK:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;OpenFeature&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@openfeature/server-sdk&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;renderCheckoutButton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;OpenFeature&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;enabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getBooleanValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;new-checkout-flow&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;targetingKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;enabled&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;new checkout&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;classic checkout&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now swap the provider underneath it, twice, using the SDK's built-in in-memory provider as a stand-in for a real vendor plugin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;OpenFeature&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;InMemoryProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@openfeature/server-sdk&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;renderCheckoutButton&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./checkout.mjs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;OpenFeature&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setProviderAndWait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;InMemoryProvider&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;new-checkout-flow&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;variants&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;off&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="na"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;defaultVariant&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;off&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}))&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;renderCheckoutButton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user-1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;// "classic checkout"&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;OpenFeature&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setProviderAndWait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;InMemoryProvider&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;new-checkout-flow&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;variants&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;off&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="na"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;defaultVariant&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;on&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}))&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;renderCheckoutButton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user-1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;// "new checkout"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I ran this with &lt;code&gt;@openfeature/server-sdk&lt;/code&gt; 1.23.0 before publishing, and the output matches the comments exactly. &lt;code&gt;checkout.mjs&lt;/code&gt; never changes between the two runs. Swapping a real vendor's provider in production is the same operation: change what you pass to &lt;code&gt;setProvider&lt;/code&gt;, not what your application calls.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part that breaks during migration
&lt;/h2&gt;

&lt;p&gt;Config vars and builds port cleanly between any of these platforms. What doesn't is percentage rollout math: LaunchDarkly, Unleash, and GrowthBook each hash users into targeting buckets differently, so a 10% rollout on one system is not the same 10% of users on another. Verify parity before you cut traffic over, and keep the old vendor running for a full billing cycle after the new one goes live, so a rollback is a config change and not an emergency.&lt;/p&gt;

&lt;p&gt;The full article on DevToolLab also covers &lt;a href="https://devtoollab.com/blog/best-launchdarkly-alternatives" rel="noopener noreferrer"&gt;GrowthBook's exact license split&lt;/a&gt;, the complete pricing comparison table, and a step-by-step migration checklist.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related DevToolLab tools
&lt;/h2&gt;

&lt;p&gt;If you're standing up a self-hosted flag server, two tools are worth bookmarking: an &lt;a href="https://devtoollab.com/tools/env-file-generator" rel="noopener noreferrer"&gt;.env file generator&lt;/a&gt; for scaffolding the environment variables Unleash, GrowthBook or Flagsmith need before your first &lt;code&gt;docker compose up&lt;/code&gt;, and a &lt;a href="https://devtoollab.com/tools/webhook-signature-verifier" rel="noopener noreferrer"&gt;webhook signature verifier&lt;/a&gt; for checking the HMAC on incoming flag-change webhooks before you trust the payload.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://devtoollab.com/blog/best-launchdarkly-alternatives" rel="noopener noreferrer"&gt;Best LaunchDarkly Alternatives in 2026 - full article on DevToolLab&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://launchdarkly.com/pricing/" rel="noopener noreferrer"&gt;LaunchDarkly pricing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://openfeature.dev" rel="noopener noreferrer"&gt;OpenFeature specification&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Unleash/unleash" rel="noopener noreferrer"&gt;Unleash on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/growthbook/growthbook" rel="noopener noreferrer"&gt;GrowthBook on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>opensource</category>
      <category>programming</category>
      <category>devops</category>
    </item>
    <item>
      <title>Heroku Went Into Maintenance Mode. Here Are Six Places to Take Your App Instead</title>
      <dc:creator>Moksh Gupta</dc:creator>
      <pubDate>Mon, 31 Aug 2026 04:31:42 +0000</pubDate>
      <link>https://dev.to/moksh/heroku-went-into-maintenance-mode-here-are-six-places-to-take-your-app-instead-4heo</link>
      <guid>https://dev.to/moksh/heroku-went-into-maintenance-mode-here-are-six-places-to-take-your-app-instead-4heo</guid>
      <description>&lt;p&gt;In February 2026, Salesforce announced that Heroku is moving to "sustaining engineering": stability, security and support, with no mention of new features. Nothing breaks today. But a platform that will never ship anything new again is a different bet than the one teams made when they first ran &lt;code&gt;git push heroku main&lt;/code&gt;. I wrote up the full comparison on DevToolLab, and this is the short version.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Real Push Isn't the Announcement, It's the Price List
&lt;/h2&gt;

&lt;p&gt;Existing customers keep their billing and support. What actually moves teams is Heroku's own tier structure: Standard-2X tops out at 1 GB for $50/mo, and the next step up, Performance-M, is $250/mo for 2.5 GB. That is five times the cost for two and a half times the memory, with nothing in between. Teams that outgrow the middle tier hit that wall long before they think about the sustaining engineering announcement.&lt;/p&gt;

&lt;h2&gt;
  
  
  Managed vs Self-Hosted
&lt;/h2&gt;

&lt;p&gt;Render, Railway, Fly.io and DigitalOcean App Platform all take a repo, build it and run it, the same shape as Heroku, just with a different bill. Coolify and Dokku instead run on a VPS you rent yourself, trading a per-app fee for the job of patching the box and owning your own uptime.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3m75sp5lgcogiapk4s6u.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3m75sp5lgcogiapk4s6u.webp" alt="Render homepage dashboard with app-backend, app-database and app-frontend cards and a banner offering $10K in migration credits" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Render&lt;/strong&gt; is the closest match to Heroku's actual feel, down to running a dedicated "Migrate to Render" push with migration credits. The catch is a two-part bill: a flat $25/mo Pro workspace fee sits on top of instance pricing, so a Standard 2 GB instance at $25/mo is really $50/mo once the workspace fee is counted.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Railway&lt;/strong&gt; bills what you consume, not what you reserve, at roughly $20 per vCPU-month and $10 per GB-month, metered by the second. That is great for spiky traffic and bad for predictability: a service that's up but idle still accrues cost every second.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fh27v89t8qytsg6yqm21o.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fh27v89t8qytsg6yqm21o.webp" alt="Fly.io homepage with a hand-drawn illustration of winged computer towers, headlined " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fly.io&lt;/strong&gt; runs apps as Firecracker microVMs and has the cheapest raw compute of the group, a 1 GB machine for $5.92/mo in Amsterdam. The trap is the database: managed Postgres starts at $38/mo, six times the app it's backing, and you're editing &lt;code&gt;fly.toml&lt;/code&gt; and thinking about regions and volumes in a way the others don't ask of you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DigitalOcean App Platform&lt;/strong&gt; is flat-rate with bandwidth bundled in, no separate workspace fee, no metering. A 1 vCPU / 1 GB container is $10/mo with 100 GiB of transfer included. It's also the plainest of the four, and the $7/mo dev database is explicitly not for production traffic.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzwg8dxkrcge4xklxiz4l.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzwg8dxkrcge4xklxiz4l.webp" alt="Coolify homepage headlined " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Coolify&lt;/strong&gt; is Apache-2.0 with no feature gates, a Laravel app managing Docker Compose deployments with 280+ one-click services. Coolify Cloud is $5/mo for the control plane on top of your own servers. A single-server setup has no failover, so a bad kernel update takes the app down with it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dokku&lt;/strong&gt; is the minimalist option, MIT licensed, and the one that most literally reproduces the Heroku workflow: &lt;code&gt;dokku apps:create&lt;/code&gt;, add a git remote, push. It's CLI and SSH only with no dashboard, single-host by default, and you're the entire ops team.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pricing a Real App
&lt;/h2&gt;

&lt;p&gt;I built a small script that prices one always-on 1 GB web service plus each platform's cheapest managed Postgres, since RAM is the one unit every provider actually publishes. At 1 GB, DigitalOcean comes out cheapest at $17/mo, Railway a dollar behind at $18, Render at $31, and Fly.io at $43.92 once you add its $38/mo Postgres. Heroku itself lands at $55/mo for the same shape. The full runnable script and the comparison table covering all seven platforms are in &lt;a href="https://devtoollab.com/blog/best-heroku-alternatives" rel="noopener noreferrer"&gt;the original writeup on DevToolLab&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Migrating Without Losing Anything
&lt;/h2&gt;

&lt;p&gt;The mechanical parts of a Heroku migration - config vars, builds, Postgres - port cleanly with &lt;code&gt;heroku config -s&lt;/code&gt; and &lt;code&gt;pg:backups:capture&lt;/code&gt;. The part that actually bites people is Heroku Scheduler, which has no direct equivalent anywhere else and needs to become cron or a scheduled GitHub Actions workflow before cutover, not after. Run both stacks in parallel behind a low DNS TTL and leave the old Heroku app running one full billing cycle before you shut it down.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which One to Pick
&lt;/h2&gt;

&lt;p&gt;If you want to think about this the least, DigitalOcean App Platform at $17/mo for a 1 GB app is the answer. Render costs more but matches Heroku's polish closest. Railway suits spiky or multi-service workloads where metered billing works for you. Fly.io wins on latency and raw compute if you bring your own database. Coolify and Dokku are for teams who'd rather own a VPS than pay a per-app fee indefinitely.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://devtoollab.com/blog/best-heroku-alternatives" rel="noopener noreferrer"&gt;Best Heroku Alternatives in 2026: Render, Railway, Fly.io and Open Source PaaS Compared&lt;/a&gt; - the original article, with the full seven-way comparison table and the complete pricing script&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://devtoollab.com/tools/connection-string-parser" rel="noopener noreferrer"&gt;Connection String Parser&lt;/a&gt; - breaks a Heroku &lt;code&gt;DATABASE_URL&lt;/code&gt; into host, port, user and sslmode when repointing it at a new database&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://devtoollab.com/tools/caddyfile-generator" rel="noopener noreferrer"&gt;Caddyfile Generator&lt;/a&gt; - generates a reverse proxy config with automatic TLS for a self-hosted Coolify or Dokku box&lt;/li&gt;
&lt;li&gt;Salesforce's February 6, 2026 announcement on Heroku moving to sustaining engineering&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>heroku</category>
      <category>webdev</category>
      <category>devops</category>
      <category>cloud</category>
    </item>
  </channel>
</rss>
