vcl_recv
The built-in vcl_recv
subroutine is executed when a client request is received by Fastly or as a result of a restart
.
Typically, the recv state is used for tasks such as:
- normalizing client input
- routing: dynamically allocating a backend to the request
- applying authentication or evaluating access rights (e.g., API keys, paywalls, session tokens, URL tokens)
- triggering synthetic responses for known paths (e.g., to implement redirects for old URLs)
- requiring TLS
- Denying requests based on geolocation or ACLs
- Enabling serve stale behavior
- Setting limits or defaults
- Enabling Image Optimization
- Validating initial request to remove 'trusted' headers that should only be added by edge logic
- Changing backend after a
restart
, as part of the pre-flight pattern, A/B testing or origin failover. - Invoking WebSockets passthrough
The default return path from vcl_recv
for GET
requests is lookup
, which will trigger the vcl_hash
subroutine, perform a cache key calculation and look up the resulting address in the cache, ultimately triggering the vcl_hit
, vcl_miss
or vcl_pass
subroutines as appropriate. It's also possible to return(pass)
, which will still perform a cache key calculation, but will always transition from vcl_hash
to vcl_pass
. Returning upgrade
will terminate the VCL execution and Fastly will maintain the connection as a persistent WebSockets tunnel.
Changes made to the req
object in vcl_recv
will affect the calculation of the cache key, if the changed properties are included in obj.hash
by vcl_hash
.
The exception statements restart
and error
may both be used in recv
.
Method specific behavior
At the end of vcl_recv
, the default behavior is dependent on the method of the inbound request:
GET
,HEAD
, andPURGE
requests will trigger alookup
, while all other methods will cause apass
. This behavior is in the boilerplate VCL and is overridable by using custom VCL in your service.- If the return state is
lookup
, methods other thanGET
andPOST
will be converted toGET
on the backend request (bereq
) and any request body will be dropped. This behavior is part of the Fastly platform and is not overridable.
HINT: With the default boilerplate VCL, the rules above will result in the conversion of a HEAD
request into a GET
to your origin server, allowing Fastly to populate the resource into our cache, but the response to the client will correctly exclude the content body, since the client requested only the HEAD.
State transitions
| vcl_recv |
To see this subroutine in the context of the full VCL flow, see using VCL.
Example
The code example Use microservices to divide up a domain is a good example of the vcl_recv
subroutine in use:
Tokens available in this subroutine
The following limited-scope VCL functions and variables are available for use in this subroutine (those in bold are available only in this subroutine, those available in *all* subroutines are not listed):
- client.socket.congestion_algorithm
- client.socket.cwnd
- client.socket.nexthop
- client.socket.pace
- client.socket.ploss
- client.socket.tcp_info
- client.socket.tcpi_advmss
- client.socket.tcpi_bytes_acked
- client.socket.tcpi_bytes_received
- client.socket.tcpi_data_segs_in
- client.socket.tcpi_data_segs_out
- client.socket.tcpi_delivery_rate
- client.socket.tcpi_delta_retrans
- client.socket.tcpi_last_data_sent
- client.socket.tcpi_max_pacing_rate
- client.socket.tcpi_min_rtt
- client.socket.tcpi_notsent_bytes
- client.socket.tcpi_pacing_rate
- client.socket.tcpi_pmtu
- client.socket.tcpi_rcv_mss
- client.socket.tcpi_rcv_rtt
- client.socket.tcpi_rcv_space
- client.socket.tcpi_rcv_ssthresh
- client.socket.tcpi_reordering
- client.socket.tcpi_rtt
- client.socket.tcpi_rttvar
- client.socket.tcpi_segs_in
- client.socket.tcpi_segs_out
- client.socket.tcpi_snd_cwnd
- client.socket.tcpi_snd_mss
- client.socket.tcpi_snd_ssthresh
- client.socket.tcpi_total_retrans
- esi.allow_inside_cdata
- fastly_info.h2.is_push
- fastly_info.h2.stream_id
- quic.cc.cwnd
- quic.cc.ssthresh
- quic.num_bytes.received
- quic.num_bytes.sent
- quic.num_packets.ack_received
- quic.num_packets.decryption_failed
- quic.num_packets.late_acked
- quic.num_packets.lost
- quic.num_packets.received
- quic.num_packets.sent
- quic.rtt.latest
- quic.rtt.minimum
- quic.rtt.smoothed
- quic.rtt.variance
- req.enable_range_on_pass
- req.enable_segmented_caching
- req.esi
- req.esi_level
- req.hash_always_miss
- req.hash_ignore_busy
- req.is_ipv6
- req.is_purge
- segmented_caching.block_size
- tls.client.certificate.dn
- tls.client.certificate.is_cert_bad
- tls.client.certificate.is_cert_expired
- tls.client.certificate.is_cert_missing
- tls.client.certificate.is_cert_unknown
- tls.client.certificate.is_unknown_ca
- tls.client.certificate.is_verified
- tls.client.certificate.issuer_dn
- tls.client.certificate.not_after
- tls.client.certificate.not_before
- tls.client.certificate.raw_certificate_b64
- tls.client.certificate.serial_number
- tls.client.cipher
- tls.client.ciphers_list
- tls.client.ciphers_list_sha
- tls.client.ciphers_list_txt
- tls.client.ciphers_sha
- tls.client.handshake_sent_bytes
- tls.client.iana_chosen_cipher_id
- tls.client.ja3_md5
- tls.client.ja4
- tls.client.protocol
- tls.client.servername
- tls.client.tlsexts_list
- tls.client.tlsexts_list_sha
- tls.client.tlsexts_list_txt
- tls.client.tlsexts_sha
- transport.bw_estimate
- transport.type