Calculator, pen and paper on a white desk

Amazon Bedrock cost optimization: a practitioner's playbook for 2026

Bedrock pricing looks simple on the pricing page. The bill rarely is. Here is the order we work in — attribution, caching, routing, output control, batch, capacity — with the arithmetic shown.

By ForthClover EngineeringUpdated October 202613 min readCost Optimization

Bedrock’s pricing page looks simple: a rate per million input tokens, a rate per million output tokens, done. Then the first real month arrives and the bill is several times the spreadsheet. The pricing card wasn’t wrong. It just doesn’t describe how spend accumulates in a production system with long system prompts, tool definitions, retrieval context, reasoning tokens and retries.

This is the playbook we use when a team already has something running on Bedrock and wants the bill to be smaller and predictable. It is ordered the way we work: measure first, then the changes that need no commitment, then the ones that do. There is a fully worked cost example in the middle with the arithmetic shown.

Prices and model lineups in this article are as of October 2026. They change often. We quote Anthropic’s published list prices for the arithmetic; confirm the exact Bedrock rate for your model, region and endpoint on the Bedrock pricing page before you budget.12

How a Bedrock bill is actually built

For a Claude model on Bedrock, one request can touch six or seven different meters. Teams that model only the first two are the ones who get surprised.

MeterWhat drives itWhy it surprises people
Uncached inputSystem prompt, tool schemas, retrieved context, conversation historyAgents resend the whole history and every tool definition on every turn
OutputThe answer plus any reasoning the model doesFive times the input rate on current Claude models2
Cache writesFirst use of a cached prefix (1.25x input for a 5-minute TTL, 2x for 1 hour)A prefix that changes every request is written every request
Cache readsReuse of a cached prefix (0.1x input; 0.05x on Sonnet 5.5 and Opus 5.5)Cheap, but only if the prefix is byte-for-byte stable2
Endpoint premiumRegional or geographic routing instead of global10% premium over global for Claude 4.5 models and later3
Long-context tierHaiku 5.5 prompts over 100,000 tokensThe whole request moves to the higher rate, cache reads included2
Committed capacityReserved tier or Provisioned ThroughputBilled whether or not you send traffic

One accounting detail catches finance teams: Claude models on Bedrock are third-party models billed through AWS Marketplace, so the charges show up in Cost Explorer under the model provider rather than under Amazon Bedrock.4 If your dashboard filters on the Bedrock service, your biggest line item may be missing from it.

The five surprises we diagnose most often

  • Reasoning tokens. Sonnet 5.5 and Haiku 5.5 on Bedrock have adaptive thinking on by default, with effort defaulting to high and medium respectively.45 Thinking tokens are part of the billed output, and Anthropic reports them separately in usage.output_tokens_details.thinking_tokens.6 A classification call that “only returns one word” can still bill hundreds of output tokens.
  • Token counts measured on the wrong model. Claude 4.7 and later use a newer tokenizer that produces roughly 30% more tokens for the same text than Sonnet 4.6 and earlier.2 A budget built from last year’s token logs is low before you change anything else.
  • Oversized max_tokens. Bedrock throttling is based on an upfront reservation of input tokens plus max_tokens, not on what the model actually generates.7 Setting it to the model maximum “just in case” burns quota, which pushes teams to buy capacity they don’t need.
  • Retries that resend the full prompt. Every retry of a long-prompt call pays for the prompt again. Aggressive client retries layered on SDK retries layered on an agent framework’s own retry loop multiply quietly.
  • Capacity bought for the peak. Committed capacity sized for the busiest hour spends most of the month idle.

Step 1: make spend attributable before you optimise

You cannot cut what you cannot attribute. Bedrock now gives you three complementary mechanisms, and we usually use two of them together.

  • Application inference profiles. Create a profile per application or team, tag it, and call the profile ARN instead of the model ID. The tags flow to Cost Explorer and the Cost and Usage Report. The finest grain is per usage type per day, so this is for chargeback, not per-request analysis.8
  • Per-request metadata. Attach up to 16 key-value pairs to each Converse or InvokeModel call. They land in your model invocation logs (only when logging is enabled in that region), not on your bill, so you compute cost from token counts and your own rate card.9
  • CloudWatch runtime metrics. InputTokenCount, OutputTokenCount, CacheReadInputTokenCount, CacheWriteInputTokenCount, InvocationThrottles and latency metrics, published under AWS/Bedrock.7

The wrapper we put on the call path looks roughly like this. It also sets up the cache checkpoint used in step 2, so it does double duty.

import boto3

brt = boto3.client("bedrock-runtime", region_name="us-east-1")
SYSTEM_PROMPT = load_prompt("support_system", version="v14")  # static, versioned

def answer(question: str, context: str, *, feature: str, user_hash: str) -> str:
    resp = brt.converse(
        # Swap in an application inference profile ARN to get cost allocation tags.
        modelId="global.anthropic.claude-sonnet-5-5",
        system=[
            {"text": SYSTEM_PROMPT},
            {"cachePoint": {"type": "default"}},   # everything above is cacheable
        ],
        messages=[{
            "role": "user",
            "content": [{"text": f"<context>{context}</context>\n\n{question}"}],
        }],
        inferenceConfig={"maxTokens": 800},        # also bounds the quota reservation
        requestMetadata={"feature": feature, "user": user_hash, "env": "prod"},
    )
    u = resp["usage"]
    # inputTokens excludes cache reads and writes, so record all four.
    emit_usage(feature, u["inputTokens"], u.get("cacheReadInputTokens", 0),
               u.get("cacheWriteInputTokens", 0), u["outputTokens"])
    blocks = resp["output"]["message"]["content"]
    return next(b["text"] for b in blocks if "text" in b)

Keep metadata keys low-cardinality (feature, team, env) and never put personal data in them; AWS’s own guidance says the same.9 Once invocation logs are flowing to CloudWatch Logs, a Logs Insights query gives you a per-feature view in seconds:

fields requestMetadata.feature as feature, modelId,
       input.inputTokenCount as inTok,
       output.outputTokenCount as outTok
| stats sum(inTok) as inputTokens, sum(outTok) as outputTokens, count() as calls
        by feature, modelId
| sort outputTokens desc

Then put an alarm on it. We like an anomaly band on hourly output tokens, because runaway agents and bad prompt deploys show up there first. In Terraform:

resource "aws_cloudwatch_metric_alarm" "bedrock_output_tokens" {
  alarm_name          = "bedrock-output-tokens-above-band"
  comparison_operator = "GreaterThanUpperThreshold"
  evaluation_periods  = 2
  threshold_metric_id = "band"
  alarm_actions       = [aws_sns_topic.llm_spend.arn]

  metric_query {
    id          = "m1"
    return_data = true
    metric {
      namespace   = "AWS/Bedrock"
      metric_name = "OutputTokenCount"
      period      = 3600
      stat        = "Sum"
    }
  }

  metric_query {
    id          = "band"
    expression  = "ANOMALY_DETECTION_BAND(m1, 3)"
    label       = "OutputTokenCount (expected)"
    return_data = true
  }
}

We deliberately alarm on the metric without a ModelId dimension. Requests that fail before Bedrock resolves the model are published without it, so filtering by model can undercount.7

Step 2: cache the stable prefix

In agent and RAG systems the system prompt and tool definitions are usually the largest single chunk of input, and they are identical across requests. Prompt caching turns that chunk from full price into a fraction of it.

The mechanics that matter on Bedrock:

  • Checkpoints are evaluated in the order tools, then system, then messages. Changing anything earlier invalidates everything after it.10
  • The Claude 5.5 models and Opus 5 need at least 512 tokens before a checkpoint (Sonnet 5 needs 1,024), allow up to four checkpoints, and support 5-minute and 1-hour TTLs. Some older models need far more: 4,096 tokens for Opus 4.5 to 4.7 and Haiku 4.5.10
  • The TTL resets on every hit. If a prefix is used more often than every five minutes, the 5-minute cache stays warm on its own; the 1-hour option is for prefixes reused less often than that.10
  • Cache reads don’t count toward your tokens-per-minute quota; cache writes do.7
  • Caching is not available for batch inference, and cross-region routing can increase cache writes at times of high demand.10

The break-even is quick. With a 5-minute write at 1.25x and a read at 0.1x, a prefix pays for itself the first time it is read again.2 The failure mode is not the price, it is prefix instability. The bugs we find most often: a timestamp or request ID rendered into the system prompt, tool definitions serialised in a non-deterministic order, per-user data placed above the checkpoint, and changing the reasoning effort between turns, which also invalidates the cache.6 Watch CacheWriteInputTokenCount against CacheReadInputTokenCount; if writes stay high after warm-up, the prefix is not as static as you think.

Step 3: route each request to the cheapest model that passes

The biggest structural saving is not sending routine work to an expensive model. The spread between tiers is large:

Model (list, per million tokens)InputCache readOutputBedrock batch support
Claude Haiku 5.5 (prompt up to 100K)$0.10$0.01$0.50Not listed
Claude Haiku 5.5 (prompt over 100K)$0.50$0.05$2.50Not listed
Claude Sonnet 5.5$2.00$0.10$10.00Not listed
Claude Opus 5.5$4.00$0.20$20.00Check model card
Claude Opus 5$5.00$0.50$25.00Yes

Prices are Anthropic’s list rates as of October 2026; batch support is from the Bedrock model cards and batch documentation at the same date.24511 Sonnet 5.5 output costs 20 times Haiku 5.5 output. If even half your traffic can run on the small model, that dominates every other optimisation in this article.

There are three router designs we use, in rising order of complexity:

  1. Static rules. Route by endpoint or task type. Extraction, classification and short summaries go small; anything with tools or long reasoning goes large. Cheap, transparent, and often enough.
  2. A small classifier. A Haiku-class call that labels the request before dispatch. It adds a few hundred tokens and some latency per request, so include it in the cost model.
  3. A cascade. Try the small model first and escalate when a validator fails (schema check, confidence threshold, a grader). This works well when failures are detectable; it is expensive when they are not, because you pay for both calls.

Bedrock’s managed option, intelligent prompt routing, is worth knowing about but check whether it fits. It routes between two models in the same family, is optimised for English prompts, and its supported list currently covers Amazon Nova and Meta Llama models rather than Claude.12 AWS prices it at $1 per 1,000 requests and says it can reduce costs by up to 30%; treat that as the vendor’s claim and measure on your own traffic.1

Decide with your evals, not the leaderboard

Before we change any routing, we ask the team to fill in this table on their own evaluation set. The point is to stop reasoning from marketing pages; teams are regularly surprised by how much traffic the smaller tier handles.

Request classCandidate modelEval pass ratep95 latencyCost per 1K requests
Intent classification, extractionHaiku 5.5, low effortMeasureMeasureCompute from logs
Grounded answer from retrieved contextHaiku 5.5 vs Sonnet 5.5MeasureMeasureCompute from logs
Multi-step tool use, planningSonnet 5.5 vs Opus 5.5MeasureMeasureCompute from logs

Step 4: control output and reasoning spend

Output is the expensive side of the meter, and it is the side teams model worst. The levers, in the order we pull them:

  • Set effort deliberately. On adaptive-thinking models, effort (set in output_config) controls how much the model reasons, and at lower settings it may skip thinking on easy inputs.6 Pick it per request class, and hold it stable within a conversation so you don’t break the cache.
  • Cap max_tokens per route. A classification route does not need the same ceiling as a report generator, and a lower ceiling also lowers your quota reservation.7
  • Ask for structure. A JSON schema with short fields produces fewer tokens than a prose answer the application then parses.
  • Stop early when streaming. If a guardrail or repetition check sees the response going wrong, cancel the stream rather than letting it run to the ceiling.

A quick way to size this lever: for every 100 output tokens you remove from a route, the monthly saving is requests x 100 / 1,000,000 x output price. On 400,000 Sonnet 5.5 requests a month that is 40 million tokens, or $400.

Worked example: a support assistant at one million requests a month

Here is the arithmetic for a realistic workload. The assumptions are ours and labelled as such; the prices are list prices on the global endpoint as of October 2026.2

AssumptionValue
Requests per month1,000,000
Static prefix (system prompt + tool definitions)6,000 tokens
Retrieved context3,000 tokens
Conversation history + question1,000 tokens
Output, including reasoning500 tokens
Cache hit rate on the prefix, once enabled90% (assumed)
Share of traffic that passes evals on Haiku 5.560% (assumed)

Baseline: everything on Sonnet 5.5, no caching

  • Input: 10,000 tokens x 1M requests = 10,000M tokens x $2.00 = $20,000
  • Output: 500 x 1M = 500M tokens x $10.00 = $5,000
  • Total: $25,000 a month

Add caching on the 6,000-token prefix

  • Prefix tokens: 6,000M. Reads: 5,400M x $0.10 = $540. Writes: 600M x $2.50 = $1,500.
  • Rest of input: 4,000M x $2.00 = $8,000. Output unchanged: $5,000.
  • Total: $15,040 a month, about 40% lower.

Notice that at a 90% hit rate the writes cost more than the reads. Pushing the hit rate to 99% (steadier traffic, a stable prefix) brings the prefix cost from $2,040 down to $744.

Add routing: 60% of requests to Haiku 5.5

  • Haiku slice (600K requests): prefix reads 3,240M x $0.01 = $32.40, writes 360M x $0.125 = $45, other input 2,400M x $0.10 = $240, output 300M x $0.50 = $150. Subtotal $467.40.
  • Sonnet slice (400K requests): prefix reads 2,160M x $0.10 = $216, writes 240M x $2.50 = $600, other input 1,600M x $2.00 = $3,200, output 200M x $10.00 = $2,000. Subtotal $6,016.
  • Classifier on Haiku 5.5 (300 input, 5 output tokens per request, too short to cache): 300M x $0.10 + 5M x $0.50 = $32.50.
  • Total: $6,515.90 a month, about 74% below baseline.

Worked example

Monthly cost, one million requests

Illustrative workload at list prices, October 2026. Bars split each total into uncached input, cache reads and writes, and output.

BaselineAll Sonnet 5.5, no cache$25,000+ Prompt caching90% hits on 6K prefix$15,040+ Routing60% to Haiku 5.5$6,516Uncached inputCache reads + writesOutput

Two things fall out of the numbers. First, after caching and routing, the Sonnet slice is 92% of the bill, and within it the uncached retrieval context ($3,200) and output ($2,000) are the biggest remaining lines. Trimming retrieved context from 3,000 to 2,000 tokens on that slice saves another $800 a month. Second, residency has a price: if you must use a US geographic inference profile instead of the global one, the 10% premium takes the total to about $7,167.3 Your numbers will differ; the method is the point.

Step 5: batch and service tiers for work that can wait

Bedrock batch inference processes a JSONL file from S3 asynchronously at 50% below on-demand pricing for selected models.113 It is the right home for overnight enrichment, backfills, evaluation runs and periodic re-summarisation. Three things to check before you plan around it:

  • Model support. The batch-supported list includes Claude Opus 5, Sonnet 4.6 and Haiku 4.5, but the Sonnet 5.5 and Haiku 5.5 model cards list Standard tier only, with no Batch, Flex, Priority or Reserved support yet.1445 New models often launch this way, so check the card before promising a saving.
  • Tool calling. Batch jobs using the Converse format reject records with toolConfig; use the InvokeModel format if you need tools.13
  • No caching. Prompt caching does not apply to batch, so the 50% discount is against full-price input.10

Each line of the input file is a record ID plus the model’s native request body:

{"recordId": "TICKET-000001", "modelInput": {"anthropic_version": "bedrock-2023-05-31", "max_tokens": 400, "messages": [{"role": "user", "content": [{"type": "text", "text": "Summarise this ticket thread: ..."}]}]}}
bedrock = boto3.client("bedrock", region_name="us-east-1")

bedrock.create_model_invocation_job(
    jobName="ticket-summaries-2026-10-24",
    roleArn="arn:aws:iam::123456789012:role/BedrockBatchRole",
    modelId="us.anthropic.claude-opus-5",   # confirm Batch support on the model card
    inputDataConfig={"s3InputDataConfig": {"s3Uri": "s3://acme-llm-batch/in/"}},
    outputDataConfig={"s3OutputDataConfig": {"s3Uri": "s3://acme-llm-batch/out/"}},
)

Output order is not guaranteed to match input order, so join results on recordId.15 As a sizing example: 200,000 documents a month at 4,000 input and 300 output tokens on Opus 5 is 800M x $5 + 60M x $25 = $5,500 on demand, or $2,750 in batch.211

Flex and Priority

For models that support them, Bedrock’s service tiers are set per request with a service_tier field: flex trades latency for a 50% discount on Standard pricing, priority buys faster responses at a 75% premium, and omitting the field (or default) means Standard.161 On-demand quota is shared across the three, and CloudWatch reports a ResolvedServiceTier dimension showing which tier actually served each request.16 Flex is a good fit for agent sub-tasks and evaluations that need an answer in minutes rather than seconds, where batch’s file-based workflow is awkward.

Step 6: commit to capacity last

Committed capacity is cheaper per token only when you keep it busy. Bedrock now has two forms:

  • Reserved tier. You reserve input and output tokens-per-minute for one or three months, with minimums of 100,000 input and 10,000 output TPM. Overflow spills to Standard automatically, AWS targets 99.5% uptime, and billing continues until the reservation is deleted. When sizing it, add CacheWriteInputTokens to input tokens, because both count.16 Access is through your AWS account team.
  • Provisioned Throughput. Hourly billing per model unit with no commitment, one month or six months; longer terms get a lower hourly rate. It is mandatory for serving customised models.17 Batch inference does not run on provisioned models.13

Our rule is to commit only to the floor. Measure the token rate you sustain for most of the day across a few weeks, commit to that, and let everything above it run on Standard. Then check the simple inequality before signing: the monthly commitment must be lower than what the same traffic would cost on demand after caching and routing. Teams that commit first lock in the unoptimised token volume and pay for it for the rest of the term.

What we don’t bother optimising

  • Temperature. It has no effect on price. We mention it because we keep meeting teams who believe otherwise.
  • Aggressive prompt compression. Shaving 10% off a system prompt that is already cached saves almost nothing and makes the prompt harder to maintain. Spend the effort on retrieval size instead.
  • Switching providers for a small rate cut. The migration, re-evaluation and operational risk usually cost more than the saving. Revisit when a new model tier changes the economics, not when a rate moves a few percent.

The order we work in

When we’re asked to fix a Bedrock bill, the sequence is nearly always the same. The first three steps are code changes you can reverse in an afternoon; the last two depend on model support and a measured traffic floor.

Playbook

The order we work in

Steps 1–3 are code changes you can reverse. Steps 4–5 depend on model support and a measured traffic floor.

1Attribute spendProfiles, metadata,token alarms2Cache the prefixStable tools + systemabove a checkpoint3Route and trimSmallest passing model,effort, max_tokens4Batch or FlexWhere the model cardlists support5Commit lastReserved or provisionedfor the floor onlyNo commitment (do these first)Check model support and traffic shape

Checklist

  • Cost Explorer views include the model provider’s Marketplace line, not just “Amazon Bedrock”.
  • Every call carries an inference profile or request metadata that maps to a feature and team.
  • Invocation logging is on in every region you call, so metadata is retained.
  • An alarm watches hourly output tokens and throttles.
  • Static content sits above a cache checkpoint; cache writes fall after warm-up.
  • Each route has an explicit model, effort level and max_tokens.
  • Token budgets were measured on the model you actually run (tokenizers changed in 4.7).
  • Haiku 5.5 routes stay under the 100,000-token prompt threshold, or you priced the long-context rate.
  • Latency-tolerant jobs run in batch or Flex where the model supports it.
  • Global versus regional endpoints is a deliberate residency decision, priced at the 10% difference.
  • Committed capacity covers the measured floor only, and is re-checked quarterly.

ForthClover runs this kind of cost review on production Bedrock systems, usually alongside the evaluation work that makes routing safe. If you want a second pair of eyes on yours, get in touch.

Sources

  1. AWS, Amazon Bedrock pricing — aws.amazon.com/bedrock/pricing/
  2. Anthropic, Claude API documentation — Pricing (model, caching, batch and residency rates) — platform.claude.com/docs/en/about-claude/pricing
  3. Anthropic, “Claude in Amazon Bedrock” (endpoints, regions, quotas, feature support) — platform.claude.com/docs/en/build-with-claude/claude-in-amazon-bedrock
  4. AWS, Amazon Bedrock model card — Claude Sonnet 5.5 — docs.aws.amazon.com/bedrock/latest/userguide/model-card-anthropic-claude-sonnet-5-5.html
  5. AWS, Amazon Bedrock model card — Claude Haiku 5.5 — docs.aws.amazon.com/bedrock/latest/userguide/model-card-anthropic-claude-haiku-5-5.html
  6. Anthropic, Claude API documentation — Extended thinking (thinking tokens, effort, caching) — platform.claude.com/docs/en/build-with-claude/extended-thinking
  7. AWS, “Monitor bedrock-runtime inference using CloudWatch metrics” — docs.aws.amazon.com/bedrock/latest/userguide/monitoring-runtime-metrics.html
  8. AWS, “Application inference profiles” (cost allocation) — docs.aws.amazon.com/bedrock/latest/userguide/cost-mgmt-application-inference-profiles.html
  9. AWS, “Per-request metadata tagging” — docs.aws.amazon.com/bedrock/latest/userguide/cost-mgmt-request-metadata.html
  10. AWS, “Prompt caching for faster model inference” — docs.aws.amazon.com/bedrock/latest/userguide/prompt-caching.html
  11. AWS, Amazon Bedrock model card — Claude Opus 5 — docs.aws.amazon.com/bedrock/latest/userguide/model-card-anthropic-claude-opus-5.html
  12. AWS, “Understanding intelligent prompt routing in Amazon Bedrock” — docs.aws.amazon.com/bedrock/latest/userguide/prompt-routing.html
  13. AWS, “Process multiple prompts with batch inference” — docs.aws.amazon.com/bedrock/latest/userguide/batch-inference.html
  14. AWS, “Supported Regions and models for batch inference” — docs.aws.amazon.com/bedrock/latest/userguide/batch-inference-supported.html
  15. AWS, “Format and upload your batch inference data” — docs.aws.amazon.com/bedrock/latest/userguide/batch-inference-data.html
  16. AWS, “Service tiers for optimizing performance and cost” — docs.aws.amazon.com/bedrock/latest/userguide/service-tiers-inference.html
  17. AWS, “Increase model invocation capacity with Provisioned Throughput in Amazon Bedrock” — docs.aws.amazon.com/bedrock/latest/userguide/prov-throughput.html

All sources were checked in October 2026. Worked-example figures are our own arithmetic on list prices and stated assumptions, not measurements from a client system.