---
title: VCL request lifecycle
summary: null
url: https://www.fastly.com/documentation/reference/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 as _hooks_ 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 a _configuration_ rather than a standalone application. Changes to your VCL can be generated automatically through the [Fastly control panel](https://www.fastly.com/documentation/guides/getting-started/navigating-fastly/about-the-web-interface-controls), 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:

> **NOTE:** This page contains a VCL flow diagram. Visit the URL to see the interactive diagram.

| Name          | Trigger point                                           | Default return state    | Alternative return states                   |
| ------------- | ------------------------------------------------------- | ----------------------- | ------------------------------------------- |
| `vcl_recv`    | Client request received                                 | `lookup`[^recv-note]    | `pass`, `error`, `restart`, `upgrade`       |
| `vcl_hash`    | A cache key will be calculated                          | `hash` [^hash-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                 | `pass` [^pass-note]     | `error`                                     |
| `vcl_fetch`   | Origin response headers received                        | `deliver` [^fetch-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                     | `deliver`[^log-note]    |                                             |

[^recv-note]&#x3A; All return states from `vcl_recv` (except `restart`) pass through `vcl_hash` first. `return(lookup)` and `return(pass)` both move control to `vcl_hash` but flag the request differently, which will determine the exit state from `vcl_hash`.
[^hash-note]&#x3A; The only possible return state from `vcl_hash` is `hash` but it will trigger different behavior depending on the earlier return state of `vcl_recv`. The default `return(lookup)` in `vcl_recv` will prompt Fastly to perform a cache lookup and run `vcl_hit` or `vcl_miss` after hash. If `vcl_recv` returns `error`, then `vcl_error` is executed after hash. If `vcl_recv` returns `return(pass)`, then `vcl_pass` is executed after hash. The hash process is required in all these cases to create a cache object to enable [hit-for-pass](https://www.fastly.com/documentation/guides/concepts/edge-state/cache/request-collapsing/#hit-for-pass).
[^pass-note]&#x3A; The `return(pass)` exit from `vcl_pass` triggers a backend fetch, similarly to `return(fetch)` in `vcl_miss` but the altered return state is a reminder that the object is flagged for pass, so that it cannot be cached when processed in `vcl_fetch`.
[^fetch-note]&#x3A; Returning with `return(deliver)` from `vcl_fetch` cannot override an earlier pass, but `return(pass)` here will prevent the response being cached.
[^log-note]&#x3A; The return state from `vcl_log` simply terminates request processing.

Some subroutines can return `error`, `restart`, or `upgrade`. Any `error` return state will result in the execution flow passing to `vcl_error`, while `restart` will result in the execution flow passing to `vcl_recv`. The special `upgrade` return state will terminate the VCL flow and create a managed WebSocket connection ([learn more](https://www.fastly.com/documentation/guides/concepts/real-time-messaging/)).
