Fastlike is a local development server for Fastly Compute (previously known as Compute@Edge) applications. It allows you to run and test your Fastly Compute WebAssembly programs locally without deploying to Fastly, making development faster and more efficient.
Fastlike is a complete Go implementation of the Fastly Compute XQD ABI that runs locally using WebAssembly. It emulates Fastly's runtime environment, allowing you to:
- Test Fastly Compute programs locally before deployment
- Debug issues without the deployment cycle
- Develop with hot-reloading capabilities
- Simulate backend services and configurations
- Full ABI Compatibility: Implements 100% of the Fastly Compute XQD ABI
- Local Development: Run Fastly Compute programs without deploying
- Multiple Backend Support: Configure multiple named backends
- Hot Reloading: Automatically reload WASM modules on file changes
- Dictionaries & Config Stores: Support for key-value lookups
- Caching: Full HTTP caching with surrogate keys
- ACL & Rate Limiting: Access control and rate limiting support
- Secure Secret Handling: Secure credential management
- KV Store Support: Object storage with async operations
- Image Optimization Hooks: Transform images on-the-fly
- Go 1.23 or later
go install fastlike.dev/cmd/fastlike@latest# Clone the repository (if you have the source code)
# If you just want to install, use: go install fastlike.dev/cmd/fastlike@latest
git clone https://github.com/fastlike/fastlike.git
cd fastlike
# Build and install
make build
# Binary will be available at ./bin/fastlike
# Or install to GOPATH/bin
make installYou'll need a Fastly Compute compatible WebAssembly program. The easiest way is using Fastly CLI:
# Create a new project
fastly compute init my-project
cd my-project
# Build the WASM binary
fastly compute build
# WASM file will be at bin/main.wasmStart Fastlike with your WASM program and a backend service:
# Run with a local backend on port 8000
fastlike -wasm bin/main.wasm -backend localhost:8000
# Or with a named backend
fastlike -wasm bin/main.wasm -backend api=localhost:8000 -bind localhost:5000Once running, make requests to your local Fastlike server:
curl http://localhost:5000/# Specify custom bind address
fastlike -wasm my-program.wasm -backend localhost:8000 -bind localhost:8080
# Enable verbose logging (0, 1, or 2 levels)
fastlike -wasm my-program.wasm -backend localhost:8000 -v 2
# Enable hot reloading on SIGHUP
fastlike -wasm my-program.wasm -backend localhost:8000 -reloadConfigure multiple named backends for complex routing:
fastlike -wasm my-program.wasm \
-backend api=localhost:8000 \
-backend static=localhost:8080 \
-backend images=localhost:9000Append @N to a backend address to simulate flakiness, where N is the percentage of requests that should reach the upstream successfully. The remaining requests are answered with a synthetic 502, identical in shape to the response Fastlike emits when a real upstream is unreachable. This is handy for exercising error paths in your guest program without actually taking a backend down.
# api responds normally for roughly half of requests, the rest get a 502
fastlike -wasm my-program.wasm -backend api=localhost:8000@50
# cdn always appears down
fastlike -wasm my-program.wasm -backend cdn=localhost:9000@0
# default catch-all backend with simulated reliability
fastlike -wasm my-program.wasm -backend localhost:8000@75The suffix is recognized only when it is purely numeric and in the 0..100 range, so URLs that legitimately contain @ (for example http://user:pass@host) are left alone. A trailing @<digits> outside 0..100 is rejected at startup. The same behavior is available programmatically through fastlike.WithUnreliableBackend and fastlike.WithUnreliableDefaultBackend.
Use JSON files for key-value lookups:
# Create a config file
echo '{"api_key": "secret123", "version": "1.0.0"}' > config.json
# Use as a dictionary
fastlike -wasm my-program.wasm -backend localhost:8000 -dictionary config=config.json
# Or use as a config store
fastlike -wasm my-program.wasm -backend localhost:8000 -config-store config=config.jsonThe file should contain a JSON object with string keys and values:
{
"key1": "value1",
"key2": "value2",
"api_endpoint": "https://api.example.com"
}Load KV store data from JSON files or create empty stores:
# Create a KV store with initial data
fastlike -wasm my-program.wasm -backend localhost:8000 -kv mystore=data.json
# Create an empty KV store
fastlike -wasm my-program.wasm -backend localhost:8000 -kv mystoreKV store JSON supports simple string values or objects with body and metadata:
{
"simple_key": "simple value",
"key_with_metadata": {
"body": "the value content",
"metadata": "optional metadata"
}
}Store sensitive credentials in JSON files:
fastlike -wasm my-program.wasm -backend localhost:8000 -secret-store secrets=secrets.jsonSecret store JSON format (string key-value pairs):
{
"api_key": "sk-live-xxxxx",
"database_password": "supersecret"
}Configure IP-based access control:
fastlike -wasm my-program.wasm -backend localhost:8000 -acl blocklist=acl.jsonACL JSON format with CIDR prefixes and actions:
{
"entries": [
{"prefix": "192.168.0.0/16", "action": "ALLOW"},
{"prefix": "10.0.0.0/8", "action": "ALLOW"},
{"prefix": "172.16.0.0/12", "action": "BLOCK"}
]
}Provide custom IP-to-location mappings:
fastlike -wasm my-program.wasm -backend localhost:8000 -geo geo.jsonGeo JSON maps IP addresses or CIDRs to location data:
{
"192.168.1.0/24": {
"city": "San Francisco",
"country_code": "US",
"region": "CA",
"latitude": 37.7749,
"longitude": -122.4194
},
"10.0.0.1": {
"city": "New York",
"country_code": "US"
}
}Configure named log endpoints for your application:
# Log to stdout
fastlike -wasm my-program.wasm -backend localhost:8000 -logger access
# Log to a file
fastlike -wasm my-program.wasm -backend localhost:8000 -logger access=/var/log/access.logSet the compliance region for data locality requirements:
fastlike -wasm my-program.wasm -backend localhost:8000 -compliance-region us-euEnable hot reloading to automatically reload your WASM module when you make changes:
# Start with reload enabled
fastlike -wasm my-program.wasm -backend localhost:8000 -reload
# In another terminal, send SIGHUP to reload
kill -SIGHUP $(pgrep fastlike)
# Or if you know the process ID: kill -SIGHUP <pid>The project includes a Makefile with helpful commands:
# Build the binary
make build
# Run all tests
make test
# Build test WASM programs (for development)
make build-test-wasm
# Run with Make (requires WASM and BACKEND variables)
make run WASM=my-program.wasm BACKEND=localhost:8000
# Run with arguments
make run WASM=my-program.wasm BACKEND=localhost:8000 ARGS='-v 2'For debugging specific requests, add the fastlike-verbose header:
curl -H "fastlike-verbose: 1" http://localhost:5000/This enables verbose logging for just that request.
# Start a simple backend server
python3 -m http.server 8000 &
# Run Fastlike with your WASM program
fastlike -wasm my-program.wasm -backend localhost:8000 -bind localhost:5000
# Test it
curl http://localhost:5000/# Start multiple backend services
python3 -m http.server 8000 & # Static files
node app.js 8080 & # API server
npx serve public/ 9000 & # Another service
# Run Fastlike with multiple backends and stores
fastlike -wasm my-program.wasm \
-backend static=localhost:8000 \
-backend api=localhost:8080 \
-backend images=localhost:9000 \
-config-store config=config.json \
-secret-store secrets=secrets.json \
-kv cache=cache.json \
-acl blocklist=acl.json \
-geo geo.json \
-logger access \
-bind localhost:5000
# Now your WASM program can use all configured backends and stores# Terminal 1: Start Fastlike with hot reload
fastlike -wasm my-program.wasm -backend localhost:8000 -reload
# Terminal 2: Build and reload when changes occur
while inotifywait -e modify my-project/src/*; do
cd my-project && fastly compute build
kill -SIGHUP $(pgrep fastlike)
done
# Terminal 3: Test continuously
watch -n 1 curl -s http://localhost:5000/Enable verbose logging to see all ABI calls:
# Persistent verbose logging
fastlike -wasm my-program.wasm -backend localhost:8000 -v 2
# Per-request verbose logging
curl -H "fastlike-verbose: 1" http://localhost:5000/Support for named backend configurations. Complex backend configurations with timeouts, SSL, and more are available through the Go API but not through the CLI. Reliability simulation (the @N suffix described above) is the one exception, and is exposed on both the CLI and the Go API.
Full HTTP caching support with request collapsing and surrogate key management - all working locally.
Fastlike adds "Fastlike" to the cdn-loop header to prevent infinite request loops. If a loop is detected, it returns a 508 Loop Detected error.
