About Fastly VCL
Fastly VCL is adomain-specific programming language that evolved from theVarnish proxy cache, forming a core part of Fastly's platform architecture. The Varnish Configuration Language (VCL) is intentionally limited in scope so that it can run quickly, maintain strong security, and be applied consistently to every request passing through Fastly.
With VCL you can handle everything from simple tasks like settingCache-Control headers, to building advanced implementations like authentication flows or full paywall systems.
VCL and what you can do with it
Every Fastly service runs on VCL, even when you don't write any code yourself. Each time you configure features in the web interface or via the API, Fastly translates those configuration settings automatically into generated VCL.
You aren't limited to using just generated VCL however. You can mix and match your code with the generated VCL, using them together to create specialized configurations. Your code customizations can modify and extend Fastly's own generated logic. Keep in mind, however, that VCL code you create always takes precedence over any VCL generated by the control panel.
IMPORTANT:
Personal data should not be incorporated into VCL. OurCompliance and Law FAQ describes in detail how Fastly handles personal data privacy.
The VCL request lifecycle
VCL does not run like a traditional program with a single entry point for your code. Instead, Fastly exposes built-in subroutines ashooks that execute at significant moments during each HTTP request's lifecycle. These hooks are where you can add your code.
This approach means your uploaded code functions as aconfiguration rather than a standalone application. Changes to your VCL can be generated automatically through theFastly control panel, compiled, and distributed to all Fastly caches worldwide, all without requiring maintenance windows or service downtime.
Here are the main subroutines, in the order they run:
| Name | Trigger point | Default return state | Alternative return states |
|---|---|---|---|
vcl_recv | Client request received | lookuprecv-note | pass,error,restart,upgrade |
vcl_hash | A cache key will be calculated | hashhash-note | |
vcl_hit | An object has been found in cache | deliver | pass,error,restart |
vcl_miss | Nothing was found in the cache, preparing backend fetch | fetch | deliver_stale,pass,error |
vcl_pass | Cache bypassed, preparing backend fetch | passpass-note | error |
vcl_fetch | Origin response headers received | deliverfetch-note | deliver_stale,pass,error,restart |
vcl_error | Error triggered (explicitly or by Fastly) | deliver | restart |
vcl_deliver | Preparing to deliver response to client | deliver | restart |
vcl_log | Finished sending response to client | deliverlog-note |
Some subroutines can returnerror,restart, orupgrade. Anyerror return state will result in the execution flow passing tovcl_error, whilerestart will result in the execution flow passing tovcl_recv. The specialupgrade return state will terminate the VCL flow and create a managed WebSocket connection (learn more).
Ways to add VCL code to service configurations
You can add custom behavior to your services in three ways, each of which you can mix and match to create specialized configurations:
- viaVCL generative objects, features you configure using the Fastly control panel's web interface or the API
- viaVCL snippets, short blocks of code you attach to subroutines in generated VCL
- viacustom VCL, a full VCL file that you upload to replace the one Fastly generates
To make all three methods work together, Fastly usesmacros inside each subroutine. Macros (for example,#FASTLY recv) act as placeholders where Fastly inserts generated code and snippets during compilation. If you remove them, Fastly cannot insert its generated logic, and your service may fail to compile.
VCL generative objects
Generative objects let you configure behavior without writing code. Fastly turns them into VCL automatically.
| Object | Purpose | Docs |
|---|---|---|
| Header | Setting HTTP headers or VCL variables | Web interface, API |
| Response | Creating a predefined response to be served from the edge | Web interface,API |
| Condition | Restricting actions to only requests that meet criteria defined as a VCL expression | Web interface,API |
| Apex redirect | Redirecting a bare domain such asexample.com to add awww. prefix | API |
| Cache settings | Changing the TTL or cache behavior of an HTTP response | Web interface,API |
| GZip | Compressing HTTP responses before inserting them into cache | Web interface,API |
| HTTP3 | Advertising HTTP/3 support | Web interface |
| Rate limiter | Creating rate limiters to stop individual clients from bombarding your site | Web interface,API |
| Request settings | Changing the cache behavior of a request (similar to a cache setting but applied before the request has been forwarded to origin) | Web interface,API |
| Settings | Update default values for cache TTLs | API |
HINT: Generative objects are a good starting point for learning how to customize VCL for your service configurations. If your configuration becomes crowded with many of those objects, however, it may be easier to usecustom VCL to manage things.
VCL snippets
VCL snippets are short blocks of VCL logic that extend or modify the default Fastly-generated configuration. They are most useful when you want to make targeted changes to your service's settings because they don't require you to replace the generated VCL.
Snippets come in two types:
- Regular snippets: used for procedural logic such as setting headers, routing requests, or applying access controls.
- Dynamic snippets: used for inserting generated rules or structured data such as redirects or allowlists. (If possible, use adictionary instead, since it is easier to manage.)
If you have VCL snippets defined on a service that also has custom VCL, the snippets will typically be rendered inside of the Fastly macros, replacing the placeholders that you must include in any custom VCL file.
Snippets can be included as many times and in as many places as desired, subject to compiler rules. For example, if your snippet attempts toset bereq.http.cookie you cannot include that snippet in thevcl_recv subroutine, becausebereq is not available in thevcl_recv scope. Our guide toVCL variables contains more details.
Custom VCL
Custom VCL allows you to upload a full VCL source file to entirely replace the one that would otherwise be generated by Fastly. To make sure that features you create usingVCL generative objects still work, we require that custom VCL files include Fastly's macros, one in each subroutine.
We recommend starting your custom VCL file with Fastly's boilerplate. It includes all the required Fastly macro placeholders and also presents VCL subroutines in the order in which they are executed.
sub vcl_recv {#FASTLY recv# Normally, you should consider requests other than GET and HEAD to be uncacheable# (to this we add the special FASTLYPURGE method)if (req.method!="HEAD"&&req.method!="GET"&&req.method!="FASTLYPURGE") {return(pass); }# If you are using image optimization, insert the code to enable it here# See https://www.fastly.com/documentation/reference/io/ for more information.return(lookup);}sub vcl_hash {setreq.hash+=req.url;setreq.hash+=req.http.host;#FASTLY hashreturn(hash);}sub vcl_hit {#FASTLY hitreturn(deliver);}sub vcl_miss {#FASTLY missreturn(fetch);}sub vcl_pass {#FASTLY passreturn(pass);}sub vcl_fetch {#FASTLY fetch# Unset headers that reduce cacheability for images processed using the Fastly image optimizerif (req.http.X-Fastly-Imageopto-Api) { unsetberesp.http.Set-Cookie; unsetberesp.http.Vary; }# Log the number of restarts for debugging purposesif (req.restarts>0) {setberesp.http.Fastly-Restarts=req.restarts; }# If the response is setting a cookie, make sure it is not cachedif (beresp.http.Set-Cookie) {return(pass); }# By default we set a TTL based on the `Cache-Control` header but we don't parse additional directives# like `private` and `no-store`. Private in particular should be respected at the edge:if (beresp.http.Cache-Control~"(?:private|no-store)") {return(pass); }# If no TTL has been provided in the response headers, set a defaultif (!beresp.http.Expires&&!beresp.http.Surrogate-Control~"max-age"&&!beresp.http.Cache-Control~"(?:s-maxage|max-age)") {setberesp.ttl=3600s;# Apply a longer default TTL for images processed using Image Optimizerif (req.http.X-Fastly-Imageopto-Api) {setberesp.ttl=2592000s;# 30 dayssetberesp.http.Cache-Control="max-age=2592000, public"; } }return(deliver);}sub vcl_error {#FASTLY errorreturn(deliver);}sub vcl_deliver {#FASTLY deliverreturn(deliver);}sub vcl_log {#FASTLY log}Constraints and limitations
VCL services are subject to the following restrictions or limits:
| Item | Limit | Implications of exceeding the limit |
|---|---|---|
| URL size | 8KB | VCL processing is skipped and a "Too long request string" error is emitted. |
Cookie header size | 32KB | The cookie header will be unset and Fastly will setreq.http.Fastly-Cookie-Overflow = "1", then run your VCL as normal. |
| Request header size | 69KB | Depending on the circumstances, exceeding the limit can result in Fastly closing the client connection abruptly, the client receiving a502 Gateway Error response with "I/O error" in the body, or receiving a503 Service Unavailable response with the text "Header overflow" in the body. |
| Response header size | 69KB | A503 error is triggered withobj.response value of "backend read error". This error can be intercepted invcl_error. SeeFastly generated errors to learn about all synthetic errors generated by Fastly. |
| Request header count | 255 | VCL processing is skipped or aborted if in progress, and a response with "Header overflow" in the body is emitted. A number of headers are added to the request by Fastly, so the practical limit is lower, but is not a predictable constant. Assuming a practical limit of 200 is safe. |
| Response header count | 96 | VCL processing is skipped or aborted if in progress, and a response with "Header overflow" in the body is emitted. A number of headers are added to the response by Fastly, so the practical limit is lower, but is not a predictable constant. Assuming a practical limit of 85 is safe. |
req.body size | 8KB | Larger requests will have an emptyreq.body, so request body payload is available inreq.body only for payloads smaller than 8KB. |
| Surrogate key size | 1KB | Requests to thepurge API that cite longer keys will fail, so in practical terms it is useless to tag content with keys exceeding the length limit. |
| Surrogate key header size | 16KB | Only keys that are entirely within the first 16KB of the surrogate key header value will be applied to the cache object. |
| VCL file size | 1MB | Attempts to uploadVCL via the API will fail if the VCL payload is larger. |
| VCL total size | 3MB | Attempts to uploadVCL via the API will fail if the VCL payload would cause your total service VCL to be larger than this. |
restart limit | 3 restarts | The 4th invocation of therestart statement will trigger a503 error. This error can be intercepted invcl_error. |
| Dictionary item count | 1000 | Attempts tocreate dictionary items will fail if they exceed the limit. ContactFastly support to discuss raising this limit. |
| Dictionary item key length | 256 characters | Attempts tocreate dictionary items will fail. |
| Dictionary item value length | 8000 characters | Attempts tocreate dictionary items will fail. |
WARNING: Personal data should not be incorporated into VCL. OurCompliance and Law FAQ describes in detail how Fastly handles personal data privacy.
Where to learn more about VCL and Varnish
Fastly provides a VCLreference for programming custom logic on VCL services along with guides onusing VCL and the currentbest practices. These resources focus on how VCL works within the Fastly platform.
For background information on the language itself, theofficial Varnish documentation is a good online starting point. Varnish Software, which provides commercial support for Varnish, also maintains afree online book covering more technical details.
Related content
- The return state from
vcl_logsimply terminates request processing.↩ - Returning with
return(deliver)fromvcl_fetchcannot override an earlier pass, butreturn(pass)here will prevent the response being cached.↩ - The
return(pass)exit fromvcl_passtriggers a backend fetch, similarly toreturn(fetch)invcl_missbut the altered return state is a reminder that the object is flagged for pass, so that it cannot be cached when processed invcl_fetch.↩ - The only possible return state from
vcl_hashishashbut it will trigger different behavior depending on the earlier return state ofvcl_recv. The defaultreturn(lookup)invcl_recvwill prompt Fastly to perform a cache lookup and runvcl_hitorvcl_missafter hash. Ifvcl_recvreturnserror, thenvcl_erroris executed after hash. Ifvcl_recvreturnsreturn(pass), thenvcl_passis executed after hash. The hash process is required in all these cases to create a cache object to enablehit-for-pass.↩ - All return states from
vcl_recv(exceptrestart) pass throughvcl_hashfirst.return(lookup)andreturn(pass)both move control tovcl_hashbut flag the request differently, which will determine the exit state fromvcl_hash.↩