Varnish Cache
Introduction
VCL (Varnish Configuration Language) is a domain-specific language designed for defining request handling logic in Varnish Cache. Unlike traditional configuration files, VCL is a procedural language that gets compiled into C code and then into native machine code for optimal performance.
Varnish Cache is a high-performance HTTP accelerator that sits between your application servers and clients, caching content to dramatically reduce server load and improve response times.
VCL Architecture Overview
Key Components
- libvcc: VCL Compiler library located in
lib/libvcc/ - VCL Runtime: Execution engine in
bin/varnishd/cache/ - Management Process: VCL lifecycle management in
bin/varnishd/mgt/ - VMODs: Extension modules that extend VCL functionality
VCL Processing Flow
Client Request
↓
vcl_recv → vcl_hash → [Cache Lookup]
↓ ↓
├─ vcl_hit ──────────────┘
├─ vcl_miss → vcl_backend_fetch → vcl_backend_response
└─ vcl_pass → vcl_backend_fetch → vcl_backend_response
↓
vcl_deliver
↓
Client ResponseVCL Compilation Process
Compilation Pipeline
Compilation Steps
1. Source Processing (vcc_source.c)
The VCL source code is read and prepared for compilation:
// Location: lib/libvcc/vcc_source.c
struct source *vcc_new_source(const char *src, const char *kind, const char *name);- Handles both inline VCL strings and file-based sources
- Tracks source location for error reporting
- Supports
includedirectives for modular VCL files
2. Lexical Analysis (vcc_token.c)
The tokenizer breaks down VCL source into tokens:
Token Types:
- Keywords:
sub,if,else,return,set,unset - Identifiers: Variable names, function names
- Literals: Strings, numbers, durations, bytes
- Operators:
==,!=,~,!~,&&,|| - Special tokens:
{,},;,,,.
3. Parsing (vcc_parse.c)
The parser builds an Abstract Syntax Tree (AST) from tokens:
Parsing Components:
- Subroutine definitions:
sub vcl_recv { ... } - Backend definitions:
backend default { ... } - ACL definitions:
acl purge_acl { ... } - Probe definitions:
probe health_check { ... } - Conditional statements:
if,else,elsif - Actions:
set,unset,return,call
VCL State Machine
VCL processing is organized as a state machine where each method represents a state. The flow through states is controlled by return() actions.
Key VCL Methods
Client-Side Methods
| Method | Purpose | Common Returns |
|---|---|---|
vcl_recv | Initial request processing | hash, pass, pipe, synth |
vcl_hash | Generate cache key | lookup |
vcl_hit | Handle cache hits | deliver, pass |
vcl_miss | Handle cache misses | fetch, pass |
vcl_deliver | Final response preparation | deliver |
vcl_synth | Generate synthetic responses | deliver |
Backend-Side Methods
| Method | Purpose | Common Returns |
|---|---|---|
vcl_backend_fetch | Prepare backend request | fetch, abandon |
vcl_backend_response | Process backend response | deliver, pass, retry |
vcl_backend_error | Handle backend errors | deliver, retry |
Request Processing Flow
Client Request Flow
Pass Mode Flow
Common VCL Variables
Client-side (vcl_recv, vcl_deliver)
req.url- Request URLreq.method- HTTP methodreq.http.*- Request headersclient.ip- Client IP addressresp.http.*- Response headersresp.status- Response status code
Backend-side (vcl_backend_*)
bereq.url- Backend request URLbereq.http.*- Backend request headersberesp.status- Backend response statusberesp.ttl- Time to liveberesp.http.*- Backend response headers
Object (vcl_hit, vcl_deliver)
obj.ttl- Object TTLobj.grace- Grace periodobj.hits- Number of hitsobj.http.*- Cached headers
VCL Type System
Built-in Types
| Type | C Type | Description | Example |
|---|---|---|---|
STRING | const char * | Text strings | "Hello, World" |
INT | VCL_INT (int64_t) | 64-bit integers | 42, -100 |
REAL | VCL_REAL (double) | Floating point | 3.14, 2.5 |
DURATION | VCL_DURATION (double) | Time duration | 10s, 2m, 1h |
BYTES | VCL_BYTES (int64_t) | Byte sizes | 1KB, 10MB, 1GB |
BOOL | VCL_BOOL (unsigned) | Boolean | true, false |
TIME | VCL_TIME (double) | Absolute time | now, now + 1h |
IP | VCL_IP | IP addresses | client.ip |
BACKEND | VCL_BACKEND | Backend/director | backend default |
ACL | VCL_ACL | Access control list | acl purge |
REGEX | vre_t | Regular expression | /^www\./ |
Type Conversion Examples
# String to boolean (implicit)
if (req.http.X-Forwarded-For) { # Non-empty string = true
# ...
}
# Int to string (implicit)
set resp.http.X-Count = 42; # 42 converted to "42"
# Duration to string
set resp.http.X-TTL = obj.ttl; # "120.000" for 120s TTL
# Explicit conversions via std VMOD
import std;
std.integer(req.http.X-Count, 0); # String to intVMOD System
VMODs (Varnish Modules) extend VCL functionality through shared libraries.
VMOD Loading Process
- Import Declaration:
import std; - Symbol Resolution: VCC loads VMOD descriptor
- Type Checking: Validate function calls
- Dynamic Loading: Load
.soat runtime - Initialization: Call VMOD event handlers
Grace Mode and Stale Content
Grace Configuration
sub vcl_backend_response {
# TTL for fresh content
set beresp.ttl = 10m;
# Grace period for stale content
set beresp.grace = 1h;
# Keep for additional time
set beresp.keep = 2h;
}
sub vcl_hit {
if (obj.ttl >= 0s) {
# Fresh object
return (deliver);
} else if (obj.ttl + obj.grace > 0s) {
# Stale but within grace
return (deliver);
} else {
# Too old
return (miss);
}
}Synthetic Responses
Example Implementation
sub vcl_recv {
if (req.url ~ "^/health") {
return (synth(200, "OK"));
}
}
sub vcl_synth {
if (resp.status == 200) {
set resp.http.Content-Type = "application/json";
set resp.body = {"{"}"status":"healthy"{"}"}";
return (deliver);
}
}VCL Variable Hierarchy
Variable Accessibility by Method
| Variable Namespace | vcl_recv | vcl_hash | vcl_miss | vcl_hit | vcl_deliver | vcl_backend_* |
|---|---|---|---|---|---|---|
req.* | R/W | R | R | R | R | - |
client.* | R | R | R | R | R | - |
server.* | R | R | R | R | R | R |
obj.* | - | - | - | R | R | - |
resp.* | - | - | - | - | R/W | - |
bereq.* | - | - | - | - | - | R/W |
beresp.* | - | - | - | - | - | R/W |
backend.* | - | - | - | - | - | R |
Legend:
- R = Read only
- R/W = Read and Write
-= Not accessible
Performance Best Practices
Good Practices
# GOOD: Minimize string operations
sub vcl_recv {
# Only set if needed
if (req.url ~ "^/api/") {
set req.http.X-API = "true";
}
}
# GOOD: Use simpler checks first
if (req.url ~ "^/very/complex/") {
if (req.url ~ "with|multiple|alternatives") {
# ...
}
}Avoid These Patterns
# BAD: String concatenation in hot path
sub vcl_recv {
set req.http.X-Custom = "prefix-" + req.url + "-suffix";
}
# BAD: Complex regex in vcl_recv
if (req.url ~ "^/very/complex/regex/pattern/(with|multiple|alternatives)/.*$") {
# ...
}Debugging and Introspection
VCL Logging
import std;
sub vcl_recv {
std.log("vcl_recv: " + req.url);
std.log("Client IP: " + client.ip);
std.log("Method: " + req.method);
}VSL (Varnish Shared Log)
View VCL execution for debugging:
# View VCL execution
varnishlog -g request -i VCL_call,VCL_return
# Example output:
# VCL_call RECV
# VCL_return hash
# VCL_call HASH
# VCL_return lookup
# VCL_call MISS
# VCL_return fetchVCL File Locations
| Component | Location |
|---|---|
| VCL Compiler | lib/libvcc/ |
| Runtime Engine | bin/varnishd/cache/cache_vcl.* |
| VCL Management | bin/varnishd/mgt/mgt_vcl.* |
| Type Definitions | include/vcl.h |
| State Transitions | include/tbl/vcl_returns.h |
| Builtin VCL | bin/varnishd/builtin.vcl |
| Example VCL | etc/example.vcl |
Summary
VCL's internal architecture demonstrates sophisticated compiler design and runtime engineering:
- Multi-phase compilation: Lexing → Parsing → Type checking → C generation → Native code
- State machine execution: Predictable request flow through well-defined states
- Type safety: Strong typing with implicit conversions where sensible
- Extensibility: VMOD system for custom functionality
- Performance: Compiled to native code with optimizations
- Flexibility: Dual-layer VCL (user + builtin) for sensible defaults
Key Takeaways
- VCL is compiled, not interpreted, for maximum performance
- The state machine provides clear separation of concerns
- Built-in VCL ensures sane defaults while allowing overrides
- VMODs extend functionality without core changes
- Type system prevents common errors at compile time
- Event system manages VCL lifecycle cleanly
Additional Resources
- Official Varnish Documentation (opens in a new tab)
- VCL Reference (opens in a new tab)
- Varnish Book (opens in a new tab)
Version: Varnish 7.7.0 Last Updated: 2025