Path- & Host-Based Routing
An Application Load Balancer (ALB — a Layer 7 load balancer that understands HTTP) can do far more than spread traffic evenly. It can read each incoming request and send it to a different backend based on the URL path (like /api/*) or the hostname (like api.example.com). This lets you run many small services behind a single load balancer instead of paying for one load balancer per service. For teams building microservices (an architecture where an app is split into many small, independent services), this is the cheapest and simplest front door you can build.
Why routing rules matter
Without routing rules, an ALB just forwards everything to one default target group (a group of servers, or “targets,” that receive traffic). Routing rules change that. Each rule has a condition (what to match) and an action (where to send it). The ALB checks rules in priority order, top to bottom, and stops at the first match. If nothing matches, the request falls through to the listener’s default action.
The two most common conditions are:
- Path-based — matches on the URL path, e.g. send
/api/*to your backend API and/img/*to an image service. - Host-based — matches on the
Hostheader, e.g. sendapi.example.comto one group andapp.example.comto another.
You can also combine them: “host is api.example.com AND path is /v2/*.”
When to use this (and when not to)
| Scenario | Use path/host routing? |
|---|---|
| Several services that share one domain | Yes — one ALB, multiple rules |
| Splitting a monolith into microservices gradually | Yes — route new paths to new services |
| You need per-service WAF, certs, or scaling isolation | Maybe not — separate ALBs give cleaner isolation |
| Pure TCP/UDP traffic (no HTTP) | No — use a Network Load Balancer instead |
| Routing on something other than host/path/header | No — ALB rules only match HTTP attributes |
Cost note: A single ALB costs roughly $16–$22/month in base charges (plus LCU usage). Running five separate ALBs instead of one with five rules turns that into ~$80–$110/month for the same traffic. Consolidating services behind one ALB is real money saved.
Path-based routing
Imagine one ALB serving /api/* from an API target group and /img/* from an image target group.
Console steps
- Open the EC2 console, go to Load Balancers, select your ALB.
- Open the Listeners and rules tab, click the HTTPS:443 (or HTTP:80) listener, then Manage rules.
- Click Add rule. Give it a name like
api-rule. - Under Add condition, choose Path and enter
/api/*. Save the condition. - Under Define action, choose Forward to target groups, pick
api-tg. Save. - Set its priority (e.g.
10). Add a second rule for/img/*forwarding toimg-tgat priority20. - Leave the default action to forward to a fallback group (e.g. a “not found” service).
CLI equivalent
aws elbv2 create-rule \
--listener-arn arn:aws:elasticloadbalancing:us-east-1:111122223333:listener/app/my-alb/0a1b2c3d/abcd1234 \
--priority 10 \
--conditions '[{"Field":"path-pattern","PathPatternConfig":{"Values":["/api/*"]}}]' \
--actions '[{"Type":"forward","TargetGroupArn":"arn:aws:elasticloadbalancing:us-east-1:111122223333:targetgroup/api-tg/0a1b2c3d"}]'
Output:
{
"Rules": [
{
"RuleArn": "arn:aws:elasticloadbalancing:us-east-1:111122223333:listener-rule/app/my-alb/0a1b2c3d/abcd1234/9f8e7d6c",
"Priority": "10",
"Conditions": [
{
"Field": "path-pattern",
"PathPatternConfig": { "Values": ["/api/*"] }
}
],
"Actions": [
{ "Type": "forward", "TargetGroupArn": "...targetgroup/api-tg/0a1b2c3d", "Order": 1 }
],
"IsDefault": false
}
]
}
Host-based routing
Same ALB, but now api.example.com and app.example.com point at the same load balancer (via DNS), and the rule splits them.
aws elbv2 create-rule \
--listener-arn arn:aws:elasticloadbalancing:us-east-1:111122223333:listener/app/my-alb/0a1b2c3d/abcd1234 \
--priority 30 \
--conditions '[{"Field":"host-header","HostHeaderConfig":{"Values":["api.example.com"]}}]' \
--actions '[{"Type":"forward","TargetGroupArn":"arn:aws:elasticloadbalancing:us-east-1:111122223333:targetgroup/api-tg/0a1b2c3d"}]'
In the console it’s identical to the path steps above, except in step 4 you choose Host header as the condition and enter api.example.com.
The gotcha: literal, case-sensitive matching and rule order
This is where most people get tripped up.
- Patterns match literally. The path
/apimatches only the exact request to/api. The pattern/api/*matches/api/usersand/api/, but not the bare/api. If you want both, add two values:["/api", "/api/*"]. - Matching is case-sensitive.
/API/orderswill not match/api/*. Normalize your routes or add explicit patterns. - Order is everything. Rules are evaluated by ascending priority number, and the first match wins. If a broad rule
/*sits at priority 5 and a specific/api/*rule sits at priority 10, the broad rule grabs everything first and/api/*never fires. Put specific rules before general ones. - The only wildcards allowed are
*(any number of characters) and?(exactly one character).
Warning: A common production bug is putting a catch-all
/*rule at a low priority number. It silently swallows traffic meant for more specific rules. Always give catch-alls the highest priority number (lowest precedence), or just use the listener’s default action for the catch-all.
IaC example (CloudFormation)
ApiRule:
Type: AWS::ElasticLoadBalancingV2::ListenerRule
Properties:
ListenerArn: !Ref HttpsListener
Priority: 10
Conditions:
- Field: path-pattern
PathPatternConfig:
Values:
- /api
- /api/*
Actions:
- Type: forward
TargetGroupArn: !Ref ApiTargetGroup
Best practices
- List specific paths (
/api/*) at lower priority numbers than broad catch-alls (/*). - Add both
/apiand/api/*when you want the bare path to route too. - Keep paths lowercase by convention, since matching is case-sensitive.
- Use the listener’s default action for your fallback instead of a low-precedence
/*rule. - Combine host + path conditions to version APIs (e.g.
api.example.com+/v2/*). - An ALB allows up to 100 rules per listener — plenty for consolidating many services, but plan groupings if you approach the limit.
- Prefer one consolidated ALB for cost, but split into separate ALBs when services need isolated certificates, WAF policies, or independent scaling.