---
title: Operators
summary: null
url: https://www.fastly.com/documentation/reference/vcl/operators
---

Fastly VCL provides various arithmetic and conditional operators.

## Operator precedence

Operator precedence defines the _order of operations_ when evaluating an expression. Higher precedence operators are evaluated before those with lower precedence. Operators are listed in the following table, highest precedence first. For example, `a || b && c` reads as `a || (b && c)` because `&&` has higher precedence than `||`.

Operator _associativity_ determines which side binds first for multiple instances of the same operator at equal precedence. For example, `a && b && c` reads as `(a && b) && c` because `&&` has left to right associativity.

| Operator          | Name                    | Associativity |
| ----------------- | ----------------------- | ------------- |
| `(` `)`           | Grouping for precedence | left to right |
| `!`               | Boolean NOT             | right to left |
| `&&`              | Boolean AND             | left to right |
| <code>\|\|</code> | Boolean OR              | left to right |

> **HINT:** use explicit parentheses in expressions to avoid having to remember operator precedence rules.

## Negation

Numeric literals may be negated by prefixing the `-` unary operator. This operator may only be applied to literals and not to numeric values in other contexts.

## String concatenation

Adjacent strings are concatenated implicitly, or explicitly by using the `+` operator. All of the following lines of code achieve the same result:

```vcl
set req.http.some-header = "helloworld";
set req.http.some-header = "hello" "world";
set req.http.some-header = "hello" + "world";
```

Concatenation works with literal strings, as well as headers and variables (including non-string types):

```vcl
set var.string_variable = "Hello " + req.http.cookie:user_name + " you are number " + var.int_variable;
```

## Conditional operators

Logical AND and OR operators (`&&` and `||` respectively) are defined for conditional expressions.

> **WARNING:** Logical operators have _short-circuit_ evaluation, whereby the right-hand side is only evaluated when necessary. For example, given `a && b`, if `a` is false the resulting value will always be false, so there's no need to evaluate `b`. This can be important when the right-hand operand has a visible side effect, such as a call to a function.

Conditional expressions may be inverted by prefixing the `!` operator.

Conditional operators produce `BOOL` values, suitable for use in `if (...)` statements:

```vcl
if (!(beresp.status >= 500 && beresp.status < 600)) {
  # ... the response is not an HTTP 5XX status
}
```

## Comparison operators

The comparison operators are:

| Operator | Purpose                                                                                | Example                                              | Types                    |
| -------- | -------------------------------------------------------------------------------------- | ---------------------------------------------------- | ------------------------ |
| `==`     | Equal                                                                                  | `resp.status == 200` (note there is no `===` in VCL) | All types                |
| `!=`     | Not equal                                                                              | `req.url.path != "/"`                                | All types                |
| `~`      | Matches regex                                                                          | `req.url ~ "^/products(?:/?.*)\z"`                   | `STRING`                 |
| `~`      | Matches [ACL](https://www.fastly.com/documentation/reference/glossary#term-acl)        | `client.ip ~ allowed_users`                          | `IP`                     |
| `!~`     | Does not match regex                                                                   | `req.http.cookie:optin !~ "ads"`                     | `STRING`                 |
| `!~`     | Does not match [ACL](https://www.fastly.com/documentation/reference/glossary#term-acl) | `client.ip !~ blocked_users`                         | `IP`                     |
| `>`      | Greater than                                                                           | `req.restarts > 0`                                   | Numeric types and `TIME` |
| `<`      | Less than                                                                              | `now < var.expiry_time`                              | Numeric types and `TIME` |
| `>=`     | At least                                                                               | `resp.status >= 500`                                 | Numeric types and `TIME` |
| `<=`     | At most                                                                                | `randomint(1,100) <= 75`                             | Numeric types and `TIME` |

FLOAT comparisons have special cases for operands which are NaN: The `!=` operator always evaluates to true when either operand is NaN. All other conditional operators always evaluate to false when either operand is NaN. For example, if a given variable is NaN, that variable will compare unequal to itself: both `var.nan == var.nan` and `var.nan >= var.nan` will be false.

STRING comparisons have special cases for operands which are not set (as opposed to empty): The `!=` and `!~` operators always evaluate to true when either operand is not set. All other conditional operators always evaluate to false when either operand is not set. For example, if a variable is not set, that variable will compare unequal to itself: Both `req.http.unset == req.http.unset` and `req.http.unset ~ ".?"` will be false.

Floating point infinities are signed, and compare as beyond the maximum and minimum values for FLOAT types, such that for any finite value: −∞ &lt; n &lt; +∞.

Note that as there are currently no numeric expressions in general, these operators are limited to use with specific operands. For example, `var.i < 5` is permitted but `2 < 5` is not.

## Assignment operators

These operators allow values or the results of expressions to be assigned to a variable using the `set` statement.

| Operator           | Purpose           | Example                                                |
| ------------------ | ----------------- | ------------------------------------------------------ |
| `=`                | Simple assignment | `set var.my_string = "42";`                            |
| `+=`               | Addition          | `set var.my_integer += 4;`                             |
| `-=`               | Subtraction       | `set var.my_integer -= 4;`                             |
| `*=`               | Multiplication    | `set var.my_integer *= 4;`                             |
| `/=`               | Division          | `set var.my_integer /= 4;`                             |
| `%=`               | Remainder         | `set var.my_integer %= 4;`                             |
| <code>\|=</code>   | Bitwise OR        | <code>set var.my_integer \|= 16;</code>                |
| `&=`               | Bitwise AND       | `set var.my_integer &= 65280;`                         |
| `^=`               | Bitwise XOR       | `set var.my_integer ^= 16;`                            |
| `<<=`              | Left shift        | `set var.my_integer <<= 4;`                            |
| `>>=`              | Right shift       | `set var.my_integer >>= 4;`                            |
| `rol=`             | Left rotate       | `set var.my_integer rol= 4;`                           |
| `ror=`             | Right rotate      | `set var.my_integer ror= 4;`                           |
| `&&=`              | Logical AND       | `set var.my_boolean &&= var.is_authenticated;`         |
| <code>\|\|=</code> | Logical OR        | <code>set var.my_boolean \|\|= randombool(1,3);</code> |

The `set` syntax is the only situation in which these operators may be used. Since the operator may only occur once in a `set` statement, these operators are mutually exclusive, so precedence between them is nonsensical.

The values the operators produce are used for assignment only. The `set` statement assigns this value to a variable, but does not itself evaluate to a value.

If both operands (left-hand side and right-hand-side) are `INTEGER`, an `INTEGER` variant of the operator, where available, is used. The advantage of this is that the operation is faster and more precise (compared with `FLOAT` variants), but because the range of `INTEGER` is more limited, overflows can happen. For example, the integer variants of the `+=`, `-=`, and `*=` operators wrap around as if they were unsigned 64-bit integers.

`FLOAT` arithmetic has special cases for operands which are NaN: Arithmetic operators evaluate to NaN when either operand is NaN.

`FLOAT` arithmetic has special cases for operands which are floating point infinities: In general all arithmetic operations evaluate to positive or negative infinity when either operand is infinity. However, some situations evaluate to NaN. Some of these situations are _domain errors_, in which case `fastly.error` is set to `EDOM` accordingly. Others situations are not domain errors: ∞ − ∞ and 0 × ∞. These evaluate to NaN but do not set `fastly.error`.

The left-shift `<<=` is equivalent to multiplying by powers of two, but the high-order bits disappearing. For example, `<<= 3` is equivalent to multiplying by `8`, shifting off the highest three bits.

The right-shift `>>=` is the arithmetic shift: that is, for both positive and negative integers it is equivalent to dividing by powers of two. For example, `>>= 3` is equivalent to dividing by `8`, shifting off the lowest three bits. For negative integers this is also known as sign-extension: at the binary level, the sign bit (the highest bit) is copied to all the vacant bits.

The left-rotate `rol=` moves the bits towards the high end but the bits dropping off from the high end are rotated back to the low end. For example, `rol= 1` moves the highest bit to the low end, and moves all the other bits up.

The right-rotate `ror=` moves the bits towards the low end but the bits dropping off the low end are rotated back to the high end. For example, `ror= 1` moves the lowest bit to the high end, and moves all the other bits down.

Shift and rotate operations with negative amounts perform the operation in the opposite direction. For example, `<<= -3` is equivalent to `>>= 3`, and `rol= >> -3` is equivalent to `ror= 3`.

The remainder operator `%=` performs the same function as a [modulus](https://en.wikipedia.org/wiki/Modulo) operator for positive numbers.

For right operands larger than the bit width of INTEGER (64), shifts will yield zero for non-negative numbers, or -1 for negative numbers. Rotates will use the operand modulo the bit width of INTEGER. For example, `>>= 99` will yield zero or -1, and `ror= 99` is equivalent to `ror= 35` because 99 % 64 is 35.

Logical AND and OR are provided in assignment form by the `&&=` and `||=` operators respectively. These are _short-circuit_ operators, see _conditional operators_ above.

## Reserved punctuation

Punctuation appears in various syntactic roles which are not operators (that is, they do not produce a value).

| Punctuation | Example Uses                                                        |
| ----------- | ------------------------------------------------------------------- |
| `{` `}`     | Block syntax                                                        |
| `[` `]`     | Stats ranges                                                        |
| `(` `)`     | Syntax around if conditions, function argument lists                |
| `/`         | Netmasks for ACLs                                                   |
| `,`         | Separator for function arguments                                    |
| `;`         | Separator for statements and various other syntactic things         |
| `!`         | Invert ACL entry                                                    |
| `.`         | To prefix fields in backend declarations                            |
| `:`         | Port numbers for backend declarations, and used in the stats syntax |

The following lexical tokens are reserved, but not used: `*` `&` `|` `>>` `<<` `++` `--` `%`
