Guides

Fastly platform guide

Deploying Fastly Compute Safely: Packages, Versions, Backends, and Rollback

A Compute deployment is an edge release and an origin-connectivity change. Make both reproducible, observable, and reversible before they carry production traffic.

Fastly Compute runs application code as WebAssembly at the edge. That makes small request decisions, response composition, and carefully bounded origin calls fast to distribute, but it also means a bad release can affect traffic globally. Treat the Compute package, its Fastly service configuration, and its runtime data stores as separate deployment surfaces with separate controls.

This tutorial is for DevOps and platform engineers operating a Compute service with one or more HTTP origins. It uses the Fastly CLI and control plane terminology current at publication. Confirm account entitlements, product limits, and CLI behavior in the linked Fastly documentation before automating the commands.

Do not turn the edge into an unbounded application tier

Compute is a strong fit for deterministic request handling, cache policy, routing, authentication checks, and short origin fetches. Keep long transactions, authoritative writes, unbounded fan-out, and strict global consistency in systems designed to own that state.

1. Establish the release contract

Start with a narrow contract for each route. Record the accepted methods and body limits; cache key and cacheability; selected backend; outbound headers; timeouts; retry policy; expected response classes; and fallback behavior. Include a release identifier in a response header only for a restricted test domain or authenticated diagnostics route, not as a dependency for clients.

Fastly services have numbered configuration versions. A version can be cloned, validated, activated, and locked; locked versions cannot be edited. Preserve the service ID, active version number, package digest, source revision, and configuration change together in the deployment record. This is the minimum evidence needed to distinguish a package regression from an origin, backend, or data-store change.

Define stop conditions before the rollout: elevated origin 5xx responses, backend timeouts, a changed authorization outcome, a cache-key regression, or a p95/p99 latency increase beyond the route budget. Name the operator who can activate the prior known-good version and the origin team that receives a direct-origin or connection surge alert.

2. Prepare credentials and tooling

Install a pinned, reviewed Fastly CLI version in CI and verify it with fastly version. Authenticate locally with fastly auth login or a CLI profile. In CI, provide FASTLY_API_TOKEN from the CI secret manager rather than committing it, printing it, or placing it in fastly.toml. The CLI documents command flags, environment variables, and local credential storage as authentication options; use a token limited to the service and operations the pipeline actually needs.

The CLI compiles a Compute package locally and uploads the resulting artifact. Install the language toolchain required by the selected starter or SDK, then pin its version in the repository or build image. Build from a clean lockfile-based dependency installation. A changing compiler, transitive dependency, or generated bundle means a package with the same source revision may not be the same release.

For a new project, scaffold a supported starter rather than inventing the manifest:

mkdir edge-router
cd edge-router
fastly compute init

The initializer writes fastly.toml. For JavaScript projects, install the declared dependencies before building. For an existing service, set service_id in the manifest or provide it through the CI environment so the pipeline cannot accidentally create a new production service.

3. Separate package, service configuration, and runtime data

fastly.toml describes how the CLI builds and packages the application and can configure the local server. It is not a place for a production API token or plaintext application secret. Its scripts.build command must produce bin/main.wasm; the CLI packages that artifact for upload.

Keep service configuration under review alongside the package: domains, TLS, static backends, health checks, host override, TLS verification, backend timeouts, connection limits, logging endpoints, and cache policy. The backend API exposes these as configuration fields. In particular, a Compute backend timeout is a connection failure, not a partially successful response, so set a route-level deadline in code that is shorter than the user-facing budget and handle the failure deliberately.

Use the correct edge data store for each runtime value:

  • Config Store: small, non-sensitive, infrequently changed configuration such as a route map or feature default.
  • KV Store: larger, non-sensitive data that needs more frequent updates, with eventual-consistency implications assessed.
  • Secret Store: small sensitive values such as API tokens, signing keys, or passwords.

These stores are versionless: updates take effect without a service-version increment. That is useful operationally but means a data update can change production behavior independently of a package deployment. Give every store an owner, change record, validation rule, and rollback procedure. Do not use a shared cache, Config Store, request headers, or logs to carry a secret.

4. Make backend behavior explicit

A named backend is the origin contract. Specify the hostname or address, port, TLS requirements, certificate and SNI expectations, host override when needed, connect/first-byte/overall timeouts, health check, and concurrency limit. Verify that the origin accepts the resulting Host header and that its certificate matches the configured verification name. Do not disable certificate checks to get a deployment through.

Static backends are configured on the Fastly service. Dynamic backends can be useful for controlled tenant routing, but derive them only from an allowlisted configuration value, never directly from a user-supplied URL or Host header. Otherwise a Compute service can become an SSRF relay. Apply an explicit route-to-backend map and deny unknown routes.

For local development, define a harmless backend substitute and test store data. This belongs in a developer-only manifest or ignored test fixture, not in a production secret file:

manifest_version = 3
name = "edge-router"
language = "javascript"
service_id = "YOUR_NON_PRODUCTION_SERVICE_ID"

[local_server.backends.origin]
url = "http://127.0.0.1:8080"
override_host = "origin.test"
health = "healthy"

[local_server.secret_stores]
test_secrets = { file = "test/fixtures/secrets.json", format = "json" }

Use fake values in test/fixtures/secrets.json, add the file to .gitignore if it can contain developer credentials, and never point a local test at an unprotected production origin. Local Secret Store data is test data; local encryption does not model production Secret Store protection.

5. Test in layers before uploading

Build the exact package CI will deploy:

fastly compute build

The expected artifact is a package archive under pkg/. Record its checksum and build metadata with the source revision. Run language-level unit tests before this command, then exercise HTTP behavior with the Fastly local server:

fastly compute serve --watch
curl -i http://127.0.0.1:7676/health
curl -i -H 'Host: app.test' http://127.0.0.1:7676/products/42

Test success, invalid input, unauthenticated input, a cacheable public response, a private response, a backend 4xx, connection refusal, slow origin, and an unhealthy backend. Assert that secrets, authorization headers, cookies, and internal routing headers are absent from responses and logs.

The local server is valuable but not a production replica. Fastly documents that it has no readthrough HTTP cache, so cache-control behavior and cache hit ratio cannot be proven locally. It also does not transit Fastly routing infrastructure, lacks several connection details and headers, and uses configured or mocked backend health. Test those properties on an isolated Fastly service with a non-production domain before production activation.

6. Deploy to an isolated service and observe it

Deploy first to a separate development or staging service with a non-production origin and domain:

fastly compute deploy --service-id "$FASTLY_SERVICE_ID" --status-check-path /health

The CLI supports a service ID, selected service version, deployment comment, and status-check path and timeout. Require a meaningful health response that checks the route's required dependencies without exposing data. A 200 from a process that cannot reach its required origin is not an adequate release gate.

Use fastly log-tail for short, controlled staging diagnosis. It streams standard output, standard error, and runtime errors, but it is not a production audit log. Configure a real-time logging endpoint for retained production telemetry. Emit structured, bounded-cardinality fields such as:

  • request or trace ID, route template, method, status, and response class
  • package digest or release ID, service version, selected backend, and cache outcome
  • backend latency, timeout or retry reason, and safe failure mode
  • an opaque configuration revision or secret version identifier, never the secret value

Redact Authorization, Cookie, signed URLs, client tokens, request bodies, and sensitive query parameters at the source. Join Fastly events with origin access logs through a request ID or trace context so an alert can show whether the edge, backend connection, or origin application is responsible.

7. Activate deliberately and retain rollback

For production, clone the active service version in the Fastly control panel or through your infrastructure workflow. Apply the intended backend and service changes to that clone, validate it, upload the reviewed package to the intended version, and activate only after the deployment gates pass. Lock the resulting good version so later edits require a new, reviewable version.

Immediately after activation, run synthetic requests from representative regions and compare them with the baseline. Watch edge and origin 5xx rate, backend timeout rate, origin request volume, cache outcomes, p95/p99 latency, and authentication failures. Fastly notes that replacement packages may take up to about a minute to begin handling requests, so keep the observation window longer than propagation and normal cache warming.

Rollback is an activation operation, not a rebuild under pressure:

  1. Keep the previous working package and locked service version identifiable in the release record.
  2. If a stop condition is met, activate that known-good version using the control plane or the approved API automation.
  3. Verify the active version, synthetic checks, origin volume, error rate, and logs after propagation.
  4. Preserve the failed package, version number, correlated logs, and metrics for investigation. Do not edit the failing version in place.

If the incident is caused by a versionless Config, KV, or Secret Store update, activating an earlier service version will not undo it. Use the store-specific rollback procedure, then verify both the data revision and the serving package.

Edge suitability and operational caveats

Choose Compute only where its execution model supports the outcome. Request handlers run in isolated WebAssembly sandboxes by default, and Fastly enforces product resource limits. Keep handler work bounded, set small outbound timeouts, cap retries, and make errors safe. A retry loop from many POPs can amplify a degraded origin.

Do not assume an edge location is an authority for user identity, inventory, balances, payment state, or write ordering. Read state from a designed system of record, expose staleness where it matters, and send long-running work to durable asynchronous processing. Cache only public or correctly isolated data; never cache a response with account data into a shared key.

Also protect the origin independently. Restrict origin ingress to Fastly or private connectivity where possible, authenticate edge-to-origin traffic, and overwrite untrusted forwarding headers at the trust boundary. Compute routing improves delivery control; it is not a substitute for origin network controls, application authorization, or a tested incident response plan.

Release checklist

Before every production activation, confirm the source revision and package checksum are recorded; the service ID and target version are intentional; backends validate TLS and have tested timeouts; runtime stores contain validated data; local and staging tests cover failure paths; retained logs can correlate edge and origin activity; the previous version is known; and the rollback owner and thresholds are on call.

Fastly primary references

Make Fastly edge releases observable and reversible

Optimi can help review Compute deployment boundaries, origin behavior, and release controls without adding unnecessary delivery complexity.

Discuss Fastly delivery operations