---
title: Writing VCL code
summary: null
url: >-
  https://www.fastly.com/documentation/guides/full-site-delivery/fastly-vcl/writing-vcl-code
---

Whether you use snippets or custom VCL to write VCL code, the features available in the language are the same. This section summarises some of the most common VCL use cases.

> **TIP:** Many common use cases for VCL are explored in our [code examples gallery](https://www.fastly.com/documentation/solutions/examples). The [best practices guide](https://www.fastly.com/documentation/guides/full-site-delivery/fastly-vcl/vcl-best-practices) also helps you understand how to avoid pitfalls and write safer, more secure edge code. Our [fiddle tool](https://www.fastly.com/documentation/reference/tools/fiddle) also allows you to interactively write and execute VCL code without logging into Fastly, giving you space to experiment and test your ideas.

## Manipulating headers

The `set` and `unset` statements allow for setting and unsetting HTTP headers on requests and responses. For example, in `vcl_fetch`, you could write:

```vcl context="sub vcl_fetch { ... }"
set beresp.http.Cache-Control = "public, max-age=3600";
unset beresp.http.x-goog-request-id;
```

The `{OBJ-NAME}.http.{HEADER-NAME}` pattern is available for `req`, `bereq`, `resp`, `beresp`, and `obj`. Refer to [VCL variables](https://www.fastly.com/documentation/reference/vcl/variables/) for details of where each of these is available, but in general:

| To add/remove headers on... | ...use this                                      | Example use cases                                                                 |
| --------------------------- | ------------------------------------------------ | --------------------------------------------------------------------------------- |
| Client request              | `req.http.{NAME}` in `vcl_recv`                  | Remove cookie header to strip credentials<br/>Store data to refer to later in VCL |
| Backend request             | `bereq.http.{NAME}` in `vcl_miss` and `vcl_pass` | Add authentication headers                                                        |
| Backend response            | `beresp.http.{NAME}` in `vcl_fetch`              | Set browser cache TTL<br/>Remove superfluous origin response headers              |
| Client response             | `resp.http.{NAME}` in `vcl_deliver`              | Set cookies                                                                       |
| Synthetic response          | `obj.http.{NAME}` in `vcl_error`                 | Set the content-type of the `synthetic` response                                  |

## URLs and query strings

The `req.url` variable contains the URL (path and query) being requested by the client, and is copied into `bereq.url` when making a request to a backend. The path and query can be separately accessed as `req.url.path` and `req.url.qs`. Consider using `querystring.get` and `querystring.set` to manipulate query parameters. `querystring.filter` can remove unwanted query parameters:

[Try it in Fastly Fiddle](https://fiddle.fastly.dev/5146d116)

Using regular expressions on the URL path is a common way to route requests to different backends, by setting `req.backend`:

[Try it in Fastly Fiddle](https://fiddle.fastly.dev/296463fa)

## Cookies

Since the `Cookie` header is a comma-delimited list of individual cookies, you can access a named cookie using subfield accessor syntax. Often this is usefully combined with a regular expression match to extract parts of a structured cookie value. For example, if you have a cookie called `auth`, which has a value such as `52b93cff.165826435.d783dad8-ebb9-4475-b6fb-68ce83f90f12`, you could use the following VCL to isolate the `auth` cookie, and then extract the various parts of it into distinct HTTP headers:

```vcl context="sub vcl_recv { ... }"
if (req.http.cookie:auth ~ "^([0-9a-f]+).(\d+).([\w-]+)$") {
  set req.http.Auth-SessionID = re.group.1;
  set req.http.Auth-CreditCount = re.group.2;
  set req.http.Auth-DisplayName = re.group.3;
}
```

To write cookies, construct a `Set-Cookie` header on the client response, normally in `vcl_deliver`. Using `set` will overwrite any existing header with the same name, so if you may be setting multiple cookies in the same response, use `add` instead. It's also wise, when setting cookies on a response, to prevent the client or any downstream entity from caching it.

```vcl context="sub vcl_deliver { ... }"
add resp.http.set-cookie = "auth=52b93cff.165826435.d783dad8-ebb9-4475-b6fb-68ce83f90f12; max-age=86400; path=/";
set resp.http.cache-control = "private, no-store";
```

## Logging

Fastly supports logging data to a variety of specific vendors and generic endpoints. In VCL, you can emit a log message from anywhere in your VCL code using the `log` statement:

```vcl
log "syslog " + req.service_id + " my-log-endpoint :: " + req.url;
```

All log statements in VCL take the form `log "syslog {service_id} {log_endpoint_name} :: {log_message}`. For more information on configuring log endpoints, and how to use them, refer to our [Logging overview](https://www.fastly.com/documentation/guides/integrations/non-fastly-services/developer-guide-logging).

## Controlling the cache

Fastly respects freshness-related HTTP headers sent in origin responses, such as `Cache-Control`, `Last-Modified`, and `Expires`. You can override this behavior using VCL in `vcl_fetch`, by setting the values of `beresp.ttl`, `beresp.stale_while_revalidate`, and `beresp.stale_if_error`.

```vcl context="sub vcl_fetch { ... }"
set beresp.ttl = 30m;
```

Regardless of HTTP headers or explicit instructions in VCL, the cache may be disabled if the response has an HTTP status that does not support caching. A `200` (OK) response is considered cacheable, while a `500` (Internal Server Error) is not. You can change this decision by setting `beresp.cacheable`. For more information, read our [HTTP semantics overview](https://www.fastly.com/documentation/guides/concepts/cache/cache-freshness).

> **IMPORTANT:** Setting the value of headers such as `Cache-Control` using VCL will not have any affect on whether or for how long the response is cached by Fastly (use `beresp.ttl` instead), but setting a `Cache-Control` header on a response is a good way to control whether the response is cached on the end user's device.
> To disable caching entirely, execute a `return(pass)` from `vcl_recv` or `vcl_fetch`. Doing so in `vcl_recv` offers better performance because it allows us to skip [request collapsing](https://www.fastly.com/documentation/guides/concepts/cache/request-collapsing).

## Synthetic responses

Synthetic responses can be used to create customized error messages, responses to API calls, and full pages of content, and they're  often employed for site-wide metadata such as `robots.txt` files. For more information on synthetic responses, refer to our [synthetic](https://www.fastly.com/documentation/reference/vcl/statements/synthetic) documentation.
