Loading learning content...
Imagine you've just discovered a critical error on your homepage—a pricing typo that shows $9.99 instead of $99.99. With most CDNs, you'd issue a cache purge and wait anxiously for 30 seconds to several minutes while stale content continues being served worldwide. With Fastly, that content is purged globally in less than 150 milliseconds.
This capability isn't just a marketing feature—it fundamentally changes how you can architect applications. When cache invalidation is effectively instant, you can cache aggressively without fear, deliver personalized content at the edge, and treat your CDN as a real-time content platform rather than a static cache layer.
Fastly was founded in 2011 with a radical premise: what if we rebuilt the CDN from scratch, optimized for developers and real-time control? Today, Fastly powers some of the world's most demanding websites—including The New York Times, GitHub, Stripe, and Shopify—each requiring split-second cache control and developer-friendly configuration.
By the end of this page, you will understand Fastly's unique architecture built on Varnish, how instant purge works at a technical level, VCL and Compute@Edge programming models, Fastly's approach to observability, and when Fastly is the optimal choice for modern web applications.
Fastly was built by engineers from Wikia and Fastly's founder, Artur Bergman, who was frustrated with existing CDNs' slow configuration and purge times. The company made a bold architectural choice: build the entire platform on Varnish Cache, an open-source HTTP accelerator known for its performance and programmability.
The Varnish Foundation:
Varnish Cache was created by Poul-Henning Kamp, a FreeBSD developer, with a fundamentally different philosophy than traditional caches:
Fastly extended Varnish with global distribution, instant purge mechanisms, real-time logging, and a developer-friendly management interface.
Fastly Network Architecture:
┌────────────────────────────────────────────────────────────────────────────────┐
│ Fastly Network Architecture │
├────────────────────────────────────────────────────────────────────────────────┤
│ │
│ DNS Query │
│ │ │
│ ▼ │
│ ┌─────────────────────┐ │
│ │ Fastly DNS (Anycast)│ → Routes to nearest POP based on geography + health │
│ └──────────┬──────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────────────────────┐ │
│ │ Fastly POP (Edge Cloud) │ │
│ │ │ │
│ │ ┌────────────────────────────────────────────────────────────────────┐│ │
│ │ │ Cache Cluster ││ │
│ │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ││ │
│ │ │ │ Varnish │ │ Varnish │ │ Varnish │ ││ │
│ │ │ │ Instance │ │ Instance │ │ Instance │ ││ │
│ │ │ │ │ │ │ │ │ ││ │
│ │ │ │ • VCL Logic │ │ • VCL Logic │ │ • VCL Logic │ ││ │
│ │ │ │ • RAM Cache │ │ • RAM Cache │ │ • RAM Cache │ ││ │
│ │ │ │ • Compute@Edge│ │ • Compute@Edge│ │ • Compute@Edge│ ││ │
│ │ │ └──────────────┘ └──────────────┘ └──────────────┘ ││ │
│ │ │ │ ││ │
│ │ │ Consistent Hashing for object distribution ││ │
│ │ └────────────────────────┼───────────────────────────────────────────┘│ │
│ │ │ │ │
│ │ Shield / Origin Fetch (if cache miss) │ │
│ └────────────────────────────┼────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────────────────────┐│
│ │ Origin Shield ││
│ │ • Aggregates cache misses from multiple POPs ││
│ │ • Reduces origin load ││
│ │ • Single designate POP per origin ││
│ └──────────────────────────────────────────────────────────────────────────┘│
│ │ │
│ ▼ │
│ ┌──────────────┐ │
│ │ Origin │ │
│ │ Server │ │
│ └──────────────┘ │
└────────────────────────────────────────────────────────────────────────────────┘
Fastly's smaller network footprint (90+ vs 300+ POPs) means slightly longer average distance to users compared to Cloudflare. However, larger POPs mean better per-location cache hit ratios. For most applications, the difference is negligible (<10ms), but latency-obsessed use cases should measure specifically.
Fastly's instant purge—completing in under 150 milliseconds globally—is the company's signature capability. Understanding how it works reveals why most CDNs can't replicate it easily.
The Purge Challenge:
Traditional CDNs struggle with fast purging because:
Fastly's Approach:
Fastly solves these challenges through several mechanisms:
| Mechanism | How It Works | Impact |
|---|---|---|
| Memory-first caching | Objects stored in RAM, not disk | No disk I/O delay for purge checks |
| Centralized purge coordination | Single purge queue processed globally | Consistent ordering, no race conditions |
| Push-based invalidation | Purge pushed to all POPs simultaneously | No polling delay |
| Surrogate keys (tags) | Objects tagged with multiple keys for grouped purge | Single API call invalidates related content |
| Fewer POPs | ~90 vs 300+ locations | Smaller blast radius, faster propagation |
Surrogate Keys (Cache Tags):
Surrogate keys are Fastly's killer feature for cache invalidation. Instead of purging by URL (which requires knowing every cached URL), you tag content during caching and purge by tag:
1234567891011121314151617
# Origin sets Surrogate-Key header during response# Multiple space-separated keys can be assigned # Product page responseHTTP/1.1 200 OKSurrogate-Key: product-123 category-electronics homepage featuredCache-Control: max-age=3600 # Article page response HTTP/1.1 200 OKSurrogate-Key: article-456 author-john category-tech homepageCache-Control: max-age=1800 # User profile responseHTTP/1.1 200 OKSurrogate-Key: user-789 user-789-avatar user-789-postsCache-Control: max-age=600Think of surrogate keys as cache dependencies. Every piece of content should include keys for all the entities it depends on: products it displays, users it mentions, categories it belongs to. When any entity changes, purging its key invalidates all dependent content without knowing specific URLs.
VCL (Varnish Configuration Language) is a domain-specific language that gives you complete control over how Fastly handles every request. Unlike configuration-based CDNs, VCL is actual code that executes on every request.
VCL Subroutines:
VCL code is organized into subroutines that execute at different points in the request lifecycle:
| Subroutine | When It Runs | Common Uses |
|---|---|---|
| vcl_recv | Start of request, before cache lookup | Auth check, URL rewrites, routing, request normalization |
| vcl_hash | Generating cache key | Custom cache key logic, vary by custom headers |
| vcl_hit | Cache hit found | Modify cached response, check freshness |
| vcl_miss | Cache miss, before origin fetch | Modify origin request, select backend |
| vcl_pass | Bypassing cache | Force origin fetch for specific requests |
| vcl_fetch | Response received from origin | Set caching rules, modify response |
| vcl_deliver | Before sending to client | Add headers, final modifications |
| vcl_error | Generating error responses | Custom error pages, synthetic responses |
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950
# vcl_recv - Handle incoming requestssub vcl_recv { # Normalize host header to lowercase set req.http.Host = std.tolower(req.http.Host); # Remove tracking query parameters for better cache efficiency set req.url = querystring.filter_except(req.url, "page" + querystring.filtersep() + "sort" + querystring.filtersep() + "filter" ); # Geographic routing based on client location if (client.geo.continent_code == "EU") { set req.backend = EU_origin; } else if (client.geo.continent_code == "AS") { set req.backend = APAC_origin; } else { set req.backend = US_origin; } # A/B testing - assign variant if not already assigned if (!req.http.Cookie:experiment) { # Random assignment if (randombool(50, 100)) { set req.http.X-Experiment = "A"; } else { set req.http.X-Experiment = "B"; } } else { set req.http.X-Experiment = req.http.Cookie:experiment; } # Force HTTPS if (!req.is_ssl) { error 801 "Force HTTPS"; } # Protect admin routes if (req.url ~ "^/admin" && !req.http.X-Admin-Token) { error 403 "Forbidden"; } # API requests bypass cache if (req.url ~ "^/api/" && req.method != "GET") { return(pass); } return(lookup); # Proceed to cache lookup}VCL is powerful but has a steep learning curve. It's not JavaScript—it's closer to a configuration language with procedural elements. Syntax errors can take down your service. Always test in staging, use Fastly Fiddle for experiments, and start with Fastly's pre-built snippets before writing custom VCL.
Compute@Edge is Fastly's answer to Cloudflare Workers—serverless computing at the edge. Unlike VCL, Compute@Edge runs WebAssembly, allowing you to write edge logic in languages like Rust, JavaScript/TypeScript, Go, or any language that compiles to Wasm.
Compute@Edge Architecture:
┌────────────────────────────────────────────────────────────────────────────────┐
│ Compute@Edge Execution Model │
├────────────────────────────────────────────────────────────────────────────────┤
│ │
│ Request │
│ │ │
│ ▼ │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ Lucet WebAssembly Runtime │ │
│ │ │ │
│ │ ┌─────────────────────────────────────────────────────┐ │ │
│ │ │ Your Wasm Module │ │ │
│ │ │ │ │ │
│ │ │ • Written in Rust, JS, Go, AssemblyScript, etc. │ │ │
│ │ │ • Compiled to WebAssembly │ │ │
│ │ │ • Runs in isolated sandbox │ │ │
│ │ │ • 50ms startup time (vs 100ms+ for Lambda@Edge) │ │ │
│ │ │ │ │ │
│ │ │ Available APIs: │ │ │
│ │ │ • HTTP request/response manipulation │ │ │
│ │ │ • KV Store access │ │ │
│ │ │ • Secret Store │ │ │
│ │ │ • Config Store │ │ │
│ │ │ • Geolocation data │ │ │
│ │ │ • Outbound fetch (to backends or internet) │ │ │
│ │ └─────────────────────────────────────────────────────┘ │ │
│ └───────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ Response or Backend Fetch │
└────────────────────────────────────────────────────────────────────────────────┘
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
use fastly::http::{header, Method, StatusCode};use fastly::{Error, Request, Response}; /// Main entry point for Compute@Edge#[fastly::main]fn main(req: Request) -> Result<Response, Error> { // Log request for debugging println!("Request: {} {}", req.get_method(), req.get_path()); // Route based on path match req.get_path() { // Health check endpoint "/health" => Ok(Response::from_status(StatusCode::OK) .with_body("OK")), // API endpoint with authentication path if path.starts_with("/api/") => handle_api(req), // Static content from backend _ => handle_static(req), }} fn handle_api(mut req: Request) -> Result<Response, Error> { // Validate JWT token let auth_header = req.get_header_str(header::AUTHORIZATION); match auth_header { Some(token) if validate_jwt(token) => { // Forward to API backend let backend = fastly::Backend::from_name("api_origin")?; req.send(backend) } _ => { Ok(Response::from_status(StatusCode::UNAUTHORIZED) .with_body_json(&serde_json::json!({ "error": "Invalid or missing authentication token" }))?) } }} fn handle_static(req: Request) -> Result<Response, Error> { // Check KV store for feature flags let kv_store = fastly::KVStore::open("config")?.unwrap(); let maintenance_mode = kv_store .lookup("maintenance_mode") .map(|v| v.into_string() == "true") .unwrap_or(false); if maintenance_mode { return Ok(Response::from_status(StatusCode::SERVICE_UNAVAILABLE) .with_body("Site under maintenance")); } // Fetch from origin let backend = fastly::Backend::from_name("static_origin")?; let mut resp = req.send(backend)?; // Add security headers resp.set_header("Strict-Transport-Security", "max-age=31536000"); resp.set_header("X-Content-Type-Options", "nosniff"); Ok(resp)} fn validate_jwt(token: &str) -> bool { // JWT validation logic // In production, use jsonwebtoken crate token.starts_with("Bearer valid_")}Fastly's approach to observability is distinctly real-time. Unlike CDNs that batch logs and deliver them minutes later, Fastly streams logs and metrics as they happen.
Real-Time Log Streaming:
Fastly can stream logs to any HTTP endpoint, syslog server, or popular log management platforms:
| Destination | Latency | Use Case |
|---|---|---|
| HTTPS Endpoint | < 1 second | Custom log processing pipelines |
| Amazon S3 | < 5 seconds | Long-term storage, batch analysis |
| Google Cloud Storage | < 5 seconds | GCP ecosystem integration |
| Datadog | < 2 seconds | Real-time monitoring, alerting |
| Splunk | < 2 seconds | Security analysis, SIEM |
| Elasticsearch | < 3 seconds | Full-text search, Kibana dashboards |
| BigQuery | < 10 seconds | SQL analytics on log data |
| New Relic | < 2 seconds | APM integration |
Custom Log Formats with VCL:
Fastly lets you define exactly what gets logged using VCL, enabling custom analytics:
12345678910111213141516171819
# Log JSON format for structured loggingsub vcl_log { # Stream to configured endpoint log "analytics" "{" ""timestamp":"" + strftime({"%Y-%m-%dT%H:%M:%SZ"}, now) + ""," ""client_ip":"" + client.ip + ""," ""method":"" + req.method + ""," ""url":"" + req.url + ""," ""status":" + resp.status + "," ""bytes":" + resp.body_bytes_written + "," ""cache":"" + fastly_info.state + ""," ""ttfb":" + time.to_first_byte + "," ""country":"" + client.geo.country_code + ""," ""asn":" + client.as.number + "," ""pop":"" + server.datacenter + ""," ""user_agent":"" + req.http.User-Agent + """ "}";}Fastly's real-time logs transform debugging. Instead of waiting for batch logs to identify issues, you can watch requests flow through in real-time. Combine with Fastly Fiddle (live VCL testing) for a powerful development workflow: make VCL changes, see immediate log output, iterate quickly.
Fastly's security approach differs from Cloudflare's comprehensive, built-in model. Instead, Fastly offers modular security products that integrate with its CDN platform.
Fastly Next-Gen WAF:
Fastly acquired Signal Sciences in 2020, gaining one of the most advanced WAF technologies in the market:
DDoS Protection:
Fastly provides DDoS protection at the network layer automatically, with application-layer protection available through the WAF:
Unlike Cloudflare's included security, Fastly's Next-Gen WAF is a separate product with significant additional cost. Expect $10,000-100,000+ annually depending on traffic and features. For budget-conscious projects, Cloudflare may offer better security value.
Fastly uses consumption-based pricing similar to traditional CDNs, with some unique aspects around developer tooling and Compute@Edge.
Pricing Components:
| Component | Rate | Notes |
|---|---|---|
| Bandwidth (US/Europe) | $0.08/GB first 10TB | Decreasing tiers with volume |
| Bandwidth (Asia/Oceania) | $0.12-0.19/GB | Higher rates outside US/Europe |
| Requests | $0.0075/10K requests | HTTP/HTTPS combined |
| Compute@Edge | $0.50/million invocations | Plus $12.80/million GB-seconds compute |
| Real-time logs | Free | Included with CDN |
| Origin Shield | Included | No additional charge |
| Image Optimizer | $0.002/image transform | Optional add-on |
| Next-Gen WAF | Custom pricing | Starts ~$10K annually |
Fastly vs Competitors Pricing:
| Feature | Fastly | Cloudflare | CloudFront |
|---|---|---|---|
| 100GB bandwidth | ~$8 | $0 (unmetered) | ~$8.50 |
| 1TB bandwidth | ~$80 | $0 (unmetered) | ~$85 |
| 1M edge compute invocations | $0.50 | $0.30 | $0.60 |
| Instant purge | Included | ~30s delay | ~30s delay |
| WAF included | No (add-on) | Yes | No (add-on) |
| Real-time logs | Included | Yes (10M/day free) | Optional ($) |
Fastly offers a developer-friendly free tier: $50 of free usage per month, which covers approximately 500GB of bandwidth and 5 million requests. This makes experimentation and development accessible without upfront commitment.
Fastly excels for specific workloads where real-time control and developer experience are paramount:
You now understand Fastly's unique value proposition: instant purge, VCL programmability, Compute@Edge, and real-time observability. This makes Fastly ideal for content-heavy sites requiring split-second cache control. Next, we'll synthesize all CDN providers into a decision framework for choosing the optimal solution.