Transform Rules let you rewrite URLs and headers right at Cloudflare’s edge, before they even hit your origin server.
Let’s see it in action. Imagine you have a legacy application that uses /old-path/ but you want to direct traffic to a new, cleaner /new-path/.
{
"id": "your-rule-id",
"description": "Rewrite old path to new path",
"expression": "http.request.uri.path contains \"/old-path/\"",
"actions": [
{
"action": "rewrite",
"url": {
"path": {
"expression": "replace(http.request.uri.path, \"/old-path/\", \"/new-path/\")"
}
}
}
],
"enabled": true
}
This rule, when applied, intercepts requests. If the request’s URI path contains /old-path/, it executes the rewrite action. The url.path.expression then uses a replace function to swap out /old-path/ with /new-path/. The crucial part is that this happens at the edge, meaning your origin server never sees the old URL.
The problem this solves is the classic pain of URL deprecation or reorganization. You don’t want to break existing links or SEO value, but you also need to modernize your site structure. Manually managing redirects on your origin server is inefficient, adds latency, and can be complex for large-scale changes. Transform Rules shift this burden to Cloudflare’s global network, making it fast and scalable.
Internally, Cloudflare evaluates these rules based on the expression. If the expression evaluates to true, the specified actions are performed. For URL rewrites, it modifies the request object before it’s forwarded. This includes changes to the Host header if you’re also rewriting the host, or adding/removing/modifying query parameters. You have fine-grained control over the entire request path.
The exact levers you control are the expression and the actions. The expression uses Cloudflare’s Expression Language, which is powerful for matching various HTTP attributes like http.request.uri.path, http.request.method, http.request.headers, and cf.country_code. The actions define what happens when the expression matches: you can rewrite (URLs, headers), set_cache_status, add, remove, or modify headers, and even route traffic to different origins.
Consider setting a specific header. If you need to inject an X-Forwarded-Proto header for an internal service that expects it, you can do this:
{
"id": "your-header-rule-id",
"description": "Set X-Forwarded-Proto to HTTPS",
"expression": "true",
"actions": [
{
"action": "modify",
"headers": [
{
"operation": "append",
"name": "X-Forwarded-Proto",
"value": "https"
}
]
}
],
"enabled": true
}
Here, expression: "true" means this rule applies to every request. The modify.headers.operation is append, adding X-Forwarded-Proto: https to the request headers. This is useful for legacy applications that might otherwise incorrectly assume HTTP when they’re actually receiving HTTPS through Cloudflare.
Most people don’t realize that Transform Rules can also be used to dynamically set cache status codes. For example, if you have an API endpoint that returns a 404 for certain requests but you want Cloudflare to cache that 404 for a short period to reduce origin load, you can configure it.
{
"id": "your-cache-rule-id",
"description": "Cache 404s for API",
"expression": "http.request.uri.path contains \"/api/\" and http.response.status_code == 404",
"actions": [
{
"action": "set_cache_status",
"cache_status_code": 404,
"ttl": "60s"
}
],
"enabled": true
}
This rule targets requests to /api/ that result in a 404 from the origin. It then tells Cloudflare to treat that response as cacheable with a 404 status for 60 seconds. This means subsequent identical requests within that minute will be served directly from Cloudflare’s cache without hitting the origin.
The next step after mastering URL and header manipulation is understanding how to orchestrate multiple Transform Rules effectively using their order of execution.