Chapter 22: Security, Compliance, and Deployment
How do we meet security and compliance requirements?
Security requirements kill platform choices. An engineering team can build features on any modern platform, but enterprise security (compliance certifications, data residency, audit trails) narrows the options drastically. Assess the controls and agreements for the specific services and data flows the application will use.
This chapter covers decisions that make enterprise adoption possible: how the isolate model shapes your security posture, authentication patterns, compliance constraints, and how to test and control production deployments.
The security model of isolates
Understanding the isolate model's security implications shapes every decision on the platform.
Workers run in V8 isolates, the same technology that keeps browser tabs from reading each other's memory. This has been battle-tested across billions of browser instances daily.
Workers remove the operating-system administration and process access of a traditional server, but an isolate can serve several concurrent requests and be reused for later ones. Its global memory is not cleared at each request boundary. Keep request-specific secrets and user data out of shared globals; isolation between deployed workloads does not separate users served by the same code.
Secrets and bindings reach your code through the environment object. That avoids distributing connection credentials through configuration files, but compromised application code can still use every capability you grant it. Scope bindings and secrets to the Worker's actual responsibilities.
What isolates don't protect
The V8 isolate model protects you from other customers' code, not from your own mistakes. Isolates provide no protection against application vulnerabilities, misconfigured bindings, or accidentally persisting sensitive data to storage services.
Understanding the security model means understanding its boundaries. Isolates separate workloads, but do not address several threat categories that remain your responsibility.
Isolates don't protect against your own code. If your Worker exfiltrates data through legitimate network calls, whether through supply chain compromise, logic bug, or malicious insider code, the isolate model is irrelevant. The code runs with the permissions you've granted.
Isolates don't protect against misconfiguration. Overly permissive CORS headers, bindings that grant production data access from staging environments, secrets accidentally logged: these are architectural failures, not runtime vulnerabilities. The platform can't save you from yourself.
Isolates don't prevent persisting sensitive data inappropriately. Sensitive information written to KV, D1, or Durable Objects persists according to your application's retention policy. Cache authentication tokens in KV without TTLs and those credentials outlive the request that created them.
The isolate model shrinks your attack surface. It doesn't eliminate the need for secure coding practices, careful configuration management, and deliberate data handling. Think of it as defence in depth: the platform provides multiple layers, but you're responsible for others.
Defence in depth: what the platform provides
Cloudflare combines runtime isolation, sandboxing and restrictions on host access to contain untrusted code. These controls reduce the scope of a runtime compromise; they do not make platform vulnerabilities impossible or restrict a compromised application from using its legitimate bindings.
The isolate is one boundary inside another. Cloudflare also sandboxes the runtime process, blocking direct access to the host filesystem and external network. Processes outside that sandbox mediate external access. This helps contain a runtime compromise, while the application's own permitted bindings and outbound calls still need appropriate controls.
Workers also limits timing facilities that can support side-channel attacks. Date.now() and performance.now() advance after I/O rather than measuring CPU execution continuously. This is why timing a synchronous block in production cannot replace local CPU profiling.
For an architectural review, separate three questions: which platform boundary contains the code, which resources its bindings and credentials permit it to reach, and which users the application authorises to perform each operation. Runtime isolation answers only the first. Review Cloudflare's documented security model for the current implementation details rather than making application guarantees depend on a particular sandbox mechanism or patch-time claim.
Authentication at the edge
Rejecting invalid credentials at the edge protects backend capacity as well as reducing unnecessary work. Authentication still requires the same care over token validation, expiry and revocation.
Traditional flow: an invalid request arrives, passes through your load balancer, reaches your application server, triggers a database query to validate credentials, fails validation, and returns an error. You've consumed compute, database connections, and network bandwidth for a request that was never legitimate.
At the edge, that same invalid request hits your Worker, fails JWT validation in microseconds, and returns immediately. No backend resources consumed. No database query executed.
If ten percent of your traffic fails authentication (expired tokens, malformed requests, bot probes), edge validation prevents that ten percent from reaching your backend. For an application serving ten million requests daily, that's one million backend requests eliminated. At typical compute and database connection costs, the savings compounds quickly.
Choosing an authentication strategy
Cloudflare supports multiple authentication patterns, each suited to different scenarios. The choice matters more than implementation details.
Cloudflare Access delegates authentication to an identity provider and issues an application token. Your Worker must validate the Cf-Access-Jwt-Assertion token, including its signature, issuer, audience and expiry, before trusting identity claims. Protect every route that can reach the application so an alternative hostname cannot bypass Access. Access handles the identity-provider integration; your application still decides what the authenticated user may do.
The architectural benefit is separation of concerns. Access handles the complexity of SAML, OIDC, and identity provider quirks. You avoid reimplementing federated authentication, which is notoriously easy to get subtly wrong.
Access excels when you have existing identity infrastructure, when you're protecting internal tools or employee-facing applications, or when compliance requires audit trails tied to corporate identity. Less suited to consumer applications where users don't have accounts in your identity provider.
Custom JWT validation makes sense when building consumer applications with your own user database, when you need fine-grained claims beyond basic identity, or when building API-first services where federated identity doesn't fit. You control token format, claims structure, and validation logic. The tradeoff: you handle token issuance, refresh flows, and revocation.
JWT validation at the edge is straightforward; libraries handle the cryptography. The architectural decisions matter more than the code. What claims do you need? How long should tokens live? How do you handle refresh? These questions have the same answers anywhere; edge location doesn't change token design principles.
API keys suit service-to-service communication where simplicity outweighs sophistication. Generate a random key, hash it for storage, validate on each request. API keys work well for tracking usage by client, building developer APIs with usage tiers, or when the calling service can securely store credentials.
The decision framework:
| Scenario | Recommended Approach |
|---|---|
| Internal tools, employee access | Cloudflare Access |
| Consumer application, own user database | Custom JWT |
| B2B SaaS with SSO requirements | Cloudflare Access or SAML integration |
| Public API with developer keys | API keys with rate limiting |
| Service-to-service, high trust | API keys or mutual TLS |
| Mixed: employees and external users | Access for employees, JWT for external |
Where session state lives
Choose session storage by the state it must preserve and the decisions it must enforce. A session might be a token with metadata (KV), queryable user state (D1), or a coordination point across concurrent requests (Durable Objects).
KV suits session metadata only when delayed visibility and revocation are acceptable. Cached values, including cached misses, can remain stale across locations; the risk is not limited to users changing continents. Keep token lifetimes and revocation requirements explicit before using an eventually consistent session store.
The limitation is query capability. You cannot ask KV "find all sessions for user X" or "count active sessions." For single-session policies or displaying active sessions to users, KV's key-value model doesn't help.
D1 suits session data requiring relational queries, such as listing or revoking a user's sessions. Reads go to the primary unless the application uses read replication through the Sessions API. For decisions requiring current revocation state, choose the read path deliberately: asynchronous replicas do not become globally current merely because a write succeeded.
Durable Objects suit sessions that coordinate connections or concurrent actions. An object provides a place to serialise decisions for one session or user. Event handlers can interleave at asynchronous boundaries, so the application must still use the storage and concurrency guarantees correctly.
Choose from the session’s responsibilities: KV for metadata whose stale visibility is acceptable, D1 for queryable records and transactional changes, or Durable Objects for active coordination. Identity proof and current permission remain separate checks whichever store you choose.
Secrets management
Wrangler secrets are secure; the real question is whether you need capabilities that static secrets cannot provide, such as rotation auditing, dynamic generation, or cross-platform consistency.
Wrangler secrets: simple and usually sufficient
Wrangler secrets are encrypted at rest and made available to the Worker at runtime without putting their values in the checked-in configuration. Application code can still expose them through logs, responses or outbound requests. Treat access to the secret and authority to deploy that code as access to the protected resource.
The limitation: Wrangler secrets are static. Changing a secret requires redeployment. For most applications, this is irrelevant; you change secrets rarely, and redeployment takes seconds.
Most teams should start with Wrangler secrets. Simple, secure, sufficient for the vast majority of applications. The complexity of external secrets managers is justified only when you have specific requirements static secrets can't meet.
When a shared secrets service matters
Choose a secrets service when the requirement exceeds static application secrets: short-lived credentials generated on demand, centrally governed rotation, evidence of secret access, or one source of truth across several platforms.
Compare those capabilities with the service's access controls, availability and cache behaviour. Fetching a secret on every request can add a dependency to the critical path; caching it changes how quickly rotation and revocation take effect. Define those windows explicitly.
Compliance labels or company size do not decide the architecture. Identify the required control and evidence, then select a service that supplies them. Keep the simpler arrangement when it meets the requirement.
Rotation without downtime
When secrets must rotate without interrupting service, support overlapping validity by keeping both old and new keys valid during the transition. Your validation logic accepts either key, allowing you to set the new key, deploy with both valid, wait for all clients to update, and finally remove the old key.
This dual-key period prevents rotation from causing failures. The pattern is simple but requires designing for it from the start; retrofitting dual-key support onto a system assuming single keys is substantially more work than building it in initially.
Scannable Cloudflare API tokens
Scannable token formats and secret scanning help detect exposed credentials. Treat detection as a recovery aid: keep tokens narrowly scoped, restrict where they are stored and rotate them after suspected exposure.
Scope deployment authority to the Worker
Workers permissions separate investigation, code review, deployment, and deletion. Metadata Read-Only permits settings and observability access without code access; Content Read-Only includes code inspection; Editor permits updates and deployments; Admin adds deletion. Apply these roles to individual Workers for teammates, agents, and CI tokens. Durable Objects inherit the permissions of the Worker that implements them.
Give a deployment pipeline Editor access to the Workers it owns rather than account-wide administration. Keep lifecycle management separate when the pipeline does not need to delete resources. Read-only investigation roles can reduce an agent's authority, but logs and traces may still contain sensitive application data.
Deployment authority also carries indirect data access. An Editor can deploy code using the Worker's existing KV, D1, and R2 bindings without separate direct permissions on those resources. Scoping a token to one Worker limits which code it can change; it does not prevent that code from accessing production data already bound to the Worker. Review deployment permissions and resource bindings together.
Compliance as architecture
Compliance certifications prove Cloudflare's infrastructure meets standards, but your architecture determines whether your use of that infrastructure meets standards. The platform is eligible; you make it compliant.
Cloudflare maintains SOC 2 Type II, ISO 27001, GDPR compliance documentation, HIPAA eligibility with Business Associate Agreements, and PCI DSS compliance. Your account team can provide attestation documents for procurement.
What matters more: understanding how compliance requirements translate into architectural decisions. Listing certifications doesn't help you build compliant systems.
GDPR: design for deletion
GDPR grants data subjects specific rights. The architectural challenge: these rights assume you can find all data about a person, and most systems aren't designed for that.
The right to deletion sounds simple until you've spread user data across D1 tables, R2 objects, KV entries, and Durable Object storage. GDPR doesn't care about your storage architecture. It cares whether you can find and delete everything.
Design your data model around a consistent user identifier that appears everywhere. When a deletion request arrives, you need a tractable query ("find everything with user_id X"), not an archaeological expedition through heterogeneous storage systems. D1 foreign keys help within a database, but deletion across D1, R2, and KV requires application logic you must design intentionally.
The right to access means users can request all data you hold. Same architectural principle: if you cannot enumerate all storage locations for a user, you cannot fulfil access requests accurately.
Data minimisation is an architectural philosophy, not a technical control. Before storing something, ask whether you actually need it. Cloudflare's storage makes keeping data easy and cheap; compliance requires discipline about what to keep. Data you don't store is data you don't need to protect, export, or delete.
Data residency: performance tradeoffs
Jurisdictional restrictions that keep data in specific regions carry consequences beyond compliance checkboxes.
Restricting a Durable Object to the EU means that object only runs in EU data centres. Users in Asia experience intercontinental round-trips: hundreds of milliseconds instead of tens. Compliance and performance are often in tension; architecture is deciding where that tension resolves.
When restricting Durable Objects to a jurisdiction, think about who accesses the data. EU data accessed only by EU users? The restriction costs nothing. Global users accessing EU-restricted data? You're adding hundreds of milliseconds to every interaction.
The same logic applies to the other jurisdictions Durable Objects support. Alongside eu, you can pin an object to us (compute and storage held inside the United States) or fedramp (FedRAMP-authorised facilities). Keeping an object within the US may align with its users, but does not eliminate network latency or service charges. A jurisdiction restriction can place some callers farther from the object's authority. Pick the jurisdiction your obligations actually require, not the broadest one available.
The decision framework for jurisdictional restrictions:
| Data Type | Restriction Typically Needed? | Performance Impact |
|---|---|---|
| Personal data covered by GDPR | Assess transfer rules and contractual commitments; EU-only storage is not a blanket GDPR requirement | Depends on where authorised users and dependencies are located |
| US data under a residency clause | Yes, if contractually required | Acceptable; users are in the US |
| Financial records for EU entity | Depends on regulations | Acceptable; transactions are not latency-critical |
| Real-time game state | Rarely | Severe; latency matters |
| User preferences | Assess what the preferences reveal and the applicable commitments | Depends on the chosen storage location |
Distinguish D1 location hints from jurisdiction restrictions. A hint guides placement without guaranteeing it. A jurisdiction restriction constrains the database's compute and storage, including read replicas, to that jurisdiction. It does not itself constrain where the calling Worker executes.
Data localization suite: enterprise controls
For enterprises with stringent data sovereignty requirements, Cloudflare offers the Data Localization Suite as an Enterprise add-on. The suite provides three independent controls that layer together depending on your compliance needs.
Regional Services controls where TLS termination and request processing occur. When you configure a hostname for EU Regional Services, requests from anywhere in the world route to EU data centres before decryption. A user in Singapore connecting to your EU-regionalised hostname experiences their traffic routed across the globe to Europe before Cloudflare decrypts and processes it. Layer 3/4 DDoS mitigation still happens globally, but all application-layer processing (WAF, Workers, caching) occurs only within your specified region.
Geo Key Manager controls where your TLS private keys are stored. By default, Cloudflare distributes encrypted keys to all data centres for local TLS termination. With Geo Key Manager, keys stay within specified regions. Data centres outside those regions must request session keys from key-holding data centres, adding latency to connection establishment. This latency only affects the initial TLS handshake; subsequent requests and session resumption don't require key server access. The trade-off is meaningful: a user in Asia connecting to a site with EU-only keys pays an intercontinental round-trip on first connection.
Customer Metadata Boundary controls where your logs and analytics are stored. With CMB configured for EU, all request metadata stays in EU infrastructure. The consequence: dashboard analytics and some API endpoints won't work when accessed from outside your configured region unless you enable out-of-region access (which allows viewing but keeps storage localised).
These controls are independent. You might use Regional Services without Geo Key Manager, or Geo Key Manager without Customer Metadata Boundary. Each adds compliance capability at a cost: Regional Services adds latency for non-regional users; Geo Key Manager adds connection establishment latency; Customer Metadata Boundary restricts analytics access. Understand each trade-off before enabling.
A boundary outside the managed region list may call for a custom region arranged through the account team. Check the ingress design before relying on it: custom regions support Regionalized Spectrum Applications and Regionalized IP Bindings, but do not support Regional Hostnames. The required geography can therefore change how traffic reaches the application.
The available jurisdictions and compatible products differ among these controls. Check their intersection for the application's actual hostnames, storage, logs and dependency calls before making a residency commitment. A control over one stage of a request does not establish the location of every later data flow.
HIPAA: eligibility is not compliance
Cloudflare's SOC 2 certification or HIPAA BAA covers their infrastructure, not your application. You remain responsible for access controls, audit logging, data handling, and all other application-level compliance requirements.
HIPAA requires a Business Associate Agreement before storing protected health information. Cloudflare offers BAAs for enterprise accounts. But a BAA doesn't make your application HIPAA-compliant; it makes Cloudflare's infrastructure eligible for use in a compliant application.
Your architecture must still implement access controls, audit logging, appropriate encryption and minimum necessary access. Confirm that the agreement covers the specific Cloudflare services and data flows you intend to use; eligibility for one service does not establish eligibility for the whole architecture.
A BAA is one prerequisite. The remaining work is to map the application's data flows and controls to the obligations, including logging, support access, retention and deletion.
PCI: scope reduction is the strategy
The strongest PCI strategy is scope reduction: don't handle cardholder data at all. Use payment processors (Stripe, Adyen, Braintree) that tokenise card data before it reaches your systems. Your Workers process tokens, not card numbers. Tokens aren't cardholder data, so PCI scope shrinks dramatically.
If you must handle card data directly, requirements escalate significantly: encryption in transit, encryption at rest, access logging, key rotation, vulnerability management, penetration testing, and more. Cloudflare's infrastructure provides some of these controls, but you're responsible for application-level implementation.
Most applications should avoid this complexity through tokenisation. The payment processor handles PCI compliance for card handling; you handle PCI compliance for everything else, a much smaller surface area.
What compliance can't easily achieve
Some requirements depend on controls the selected Cloudflare service does not expose. Identify those gaps before committing to the deployment.
Cross-region audit logging requires intentional design. Logs from Workers don't automatically aggregate into a central, tamper-proof audit store. For comprehensive audit trails, build the aggregation and ship logs to a centralised system via Logpush or application-level logging.
Fine-grained access control within a Worker is your responsibility. If multiple teams share a Worker and compliance requires tracking which team accessed which data, that's application logic you implement, not platform capability you configure.
Infrastructure you control is required by some compliance frameworks. Edge compute is, by definition, someone else's infrastructure. If compliance mandates that all processing occur on hardware you own, serverless platforms (Cloudflare included) don't fit.
Deployment as hypothesis testing
A deployment without predefined success criteria isn't a gradual rollout; it's a gradual hope that drifts until reality intrudes. Define what "working" means before you deploy, or you'll discover what "broken" means from your users.
Code rollback and state rollback
Workers versions let a deployment route traffic to retained code versions and change their allocation without rebuilding the application. This makes gradual exposure and code rollback practical parts of normal deployment.
The previous version's existence does not reverse writes, schema changes or calls to external systems. Before rolling back, check that the older code can read the current data and tolerate work started by the newer version. Use compatible schema changes and versioned messages when old and new code will coexist.
Defining success criteria
Before deploying, establish measurable criteria. Write these down before you deploy, not while staring at ambiguous metrics trying to decide whether the deployment succeeded.
Error rate threshold: "Error rate must not increase by more than 0.1% compared to the previous version." Be specific about what counts as an error: 5xx responses only, or also 4xx that indicate bugs? Over what time window: instantaneous, or averaged over five minutes?
Latency threshold: "P99 latency must remain below 200ms." Choose the percentile that matters for your application. P50 hides tail latency issues that affect your most complex requests or unluckiest users. P99 or P99.9 reveals them.
Business metrics: "Conversion rate must not decrease." "API success rate must stay above 99.9%." Connect deployment health to outcomes that matter. A deployment passing technical metrics but tanking business metrics isn't successful.
No new error types: "No error messages appearing that were not present in the previous version." New errors often indicate new bugs. This criterion catches issues that might not increase error rate significantly but indicate problems.
Exposure, observation and rollback
Choose the first allocation by the harm a defect could cause and the traffic needed to observe it. A small percentage of a high-volume API can give useful evidence quickly; the same percentage on a low-volume system may miss the relevant paths entirely.
Keep each stage long enough to exercise meaningful behaviour: concurrent writes, scheduled jobs, a traffic peak or a complete business process. Request counts alone do not expose time-dependent failures.
Define rollback triggers before deployment using the baseline and the change's risks. Compare new and old versions where possible, including correctness and business outcomes as well as error rate and latency. A normal background 5xx in the first hundred requests is not automatically evidence against the release, while one incorrect payment can justify immediate intervention.
When a trigger fires, use the prepared recovery path. Confirm code and data compatibility before routing back, and escalate when recovery needs more than a code version change.
Environment progression
Maintain separate environments: development, staging, production. Deploy to staging first. Run automated tests against staging. Verify manually. Only then deploy to production with gradual rollout.
The binding model makes environment separation clean. Staging and production Workers are identical artifacts with different bindings. Staging points to staging databases, staging KV namespaces, staging Durable Object namespaces. Production points to production resources.
What should differ between environments? Data sources must differ; you don't want staging tests modifying production data. Code paths should not differ. Avoid conditional logic based on environment that means staging doesn't test production behaviour.
Feature flags provide safer conditional behaviour than environment checks. A feature flag tested in staging behaves identically in production; an environment check by definition behaves differently. Need to disable a feature in production that's enabled in staging? Use a feature flag, not environment detection.
Automated deployment with Workers builds
Manual deployments work for side projects. Production systems need automation: code changes trigger builds, tests run, deployments happen consistently regardless of which engineer pushed the commit.
Workers Builds is Cloudflare's native CI/CD system. Connect a repository from a supported Git provider, configure build settings, and every push to your production branch automatically deploys. No external CI system required, no deployment scripts to maintain, no credentials to manage.
Connecting a repository
Workers Builds can connect a repository to build and deploy on changes. Define which branch reaches production, which checks must pass, and which identity may deploy. Keep build and deployment commands in the project's operating documentation.
Pin tooling through the dependency and lockfile policy so local validation and CI use the same version. Worker Previews require Wrangler 4.135.0 or later.
Preview URLs for every branch
Worker Previews give each branch its own deployed code, configuration, state boundary, and observability under the same Worker. Preview URLs are public by default; use Cloudflare Access when review requires authentication. Stable branch URLs let reviewers follow a change across pushes, while immutable deployment URLs identify the exact version tested. Workers Builds can create these environments as part of pull-request review.
A version-specific URL identifies code; a Preview also separates its configuration and its own Durable Object and Container state. Account-level storage such as KV, D1, and R2 still needs separate resources, and calls to other Workers can reach their production deployments. Chapter 5 covers the resource and trigger limits. Require an explicit review of bindings before treating a Preview as safe for tests that mutate data.
Use Previews for parallel review of individual changes and staging for coordinated integration tests. Neither replaces a gradual production rollout: realistic execution helps find defects, while controlled traffic exposure limits the cost of defects that escape.
Monorepo support
Organisations with multiple Workers in a single repository need fine-grained control over which Workers rebuild when code changes.
Connect each Worker to the same repository and set its build working directory, such as services/api/ or services/auth/, in Settings → Builds → Root directory. This selects where the build runs; it does not by itself restrict which file changes trigger it.
Build watch paths provide additional control. By default, any file change triggers a build. Configure include and exclude patterns to specify which paths trigger rebuilds:
Include paths: services/api/*, shared/utils/*
Exclude paths: *.md, *.test.ts
A change to services/api/handler.ts triggers the API Worker build. A change to services/auth/config.ts doesn't. A change to shared/utils/helpers.ts triggers both if both include it in their watch paths. For monorepos with many Workers, this prevents unnecessary builds and keeps deployment times predictable.
When to use external CI/CD instead
Workers Builds covers most deployment needs but doesn't fit every situation.
Self-hosted Git isn't supported. If your repository lives on self-hosted GitHub Enterprise or GitLab, use external CI/CD with Wrangler commands.
Complex testing requirements may need more than Workers Builds provides. If deployment depends on integration tests against staging databases, security scans, or approval workflows, orchestrate those in GitHub Actions or your existing CI platform, then call wrangler deploy at the end.
Multi-service coordination may need external orchestration to sequence migrations and deployments. A CI runner does not make those calls atomic. Use compatible intermediate states, repeatable steps and an explicit recovery procedure; where a serving change must be indivisible, establish the transaction or routing boundary that supplies that property.
The decision: if your deployment is "build, maybe run tests, deploy Worker," Workers Builds handles it with minimal configuration. Complex orchestration? External CI/CD provides the flexibility you need.
Private network connectivity
Some backends aren't publicly accessible. Your application needs data from a database inside a VPC, an internal API behind a firewall, a legacy system that cannot be exposed to the internet. Workers VPC provides secure connectivity through Cloudflare Tunnel with bindings that restrict which private services the Worker can reach.
Cloudflare tunnel: the foundation
Cloudflare Tunnel creates an outbound-only connection from your private network to Cloudflare's edge. Install cloudflared on a server inside your network; it establishes a connection to Cloudflare; Workers route requests through that tunnel to your internal resources.
The security model is compelling: no inbound ports opened, no public IP addresses exposed, no firewall rules to maintain. The tunnel initiates from inside your network. If the tunnel process stops, connectivity stops; no dormant attack surface waiting to be exploited.
For production deployments, run at least two cloudflared replicas on separate hosts for redundancy. Each host should have minimum 4 GB RAM and 4 CPU cores. The tunnel maintains persistent connections to Cloudflare, eliminating the need for complex firewall configurations.
VPC services: the binding layer
Workers VPC is currently in beta. Features and APIs may change before general availability. While in beta, Workers VPC is available for free to all Workers plans.
VPC Services build on Tunnels to provide a binding-based access model. Rather than giving Workers broad access to everything reachable through a tunnel, you create VPC Services representing specific endpoints, then bind those services to Workers.
{
"vpc_services": [
{
"binding": "PRIVATE_API",
"service_id": "your-vpc-service-id"
}
]
}
Replace the service ID with your configured VPC Service ID. The binding selects that configured destination; the URL host and port do not select another internal service:
const response = await env.PRIVATE_API.fetch(
"http://internal-api.company.local/users"
);
A VPC Service binding restricts the configured destination, reducing the opportunity to pivot to arbitrary internal hosts through that capability. It does not validate attacker-controlled paths or arguments at an allowed service, and other available network paths still need review. Enforce the permitted operation as well as the destination.
VPC Services also enable role-based access control. The Connectivity Directory Admin role creates and manages services; the Connectivity Directory Bind role allows developers to use existing services without the ability to create new ones. This separation matters in larger organisations where infrastructure teams control what's exposed while application teams consume those services.
The limit is 1,000 VPC Services per account. Each service represents one endpoint in your private network; you can bind multiple Workers to the same service.
Cloudflare Mesh and cf1:network bindings
For organisations whose private resources are not behind a single tunnel but spread across personal devices, remote servers, and multiple cloud VPCs, Cloudflare Mesh provides a connector-based private network that routes through Cloudflare's edge. A lightweight Cloudflare One Client on each node creates many-to-many private connectivity over private IPs, with Gateway, DNS filtering, device posture, and DLP applied automatically because Mesh inherits the Cloudflare One stack. Every Cloudflare account gets 50 nodes and 50 users free.
A cf1:network binding lets a Worker reach hosts across a Mesh network without registering each as an individual service. That broader reach changes the security decision: an endpoint binding limits destinations by construction, while a network binding requires appropriate network policy and application destination controls. For agents, derive the permitted destination from trusted configuration rather than accepting an arbitrary host supplied by a user or model.
The hybrid edge pattern
Workers become particularly valuable as a global edge layer connecting multiple backend clouds. Your organisation might have databases in AWS, APIs in GCP, and legacy systems on-premises. Workers provide a unified global entry point routing to the appropriate backend based on request type.
A single edge layer means consistent authentication, logging, and rate limiting across all backends. Backend distance, query time and availability still affect each request; consistent ingress policy does not imply consistent latency.
The architectural insight: Workers aren't just a compute platform; they're a global routing layer that happens to execute code. Use that capability to unify fragmented backends into a coherent experience.
Security practices at the edge
A few security practices deserve explicit mention, not because they're Cloudflare-specific, but because the edge model affects implementation.
Rate limiting
Distributed rate limiting is hard. Traditional approaches use centralised counters (Redis, typically), but centralised anything adds latency at the edge.
For approximate abuse controls, consider the platform's local rate limiting facilities and the scope in which their counters operate. KV is unsuitable for a precise counter: propagation delay and non-atomic read-modify-write operations can lose increments, with no general 5–10% bound on the error. Chapter 24 distinguishes local limits from strict global quotas.
A Durable Object can own a strict rate limit for one user or quota key. Keep the check and state update atomic; single-threaded JavaScript alone does not prevent interleaving around asynchronous work. Every admission decision adds a call to the object, so measure its latency from the relevant user locations.
Choose based on precision requirements. Approximate limits protect against abuse while being cheap and fast. Exact limits enforce contractual quotas or prevent resource exhaustion where every request over the limit costs real money.
Input validation
Validate inputs at the edge, before they propagate to backends. Invalid inputs rejected at the edge never consume backend resources.
Use structured validation libraries rather than ad-hoc checks. TypeScript's type system helps at compile time; runtime validation with libraries like Zod catches what types can't express. The combination catches most input errors before they cause problems.
Dependency minimisation
Workers restrict host access, child processes, and operating-system APIs, reducing the attack surface compared with a traditional server. Maintain that advantage by minimising dependencies.
Every npm package is code you haven't reviewed executing in your security context. Supply chain attacks happen with uncomfortable regularity. Prefer standard APIs over utility libraries. When dependencies are necessary, prefer well-maintained packages with security track records. Audit regularly.
Workers do not expose the host filesystem or permit arbitrary child processes. Their virtual filesystem can still contain sensitive bundled or temporary data, and application code can send that data over permitted network calls. Restricted system access reduces the attack surface; careful data handling remains your responsibility.
What comes next
Security controls define who may act; recovery must preserve those decisions when state is damaged or restored. Chapter 23 follows accepted work through partial failure, reconciliation and the return to safe service.