
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/">
    <channel>
        <title><![CDATA[ The Cloudflare Blog ]]></title>
        <description><![CDATA[ Get the latest news on how products at Cloudflare are built, technologies used, and join the teams helping to build a better Internet. ]]></description>
        <link>https://blog.cloudflare.com</link>
        <atom:link href="https://blog.cloudflare.com/" rel="self" type="application/rss+xml"/>
        <language>en-us</language>
        <image>
            <url>https://blog.cloudflare.com/favicon.png</url>
            <title>The Cloudflare Blog</title>
            <link>https://blog.cloudflare.com</link>
        </image>
        <lastBuildDate>Wed, 15 Apr 2026 04:47:08 GMT</lastBuildDate>
        <item>
            <title><![CDATA[Serverless Statusphere: a walk through building serverless ATProto applications on Cloudflare’s Developer Platform]]></title>
            <link>https://blog.cloudflare.com/serverless-atproto/</link>
            <pubDate>Thu, 24 Jul 2025 13:00:00 GMT</pubDate>
            <description><![CDATA[ Build and deploy real-time, decentralized Authenticated Transfer Protocol (ATProto) apps on Cloudflare Workers. ]]></description>
            <content:encoded><![CDATA[ <p></p><p>Social media users are tired of losing their identity and data every time a platform shuts down or pivots. In the ATProto ecosystem — short for <a href="https://atproto.com/"><u>Authenticated Transfer Protocol</u></a> — users own their data and identities. Everything they publish becomes part of a global, cryptographically signed shared social web. <a href="https://bsky.social/"><u>Bluesky</u></a> is the first big example, but a new wave of decentralized social networks is just beginning. In this post I’ll show you how to get started, by building and deploying a fully serverless ATProto application on Cloudflare’s Developer Platform.</p><p>Why <a href="https://www.cloudflare.com/learning/serverless/what-is-serverless/"><u>serverless</u></a>? The overhead of managing VMs, scaling databases, maintaining CI pipelines, distributing data across availability zones, and <a href="https://www.cloudflare.com/learning/security/api/what-is-api-security/"><u>securing APIs</u></a> against DDoS attacks pulls focus away from actually building.</p><p>That’s where Cloudflare comes in. You can take advantage of our <a href="https://www.cloudflare.com/developer-platform/"><u>Developer Platform</u></a> to build applications that run on our global network: <a href="https://workers.cloudflare.com/"><u>Workers</u></a> deploy code globally in milliseconds, <a href="https://developers.cloudflare.com/kv/"><u>KV</u></a> provides fast, globally distributed caching, <a href="https://developers.cloudflare.com/d1/"><u>D1</u></a> offers a <a href="https://www.cloudflare.com/developer-platform/products/d1/">distributed relational database</a>, and <a href="https://developers.cloudflare.com/durable-objects/"><u>Durable Objects</u></a> manage WebSockets and handle real-time coordination. Best of all, everything you need to build your serverless ATProto application is available on our free tier, so you can get started without spending a cent. You can find the code <a href="https://github.com/inanna-malick/statusphere-serverless/tree/main"><u>in this GitHub repo</u></a>.</p>
    <div>
      <h2>The ATProto ecosystem: a quick introduction</h2>
      <a href="#the-atproto-ecosystem-a-quick-introduction">
        
      </a>
    </div>
    <p>Let’s start with a conceptual overview of how data flows in the ATProto ecosystem:</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3mYzoDzLeNyAMxvPmTPg89/ef5fe2ec7fad881b1508afa58779e5db/image1.png" />
          </figure><p>Users interact with apps, which write updates to their personal <a href="https://atproto.com/specs/repository"><u>repositories</u></a>. Those updates trigger change events, which are published to a relay and broadcast through the global event stream. Any app can subscribe to these events — even if it didn’t publish the original update — because in ATProto, repos, relays, and apps are all independent components, which can be (and are) run by different operators.</p>
    <div>
      <h3>Identity</h3>
      <a href="#identity">
        
      </a>
    </div>
    <p>User identity starts with <a href="https://atproto.com/specs/handle"><u>handles</u></a> — human-readable names like <code>alice.example.com</code>. Each handle must be a valid domain name, allowing the protocol to leverage DNS to provide a global view of who owns what account. Handles map to a user’s <a href="https://atproto.com/specs/did"><u>Decentralized Identifier (DID)</u></a>, which contains the location of the user’s <a href="https://atproto.com/specs/account"><u>Personal Data Server (PDS)</u></a>.</p>
    <div>
      <h3>Authentication</h3>
      <a href="#authentication">
        
      </a>
    </div>
    <p>A user’s PDS manages their keys and repos. It handles authentication and provides an authoritative view of their data via their repo.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6axi6BOY6UxOaEixRewhUD/dacb070e6b511869d20407bb10006bf6/image3.png" />
          </figure><p>If you’d like to learn more, there’s a great article here: <a href="https://atproto.com/articles/atproto-for-distsys-engineers"><u>ATProto for distributed systems engineers</u></a>.</p><p>What’s different here — and easy to miss — is how little any part of this stack relies on trust in a single service. DID resolution is verifiable. The PDS is user-selected. The client app is just an interface.</p><p>When we publish or fetch data, it’s signed and self-validating. That means any other app can consume or build on top of it without asking permission, and without trusting our backend.</p>
    <div>
      <h2>Our application</h2>
      <a href="#our-application">
        
      </a>
    </div>
    
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7A4k84VxHgUYIRZ1I6bH0e/6b8c407579960be9e7bba9bec21776dd/image2.png" />
          </figure><p>We’ll be working with <a href="https://atproto.com/guides/applications"><b><u>Statusphere</u></b></a>, a tiny but complete demo app built by the ATProto team. It’s the simplest possible social media app: users post single-emoji status updates. Because it’s so minimal, Statusphere is a perfect starting point for learning how decentralized ATProto apps work, and how to adapt them to run on Cloudflare’s serverless stack.</p>
    <div>
      <h3>Statusphere schema</h3>
      <a href="#statusphere-schema">
        
      </a>
    </div>
    <p>In ATProto, all repository data is typed using <a href="https://atproto.com/specs/lexicon"><b><u>Lexicons</u></b></a> — a shared schema language similar to <a href="https://json-schema.org/"><u>JSON-Schema</u></a>. For Statusphere, we use the <code>xyz.statusphere.status</code> record, originally defined by the ATProto team:</p>
            <pre><code>{
  "type": "record",
  "key": "tid", # timestamp-based id
  "record": {
    "type": "object",
    "required": ["status", "createdAt"],
    "properties": {
      "status": { "type": "string", "maxGraphemes": 1 },
      "createdAt": { "type": "string", "format": "datetime" }
    }
  }
}</code></pre>
            <p>Lexicons are strongly typed, which allows for easy interoperability between apps. </p>
    <div>
      <h2>How it's built</h2>
      <a href="#how-its-built">
        
      </a>
    </div>
    <p>In this section, we’ll follow the flow of data inside Statusphere: from authentication, to repo reads and writes, to real-time updates, and look at how we handle live event streams on serverless infrastructure.</p>
    <div>
      <h3>1. Language choice</h3>
      <a href="#1-language-choice">
        
      </a>
    </div>
    <p>ATProto’s core libraries are written in TypeScript, and Cloudflare Workers provide first-class TypeScript support. It’s the natural starting point for building ATProto services on Cloudflare Workers.</p><p>However, the ATProto TypeScript libraries assume a <a href="https://www.npmjs.com/package/@atproto/oauth-client-node"><u>backend</u></a> or <a href="https://www.npmjs.com/package/@atproto/oauth-client-browser"><u>browser</u></a> context. Cloudflare Workers support using <a href="https://developers.cloudflare.com/workers/runtime-apis/nodejs/"><u>Node.js APIs in a serverless context</u></a>, but the ATProto library’s <a href="https://github.com/bluesky-social/atproto/blob/f476003709d43b5e2474218cd48a9e1d7ebf3089/packages/internal/did-resolver/src/methods/plc.ts#L51"><u>use</u></a> of the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Request/redirect"><u>‘error’ redirect handling mode</u></a> isn’t compatible with the edge runtime.</p><p>Cloudflare also supports Rust in Workers via <a href="https://developers.cloudflare.com/workers/runtime-apis/webassembly/"><u>WASM cross-compilation</u></a>, so I tried that next. The <a href="https://github.com/atrium-rs/atrium"><u>ATProto Rust crates</u></a> and codegen tooling make strong use of Rust’s type system and build tooling, but they’re still in active development. Rust’s WASM ecosystem is solid, though, so I was able to get a working prototype running quickly by adapting <a href="https://github.com/fatfingers23/rusty_statusphere_example_app"><u>an existing Rust implementation of Statusphere</u></a> — originally written by Bailey Townsend. You can find the code <a href="https://github.com/inanna-malick/statusphere-serverless/tree/main"><u>in this GitHub repo</u></a>.</p><p>If you're building ATProto apps on Cloudflare Workers, I’d suggest contributing to the TypeScript libraries to better support serverless runtimes. A TypeScript version of this app would be a great next step — if you’re interested in building it, please get in touch via the <a href="https://discord.com/invite/cloudflaredev"><u>Cloudflare Developer Discord server</u></a>.</p>
    <div>
      <h3>2. Follow along</h3>
      <a href="#2-follow-along">
        
      </a>
    </div>
    <p>Use this Deploy to Cloudflare button to clone the repo and set up your own KV and D1 instances and a CI pipeline.</p><a href="https://deploy.workers.cloudflare.com/?url=https%3A%2F%2Fgithub.com%2Finanna-malick%2Fstatusphere-serverless%2Ftree%2Fmain%2Fworker"><img src="https://deploy.workers.cloudflare.com/button" /></a>
<p></p><p>Follow the steps at this link, use the default values or choose custom names, and it’ll build and deploy your own Statusphere Worker.</p><p><b>Note: this project includes a scheduled component that reads from the public event stream. You may wish to delete it when you finish experimenting to save resources.</b></p>
    <div>
      <h3>3. Resolving the user’s handle</h3>
      <a href="#3-resolving-the-users-handle">
        
      </a>
    </div>
    <p>To interact with a user's data, we start by resolving their handle to a DID using the record registered at the _atproto subdomain. For example, my handle is <code>inanna.recursion.wtf</code>, so my DID record is stored at <a href="https://digwebinterface.com/?hostnames=_atproto.inanna.recursion.wtf&amp;type=TXT&amp;ns=resolver&amp;useresolver=1.1.1.1&amp;nameservers="><code><u>_atproto.inanna.recursion.wtf</u></code></a>. The value of that record is <code>did:plc:p2sm7vlwgcbbdjpfy6qajd4g</code>. </p><p>We then resolve the DID to its corresponding <a href="https://atproto.com/specs/did#did-documents"><u>DID Document</u></a>, which contains identity metadata including the location of the user’s Personal Data Server. Depending on the DID method, this resolution is handled directly via DNS (for <code>did:web</code> identifiers) or, more frequently, via the <a href="https://github.com/did-method-plc/did-method-plc"><u>Public Ledger of Credentials</u></a> for <code>did:plc</code> identifiers.</p><p>Since these values don’t change frequently, we cache them using <a href="https://developers.cloudflare.com/kv/"><u>Cloudflare KV</u></a> — it’s perfect for cases like this, where we have some infrequently updated but frequently read key-value mapping that needs to be globally available with low latency.</p><p>From the DID document, we extract the location of the user’s Personal Data Server. In my case, it’s <code>bsky.social</code>, but other users may self-host their own PDS or use an alternative provider.</p><p>The details of the OAuth flow aren’t important here — you can <a href="https://github.com/inanna-malick/statusphere-serverless/blob/main/worker/src/services/oauth.rs"><u>read the code</u></a> I used to implement it or <a href="https://datatracker.ietf.org/doc/html/rfc6749"><u>dig into the OAuth spec</u></a> if you're curious — but the short version is: the user signs in via their PDS, and it grants our app permission to act on their behalf, using the signing keys it manages.</p><p>We persist session data in a secure session cookie using <a href="https://docs.rs/tower-sessions/latest/tower_sessions/#implementation"><u>tower-sessions</u></a>. This means that only an opaque session ID is stored client-side, and all session/oauth state data is stored in Cloudflare KV. Again, it’s a natural fit for this use case.</p>
    <div>
      <h3>4. Fetching status and profile data</h3>
      <a href="#4-fetching-status-and-profile-data">
        
      </a>
    </div>
    <p>Using the DID stored in the session cookie, we restore the user’s OAuth session and <a href="https://github.com/inanna-malick/statusphere-serverless/blob/ca6e5ecd3a81dcfc80d9a9d976bac6efdad3a312/worker/src/frontend_worker/endpoints.rs#L111-L118"><u>spin up an authenticated agent</u></a>:</p>
            <pre><code>let agent = state.oauth.restore_session(&amp;did).await?;</code></pre>
            <p>With the agent ready, we <a href="https://github.com/inanna-malick/statusphere-serverless/blob/ca6e5ecd3a81dcfc80d9a9d976bac6efdad3a312/worker/src/frontend_worker/endpoints.rs#L120-L140"><u>fetch the user’s latest Statusphere post and their Bluesky profile</u></a>.</p>
            <pre><code>let current_status = agent.current_status().await?;
let profile = agent.bsky_profile().await?;</code></pre>
            <p>With their status and profile info in hand, we can <a href="https://github.com/inanna-malick/statusphere-serverless/blob/ca6e5ecd3a81dcfc80d9a9d976bac6efdad3a312/worker/src/frontend_worker/endpoints.rs#L142-L150"><u>render the homepage</u></a>:</p>
            <pre><code>Ok(HomeTemplate {
    status_options: &amp;STATUS_OPTIONS,
    profile: Some(Profile {
        did: did.to_string(),
        display_name: Some(username),
    }),
    my_status: current_status,
})</code></pre>
            
    <div>
      <h3>5. Publishing updates</h3>
      <a href="#5-publishing-updates">
        
      </a>
    </div>
    <p>When a user posts a new emoji status, we create a new record in their personal repo — using the same authenticated agent we used to fetch their data. This time, instead of reading, we <a href="https://github.com/inanna-malick/statusphere-serverless/blob/ca6e5ecd3a81dcfc80d9a9d976bac6efdad3a312/worker/src/frontend_worker/endpoints.rs#L183"><u>perform a </u><b><u>create record</u></b><u> operation</u></a>:</p>
            <pre><code>let uri = agent.create_status(form.status.clone()).await?.uri;</code></pre>
            <p>The operation returns a URI — the canonical identifier for the new record.</p><p>We then write the status update into D1, so it can immediately be reflected in the UI.</p>
    <div>
      <h3>6. Using Durable Objects to broadcast updates</h3>
      <a href="#6-using-durable-objects-to-broadcast-updates">
        
      </a>
    </div>
    <p>Every active homepage maintains a WebSocket connection to a Durable Object, which acts as a lightweight real-time message broker. When idle, the Durable Object <a href="https://developers.cloudflare.com/durable-objects/best-practices/websockets/#websocket-hibernation-api"><u>hibernates</u></a>, saving resources while keeping the WebSocket connections alive. We send a message to the Durable Object to <a href="https://github.com/inanna-malick/statusphere-serverless/blob/ca6e5ecd3a81dcfc80d9a9d976bac6efdad3a312/worker/src/frontend_worker/endpoints.rs#L192"><u>wake it up and broadcast the new update</u></a>:</p>
            <pre><code>state.durable_object.broadcast(status).await?;</code></pre>
            <p>The Durable Object then <a href="https://github.com/inanna-malick/statusphere-serverless/blob/ca6e5ecd3a81dcfc80d9a9d976bac6efdad3a312/worker/src/durable_object/server.rs#L88-L92"><u>broadcasts the new update to every connected homepage</u></a>:</p>
            <pre><code>for ws in self.state.get_websockets() {
    ws.send(&amp;status);
}</code></pre>
            <p>It then iterates over every live WebSocket and sends the update.</p><p>One practical note: Durable Objects perform better when <b>sharded across instances</b>. For simplicity, I’ve described the case where everything runs everything through <b>one single Durable Object.</b></p><p>To scale beyond that, the next step would be using multiple Durable Object instances per <a href="https://developers.cloudflare.com/durable-objects/reference/data-location/#supported-locations-1"><u>supported location</u></a> using <a href="https://developers.cloudflare.com/durable-objects/reference/data-location/#provide-a-location-hint"><u>location hints</u></a>, to minimize latency for users around the globe and avoid bottlenecks if we encounter high numbers of concurrent users in a single location. I initially considered implementing this pattern, but it conflicted with my goal of creating a concise ‘hello world’ style example that ATProto devs could clone and use as a template for their app.</p>
    <div>
      <h3>7. Listening for live changes</h3>
      <a href="#7-listening-for-live-changes">
        
      </a>
    </div>
    
    <div>
      <h4>The challenge: realtime feeds vs serverless</h4>
      <a href="#the-challenge-realtime-feeds-vs-serverless">
        
      </a>
    </div>
    <p>Publishing updates inside our own app is easy, but in the ATProto ecosystem, <b>other applications</b> can publish status updates for users. If we want Statusphere to be fully integrated, we need to pick up those events too.</p><p>Listening for live event updates requires a persistent WebSocket connection to the ATProto <a href="https://github.com/bluesky-social/jetstream"><u>Jetstream</u></a> service. Traditional server-based apps can keep WebSocket client sockets open indefinitely, but serverless platforms<b> </b>can’t — workers aren’t allowed to run forever.</p><p>We need a way to "listen" without running a live server.</p>
    <div>
      <h4>The solution: Cloudflare worker Cron Triggers</h4>
      <a href="#the-solution-cloudflare-worker-cron-triggers">
        
      </a>
    </div>
    <p>To solve this, we moved the listening logic into a <a href="https://developers.cloudflare.com/workers/configuration/cron-triggers/"><b><u>Cron Trigger</u></b></a> — instead of keeping a live socket open, we used this feature to read updates in small batches using a recurring scheduled job.</p><p>When the scheduled worker invocation fires, it loads the last seen cursor from its persistent storage. Then it <a href="https://github.com/inanna-malick/statusphere-serverless/blob/ca6e5ecd3a81dcfc80d9a9d976bac6efdad3a312/worker/src/services/jetstream.rs#L98-L101"><u>connects</u></a> to <a href="https://github.com/bluesky-social/jetstream"><u>Jetstream</u></a> — a streaming service for ATProto repo events — filtered by the xyz.statusphere.status collection and starting at the last seen cursor.</p>
            <pre><code>let ws = WebSocket::connect("wss://jetstream1.us-east.bsky.network/subscribe?wantedCollections=xyz.statusphere.status&amp;cursor={cursor}").await?;</code></pre>
            <p>We store a <b>cursor</b> — a microsecond timestamp marking the last message we received — in the Durable Object's persistent storage, so even if the object restarts, it knows exactly where to resume. As soon as we process an event newer than our start time, we close the WebSocket connection and let the Durable Object go back to sleep.</p><p>The tradeoff: updates can lag by up to a minute, but the system stays fully serverless. This is a great fit for early-stage apps and prototypes, where minimizing infrastructure complexity matters more than achieving perfect real-time delivery.</p>
    <div>
      <h2>Optional upgrade: real-time event listener</h2>
      <a href="#optional-upgrade-real-time-event-listener">
        
      </a>
    </div>
    <p>If you want real time updates, and you're willing to <b>bend the serverless model slightly</b>, you can deploy a lightweight listener process that maintains a live WebSocket connection to Jetstream.</p><p>Instead of polling once a minute, this process listens for new events for the xyz.statusphere.status collection and pushes updates to our Cloudflare Worker as soon as they arrive. You can find a sketch of this listener process <a href="https://github.com/inanna-malick/statusphere-serverless/tree/main/firehose_listener"><u>here</u></a> and the endpoint that handles updates from it <a href="https://github.com/inanna-malick/statusphere-serverless/blob/ca6e5ecd3a81dcfc80d9a9d976bac6efdad3a312/worker/src/frontend_worker/endpoints.rs#L211-L238"><u>here</u></a>.</p><p>The result still isn’t a traditional server:</p><ul><li><p>No public exposure to the web</p></li><li><p>No open HTTP ports</p></li><li><p>No persistent database</p></li></ul><p>It’s just a single-purpose, stateless listener — something simple enough to run on a home server until your app grows large enough to need more serious infrastructure.</p><p>Later on, you could swap this design for something more scalable using tools like <a href="https://developers.cloudflare.com/queues/"><u>Cloudflare Queues</u></a> to provide <a href="https://developers.cloudflare.com/queues/configuration/batching-retries/"><u>batching and retries</u></a> — but for small-to-medium apps, this lightweight listener is an easy and effective upgrade.</p>
    <div>
      <h2>Looking ahead</h2>
      <a href="#looking-ahead">
        
      </a>
    </div>
    <p>Today, Durable Objects can hibernate while holding long-lived WebSocket<b> server connections</b> but don't support hibernation when holding long-lived WebSocket <b>client connections</b> (like a Jetstream listener). That’s why Statusphere uses workarounds — scheduled Worker invocations via Cron Trigger and lightweight external listeners — to stay synced with the network.</p><p>Future improvements to Durable Objects — like adding support for hibernating active WebSocket clients — could remove the need for these workarounds entirely.</p>
    <div>
      <h2>Build your own ATProto app</h2>
      <a href="#build-your-own-atproto-app">
        
      </a>
    </div>
    <p>This is a full-featured atproto app running entirely on Cloudflare with zero servers and minimal ops overhead. Workers run your code <a href="https://www.cloudflare.com/network/"><u>within 50 ms of most users</u></a>, KV and D1 keep your data available, and Durable Objects handle WebSocket fan-out and live coordination.</p><p>Use the <b>Deploy to Cloudflare Button</b> to clone the <a href="https://github.com/inanna-malick/statusphere-serverless/tree/main"><u>repo</u></a> and set up your serverless environment. Then show us what you build. Drop a link in <a href="https://discord.com/invite/cloudflaredev"><u>our Discord</u></a>, or tag <a href="https://bsky.app/profile/cloudflare.social"><u>@cloudflare.social</u></a> on Bluesky or <a href="https://x.com/cloudflaredev"><u>@CloudflareDev</u></a> on X — we’d love to see it.</p><a href="https://deploy.workers.cloudflare.com/?url=https%3A%2F%2Fgithub.com%2Finanna-malick%2Fstatusphere-serverless%2Ftree%2Fmain%2Fworker"><img src="https://deploy.workers.cloudflare.com/button" /></a>
<p></p><p></p> ]]></content:encoded>
            <category><![CDATA[Durable Objects]]></category>
            <category><![CDATA[Wrangler]]></category>
            <category><![CDATA[Rust]]></category>
            <guid isPermaLink="false">1K5CTPFINqc8MVMEH3myp7</guid>
            <dc:creator>Inanna Malick</dc:creator>
        </item>
        <item>
            <title><![CDATA[Blazing fast development with full-stack frameworks and Cloudflare]]></title>
            <link>https://blog.cloudflare.com/blazing-fast-development-with-full-stack-frameworks-and-cloudflare/</link>
            <pubDate>Fri, 05 Apr 2024 13:00:44 GMT</pubDate>
            <description><![CDATA[ You can now use your framework’s development server while accessing D1 databases, R2 object stores, AI models, and more. Iterate locally in milliseconds to build sophisticated web apps that run on Cloudflare ]]></description>
            <content:encoded><![CDATA[ <p></p><p>Hello web developers! <a href="/making-cloudflare-for-web">Last year we released</a> a slew of improvements that made deploying web applications on Cloudflare much easier, and in response we’ve seen a large growth of Astro, Next.js, Nuxt, Qwik, Remix, SolidStart, SvelteKit, and other web apps hosted on Cloudflare. Today we are announcing major improvements to our integration with these web frameworks that makes it easier to develop sophisticated applications that use our <a href="https://www.cloudflare.com/developer-platform/products/d1/">D1 SQL database</a>, <a href="https://developers.cloudflare.com/r2/">R2</a> object store, <a href="https://developers.cloudflare.com/ai/">AI</a> models, and other powerful features of <a href="https://www.cloudflare.com/developer-platform/">Cloudflare’s developer platform.</a></p><p>In the past, if you wanted to develop a web framework-powered application with D1 and run it locally, you’d have to build a production build of your application, and then run it locally using `wrangler pages dev`. While this worked, each of your code iterations would take seconds, or tens of seconds for big applications. Iterating using production builds is simply too slow, pulls you out of the <a href="https://en.wikipedia.org/wiki/Flow_(psychology)">flow</a>, and doesn’t allow you to take advantage of all the DX optimizations that framework authors have put a lot of hard work into. This is changing today!</p><p>Our goal is to integrate with web frameworks in the most natural way possible, without developers having to learn and adopt significant workflow changes or custom APIs when deploying their app to Cloudflare. Whether you are a Next.js developer, a Nuxt developer, or prefer another framework, you can now keep on using the blazing fast local development workflow familiar to you, and ship your application on Cloudflare.</p><p>All full-stack web frameworks come with a local development server (dev server) that is custom tailored to the framework and often provides an excellent development experience, with only one exception — they don't natively support some important features of Cloudflare’s development platform, especially our <a href="https://www.cloudflare.com/developer-platform/products/#storage">storage solutions</a>.</p><p>So up until recently, you had to make a tough choice. You could use the framework-specific dev server to develop your application, but forgo access to many of Cloudflare’s features. Alternatively, you could take full advantage of Cloudflare’s platform including various resources like D1 or R2<a href="https://developers.cloudflare.com/workers/configuration/bindings/">, but you would have to give up using the framework specific developer tooling. In that case, your iteration cycle would slow down, and it would take seconds rather than milliseconds for you to see results of your code changes in the browser.</a> But not anymore! Let’s take a look.</p>
    <div>
      <h3>Let’s build an application</h3>
      <a href="#lets-build-an-application">
        
      </a>
    </div>
    <p>Let’s create a new application using <a href="https://developers.cloudflare.com/pages/get-started/c3/">C3</a> — our create-cloudflare CLI. We could use any npm client of our choice (pnpm anyone?!?), but to keep things simple in this post, we’ll stick with the default npm client. To get started, just run:</p><p><code>$ npm create cloudflare@latest</code></p><p>Provide a name for your app, or stick with the randomly generated one. Then select the “Website or web app” category, and pick a full-stack framework of your choice. We support many: <a href="https://astro.build/">Astro</a>, <a href="https://nextjs.org/">Next.js</a>, <a href="https://nuxt.com/">Nuxt</a>, <a href="https://qwik.dev/">Qwik</a>, <a href="https://remix.run/">Remix</a>, <a href="https://start.solidjs.com/getting-started/what-is-solidstart">SolidStart</a>, and <a href="https://kit.svelte.dev/">SvelteKit</a>.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/pa9natISsY3icyIUpu9Ul/cd6aa0baebe85d1b0a85eaba684d66e6/Screenshot-2024-03-28-at-7.25.10-AM.png" />
            
            </figure><p>Since C3 delegates the application scaffolding to the latest version of the framework-specific CLI, you will scaffold the application exactly as the framework authors intended without missing out on any of the framework features or options. C3 then adds to your application everything necessary for integrating and deploying to Cloudflare so that you don’t have to configure it yourself.</p><p>With our application scaffolded, let’s get it to display a list of products stored in a database with just a few steps. First, we add the configuration for our database to our <a href="https://developers.cloudflare.com/workers/wrangler/configuration/#d1-databases">wrangler.toml</a> config file:</p>
            <pre><code>[[d1_databases]]
binding = "DB"
database_name = "blog-products-db"
database_id = "XXXXXXXXXXXXXXXX"</code></pre>
            <p>Yes, that’s right! You can now configure your <a href="https://developers.cloudflare.com/workers/configuration/bindings/">bound resources</a> via the <a href="https://developers.cloudflare.com/pages/functions/wrangler-configuration/">wrangler.toml file</a>, even for full-stack apps deployed to Pages. We’ll share much more about configuration enhancements to Pages in a <a href="/browser-rendering-api-ga-rolling-out-cloudflare-snippets-swr-and-bringing-workers-for-platforms-to-our-paygo-plans/">dedicated announcement</a>.</p><p>Now let’s create a simple schema.sql file representing our database schema:</p>
            <pre><code>CREATE TABLE products(product_id INTEGER PRIMARY KEY, name TEXT, price INTEGER);
INSERT INTO products (product_id, name, price) VALUES (1, 'Apple', 250), (2, 'Banana', 100), (3, 'Cherry', 375);</code></pre>
            <p>And initialize our database:</p><p><code>$ npx wrangler d1 execute blog-products-db --local --file schema.sql</code></p><p>Notice that we used the <code>–local</code> flag of <a href="https://developers.cloudflare.com/workers/wrangler/commands/#execute"><code>wrangler d1 execute</code></a> to apply the changes to our local D1 database. This is the database that our dev server will connect to.</p><p>Next, if you use TypeScript, let TypeScript know about your database by running:</p><p><code>$ npm run build-cf-types</code></p><p>This command is preconfigured for all full-stack applications created via C3 and executes <a href="https://developers.cloudflare.com/workers/wrangler/commands/#types"><code>wrangler types</code></a> to update the interface of Cloudflare’s environment containing all configured bindings.</p><p>We can now start the dev server provided by your framework via a handy shortcut:</p><p><code>$ npm run dev</code></p><p>This shortcut will start your framework’s dev server, whether it’s powered by <a href="https://nextjs.org/docs/app/api-reference/next-cli#development">next dev</a>, <a href="https://nitro.unjs.io/">nitro</a>, or <a href="https://vitejs.dev/">vite</a>.</p><p>Now to access our database and list the products, we can now use a framework specific approach. For example, in a Next.js application that uses the App router, we could update <code>app/api/hello/route.ts</code> with the following:</p>
            <pre><code>const db = getRequestContext().env.DB;
 const productsResults = await db.prepare('SELECT * FROM products').all();
 return Response.json(productsResults.results);</code></pre>
            <p>Or in a Nuxt application, we can create a <code>server/api/hello.ts</code> file and populate it with:</p>
            <pre><code>export default defineEventHandler(async ({ context }) =&gt; {
   const db = context.cloudflare.env.DB;
   const productsResults = await db.prepare('SELECT * FROM products').all();
   return productsResults.results;
 });</code></pre>
            <p>Assuming that the framework dev server is running on port 3000, you can test the new API route in either framework by navigating to <a href="http://localhost:3000/api/hello">http://localhost:3000/api/hello</a>. For simplicity, we picked API routes in these examples, but the same applies to any UI-generating routes as well.</p><p>Each web framework has its own way to define routes and pass contextual information about the request throughout the application, so how you access your databases, object stores, and other resources will depend on your framework. You can read our updated full-stack framework guides to learn more:</p><ul><li><p><a href="https://developers.cloudflare.com/pages/framework-guides/deploy-an-astro-site/">Astro guide</a></p></li><li><p><a href="https://developers.cloudflare.com/pages/framework-guides/nextjs/deploy-a-nextjs-site/">Next.js guide</a></p></li><li><p><a href="https://developers.cloudflare.com/pages/framework-guides/deploy-a-nuxt-site/">Nuxt guide</a></p></li><li><p><a href="https://developers.cloudflare.com/pages/framework-guides/deploy-a-qwik-site/">Qwik guide</a></p></li><li><p><a href="https://developers.cloudflare.com/pages/framework-guides/deploy-a-remix-site/">Remix guide</a></p></li><li><p><a href="https://developers.cloudflare.com/pages/framework-guides/deploy-a-solid-site/">SolidStart guide</a></p></li><li><p><a href="https://developers.cloudflare.com/pages/framework-guides/deploy-a-svelte-site/">SvelteKit guide</a></p></li></ul><p>Now that you know how to access Cloudflare’s resources in the framework of your choice, everything else you know about your framework remains the same. You can now develop your application locally, using the development server optimized for your framework, which often includes support for hot module replacement (HMR), custom dev tools, enhanced debugging support and more, all while still benefiting from Cloudflare-specific APIs and features. Win-win!</p>
    <div>
      <h3>What has actually changed to enable these development workflows?</h3>
      <a href="#what-has-actually-changed-to-enable-these-development-workflows">
        
      </a>
    </div>
    <p>To decrease the development latency and preserve the custom framework-specific experiences, we needed to enable web frameworks and their dev servers to integrate with wrangler and miniflare in a seamless, almost invisible way.</p><p><a href="https://miniflare.dev/">Miniflare</a> is a key component in this puzzle. It is our local simulator for Cloudflare-specific resources, which is powered by <a href="https://github.com/cloudflare/workerd">workerd</a>, our JavaScript (JS) runtime. By relying on workerd, we ensure that Cloudflare’s JavaScript APIs run locally in a way that faithfully simulates our production environment. The trouble is that framework dev servers already rely on Node.js to run the application, so bringing another JS runtime into the mix breaks many assumptions in how these dev servers have been architected.</p><p>Our team however came up with an interesting approach to bridging the gap between these two JS runtimes. We call it the <a href="https://developers.cloudflare.com/workers/wrangler/api/#getplatformproxy">getPlatformProxy()</a> API, which is now part of wrangler and is super-powered by <a href="https://github.com/cloudflare/miniflare/pull/639">miniflare’s magic proxy</a>. This API exposes a <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy">JS proxy object</a> that behaves just like the usual <a href="https://developers.cloudflare.com/workers/runtime-apis/handlers/fetch/#parameters">Workers env object</a> containing all bound resources. The proxy object enables code from Node.js to transparently invoke JavaScript code running in workerd, as well access Cloudflare-specific runtime APIs.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1MPXvdyK3eYsY3YKnOC8co/480cdd00d7a921ecb65eb738caf17ff2/pasted-image-0--6-.png" />
            
            </figure><p>With this bridge between the Node.js and workerd runtimes, your application can now access Cloudflare simulators for D1, R2, KV and other storage solutions directly while running in a dev server powered by Node.js. Or you could even write an Node.js script to do the same:</p>
            <pre><code> import {getPlatformProxy} from 'wrangler';


 const {env} = getPlatformProxy();
 console.dir(env);
 const db = env.DB;


 // Now let’s execute a DB query that runs in a local D1 db
 // powered by miniflare/workerd and access the result from Node.js
 const productsResults = await db.prepare('SELECT * FROM products').all();
 console.log(productsResults.results);</code></pre>
            <p>With the <code>getPlatformProxy()</code> API available, the remaining work was all about updating all framework adapters, plugins, and in some cases frameworks themselves to make use of this API. We are grateful for the support we received from framework teams on this journey, especially <a href="https://github.com/alexanderniebuhr">Alex</a> from Astro, <a href="https://github.com/pi0">pi0</a> from Nuxt, <a href="https://github.com/pcattori">Pedro</a> from Remix, <a href="https://github.com/ryansolid">Ryan</a> from Solid, <a href="https://github.com/benmccann">Ben</a> and <a href="https://github.com/Rich-Harris">Rich</a> from Svelte, and our collaborator on the <a href="https://github.com/cloudflare/next-on-pages">next-on-pages</a> project, <a href="https://github.com/james-elicx">James Anderson</a>.</p>
    <div>
      <h3>Future improvements to development workflows with Vite</h3>
      <a href="#future-improvements-to-development-workflows-with-vite">
        
      </a>
    </div>
    <p>While the <a href="https://developers.cloudflare.com/workers/wrangler/api/#getplatformproxy"><code>getPlatformProxy()</code></a> API is a good solution for many scenarios, we can do better. If we could run the entire application in our JS runtime rather than Node.js, we could even more faithfully simulate the production environment and reduce developer friction and production surprises.</p><p>In the ideal world, we’d like you to develop against the same runtime that you deploy to in production, and this can only be achieved by integrating workerd directly into the dev servers of all frameworks, which is not a small feat considering the number of frameworks out there and the differences between them.</p><p>We however got a bit lucky. As we kicked off this effort, we quickly realized that <a href="https://vitejs.dev/">Vite</a>, a popular dev server used by many full-stack frameworks, was gaining increasingly greater adoption. In fact, Remix switched over to <a href="https://remix.run/blog/remix-vite-stable">Vite just recently</a> and confirmed the popularity of Vite as the common foundation for web development today.</p><p>If Vite had first-class support for running a full-stack application in an alternative JavaScript runtime, we could enable anyone using Vite to develop their applications locally with complete access to the Cloudflare developer platform. No more framework specific custom integrations and workarounds — all the features of a full-stack framework, Vite, and Cloudflare accessible to all developers.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3hj4Tb9Ex2NnwrnqZ5z6M2/e049e4300b188381259f60bc69ad054c/pasted-image-0--7-.png" />
            
            </figure><p>Sounds too good to be true? Maybe. We are very stoked to be working with the Vite team on the <a href="https://github.com/vitejs/vite/pull/16089">Vite environments</a> proposal, which could enable just that. This proposal is still evolving, so stay tuned for updates.</p>
    <div>
      <h3>What will you build today?</h3>
      <a href="#what-will-you-build-today">
        
      </a>
    </div>
    <p>We aim to make Cloudflare the best development platform for web developers. Making it quick and easy to develop your application with frameworks and tools you are already familiar with is a big part of our story. Start your journey with us by running a single command:</p><p><code>$ npm create cloudflare@latest</code></p> ]]></content:encoded>
            <category><![CDATA[Developer Week]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Developer Platform]]></category>
            <category><![CDATA[Full Stack]]></category>
            <category><![CDATA[Wrangler]]></category>
            <category><![CDATA[Miniflare]]></category>
            <guid isPermaLink="false">14PqvEOUknz9TI2FQGbZT3</guid>
            <dc:creator>Igor Minar</dc:creator>
            <dc:creator>Dario Piotrowicz</dc:creator>
            <dc:creator>James Culveyhouse</dc:creator>
            <dc:creator>Peter Bacon Darwin</dc:creator>
        </item>
        <item>
            <title><![CDATA[Announcing Pages support for monorepos, wrangler.toml, database integrations and more!]]></title>
            <link>https://blog.cloudflare.com/pages-workers-integrations-monorepos-nextjs-wrangler/</link>
            <pubDate>Thu, 04 Apr 2024 13:00:16 GMT</pubDate>
            <description><![CDATA[ Today, we’re launching four improvements to Pages that bring functionality previously restricted to Workers, with the goal of unifying the development experience between the two.  Support for monorepos, wrangler.toml, new additions to Next.js support and database integrations ]]></description>
            <content:encoded><![CDATA[ <p></p><p>Pages <a href="/cloudflare-pages-ga">launched</a> in 2021 with the goal of empowering developers to go seamlessly from idea to production. With <a href="https://developers.cloudflare.com/pages/get-started/git-integration/#configure-your-deployment">built-in CI/CD</a>, <a href="https://developers.cloudflare.com/pages/configuration/preview-deployments/">Preview Deployments</a>, <a href="https://developers.cloudflare.com/pages/configuration/git-integration/">integration with GitHub and GitLab</a>, and support for all the most popular <a href="https://developers.cloudflare.com/pages/framework-guides/">JavaScript frameworks</a>, Pages lets you build and deploy both static and full-stack apps globally to our network in seconds.</p><p>Pages has superpowers like these that Workers does not have, and vice versa. Today you have to choose upfront whether to build a Worker or a Pages project, even though the two products largely overlap. That’s why during 2023’s <a href="/pages-and-workers-are-converging-into-one-experience">Developer Week</a>, we started bringing both products together to give developers the benefit of the best of both worlds. And it’s why we announced that like Workers, Pages projects can now directly access <a href="https://developers.cloudflare.com/workers/configuration/bindings/">bindings</a> to Cloudflare services — using <a href="https://github.com/cloudflare/workerd">workerd</a> under-the-hood — even when using the local development server provided by a full-stack framework like <a href="https://developers.cloudflare.com/pages/framework-guides/deploy-an-astro-site/">Astro,</a> <a href="https://developers.cloudflare.com/pages/framework-guides/nextjs/deploy-a-nextjs-site/">Next.js,</a> <a href="https://developers.cloudflare.com/pages/framework-guides/deploy-a-nuxt-site/">Nuxt,</a> <a href="https://developers.cloudflare.com/pages/framework-guides/deploy-a-qwik-site/">Qwik,</a> <a href="https://developers.cloudflare.com/pages/framework-guides/deploy-a-remix-site/">Remix,</a> <a href="https://developers.cloudflare.com/pages/framework-guides/deploy-a-solid-site/">SolidStart, or</a> <a href="https://developers.cloudflare.com/pages/framework-guides/deploy-a-svelte-site/">SvelteKit</a>. Today, we’re thrilled to be launching some new improvements to Pages that bring functionality previously restricted to Workers. Welcome to the stage: monorepos, wrangler.toml, new additions to Next.js support, and database integrations!</p>
    <div>
      <h3>Pages now supports monorepos</h3>
      <a href="#pages-now-supports-monorepos">
        
      </a>
    </div>
    <p>Many development teams use monorepos – repositories that contain multiple apps, with each residing in its own subdirectory. This approach is extremely helpful when these apps share code.</p><p>Previously, the Pages CI/CD set-up limited users to one repo per project. To use a monorepo with Pages, you had to <a href="https://developers.cloudflare.com/pages/get-started/direct-upload/">directly upload it</a> on your own, using the Wrangler CLI. If you did this, you couldn’t use Pages’ integration with GitHub or Gitlab, or have Pages CI/CD handle builds and deployments. With Pages support for monorepos, development teams can trigger builds to their various projects with each push.</p><p><b>Manage builds and move fast</b>You can now include and exclude specific paths to watch for in each of your projects to avoid unnecessary builds from commits to your repo.</p><p>Let’s say a monorepo contains 4 subdirectories – a marketing app, an ecommerce app, a design library, and a package. The marketing app depends on the design library, while the ecommerce app depends on the design library and the package.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/435MhqmGH7CJ4dXIvMEbN2/2ec159aecf92ea18f5b686b75024484d/image3-7.png" />
            
            </figure><p>Updates to the design library should rebuild and redeploy both applications, but an update to the marketing app shouldn’t rebuild and deploy the ecommerce app. However, by default, any push you make to my-monorepo triggers a build for both projects regardless of which apps were changed. Using the include/exclude build controls, you can specify paths to build and ignore for your project to help you track dependencies and build more efficiently.</p><p><b>Bring your own tools</b>Already using tools like <a href="https://turbo.build/">Turborepo</a>, <a href="https://nx.dev/">NX</a>, and <a href="https://lerna.js.org/">Lerna</a>? No problem! You can also bring your favorite <a href="https://developers.cloudflare.com/pages/configuration/monorepos/#monorepo-management-tools">monorepo management tooling</a> to Pages to help manage your dependencies quickly and efficiently.</p><p>Whatever your tooling and however you’re set up, check out our <a href="https://developers.cloudflare.com/pages/configuration/monorepos/">documentation</a> to get started with your monorepo right out of the box.</p>
    <div>
      <h3>Configure Pages projects with wrangler.toml</h3>
      <a href="#configure-pages-projects-with-wrangler-toml">
        
      </a>
    </div>
    <p>Today, we’re excited to announce that you can now configure Pages projects using wrangler.toml — the same configuration file format that is already used for configuring Workers.</p><p>Previously, Pages projects had to be configured exclusively in the dashboard. This forced you to context switch from your development environment any time you made a configuration change, like adding an environment variable or <a href="https://developers.cloudflare.com/workers/configuration/bindings/">binding</a>. It also separated configuration from code, making it harder to know things like what bindings are being used in your project. If you were developing as a team, all the users on your team had to have access to your account to make changes – even if they had access to make changes to the source code via your repo.</p><p>With wrangler.toml, you can:</p><ul><li><p><b>Store your configuration file in source control.</b> Keep your configuration in your repo alongside the rest of your code.</p></li><li><p><b>Edit your configuration via your code editor.</b> Remove the need to switch back and forth between interfaces.</p></li><li><p><b>Write configuration that is shared across environments.</b> Define bindings and environment variables for local, preview, and production in one file.</p></li><li><p><b>Ensure better access control.</b> By using a configuration file in your repo, you can control who has access to make changes without giving access to your Cloudflare dashboard.</p></li></ul><p><b>Migrate existing projects</b>If you have an existing Pages project, we’ve added a new Wrangler CLI command that downloads your existing configuration and provides you with a valid <code>wrangler.toml</code> file.</p>
            <pre><code>$ npx wrangler@latest pages download config &lt;PROJECT_NAME&gt;</code></pre>
            <p>Run this command, add the wrangler.toml file that it generates to your project’s root directory, and then when you deploy, your project will be configured based on this configuration file.</p><p>If you are already using wrangler.toml to define your local development configuration, you can continue doing so. By default, your existing wrangler.toml file will continue to only apply to local development. When you run <code>wrangler pages deploy</code>, Wrangler will show you the additional fields that you must add in order for your configuration to apply to production and preview environments. Add these fields to your wrangler.toml, and then when you deploy your changes, the configuration you’ve defined in wrangler.toml will be used by your Pages project.</p><p>Refer to the <a href="https://developers.cloudflare.com/pages/functions/wrangler-configuration/">documentation</a> for more information on exactly what’s supported and how to leverage wrangler.toml in your development workflows.</p>
    <div>
      <h3>Integrate Pages projects with your favorite database</h3>
      <a href="#integrate-pages-projects-with-your-favorite-database">
        
      </a>
    </div>
    <p>You can already connect to <a href="https://developers.cloudflare.com/d1/">D1</a>, Cloudflare’s <a href="https://www.cloudflare.com/developer-platform/products/d1/">serverless SQL database</a>, directly from Pages projects. And you can connect directly to your existing PostgreSQL database using <a href="https://developers.cloudflare.com/hyperdrive/">Hyperdrive</a>. Today, we’re making it even easier for you to connect 3rd party databases to Pages with just a couple of clicks. Pages now integrates directly with <a href="https://developers.cloudflare.com/workers/databases/native-integrations/neon/">Neon</a>, <a href="https://developers.cloudflare.com/workers/databases/native-integrations/planetscale/">PlanetScale</a>, <a href="https://developers.cloudflare.com/workers/databases/native-integrations/supabase/">Supabase</a>, <a href="https://developers.cloudflare.com/workers/databases/native-integrations/turso/">Turso</a>, <a href="https://developers.cloudflare.com/workers/databases/native-integrations/upstash/">Upstash</a>, and <a href="https://developers.cloudflare.com/workers/databases/native-integrations/xata/">Xata</a>!</p><p>Simply navigate to your Pages project’s settings, select your database provider, and we’ll add <a href="https://developers.cloudflare.com/pages/functions/bindings/#environment-variableshttps://developers.cloudflare.com/pages/functions/bindings/#environment-variables">environment variables</a> with credentials needed to connect as well a <a href="https://developers.cloudflare.com/pages/functions/bindings/#secrets">secret</a> with the API key from the provider for you automatically.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2seOXZ1bXjWnBbHTV7zs4U/6e180084ddfcbcc3a661afdacb8b1dc9/image1-4.png" />
            
            </figure><p>Not ready to ship to production yet? You can deploy your changes to Pages’ preview environment alongside your staging database and test your deployment with its unique preview URL.</p><p><b>What’s coming up for integrations?</b>We’re just getting started with database integrations, with many more providers to come. In the future, we’re also looking to expand our integrations platform to include seamless set up when building other components of your app – think authentication and observability!</p><p>Want to bring your favorite tools to Cloudflare but don’t see the integration option? Want to build out your own integration?</p><p>Not only are we looking for <a href="https://docs.google.com/forms/d/e/1FAIpQLScUzm1bpWzR0SlJLGI80HchcAz9emPWG2lIXO107KNZTcfo-w/viewform">user input on new integrations</a> to add, but we’re also opening up the integrations platform to builders who want to submit their own products! We’ll be releasing step-by-step documentation and tooling to easily build and publish your own integration. If you’re interested in submitting your own integration, please fill out our <a href="https://docs.google.com/forms/d/e/1FAIpQLScUzm1bpWzR0SlJLGI80HchcAz9emPWG2lIXO107KNZTcfo-w/viewform">integration intake form</a> and we’ll be in touch!</p>
    <div>
      <h3>Improved Next.js Support for Pages</h3>
      <a href="#improved-next-js-support-for-pages">
        
      </a>
    </div>
    <p>With <a href="https://github.com/cloudflare/next-on-pages/releases">30 minor and patch releases</a> since the 1.0 launch of <a href="https://github.com/cloudflare/next-on-pages">next-on-pages</a> during Dev Week 2023, our <a href="https://nextjs.org/">Next.js</a> integration has been continuously maturing and keeping up with the evolution of Next.js. In addition to performance improvements, and compatibility and bug fixes, we released three significant improvements.</p><p>First, the <a href="https://eslint.org/">ESLint</a> plugin <a href="https://www.npmjs.com/package/eslint-plugin-next-on-pages">eslint-plugin-next-on-pages</a> is a great way to catch and fix compatibility issues as you are writing your code before you build and deploy applications. The plugin contains <a href="https://github.com/cloudflare/next-on-pages/tree/main/packages/eslint-plugin-next-on-pages/docs/rules">several rules</a> for the most common coding mistakes we see developers make, with more being added as we identify problematic scenarios.</p><p>Another noteworthy change is the addition of <a href="https://github.com/cloudflare/next-on-pages/blob/3846730c4a0d12/packages/next-on-pages/README.md#cloudflare-platform-integration">getRequestContext()</a> APIs, which provides you with access to Cloudflare-specific resources and metadata about the request currently being processed by your application, allowing for example you to take client’s location or browser preferences into account when generating a response.</p><p>Last but not least, we have completely <a href="https://developers.cloudflare.com/pages/framework-guides/nextjs/deploy-a-nextjs-site/">overhauled the local development workflow for Next.js</a> as well as other full-stack frameworks. Thanks to the new <a href="https://github.com/cloudflare/next-on-pages/tree/main/internal-packages/next-dev">setupDevPlatform()</a> API, you can now use the default development server <code>next dev</code>, with support for instant edit &amp; refresh experience, while also using D1, <a href="https://www.cloudflare.com/developer-platform/r2/">R2</a>, KV and other resources provided by the Cloudflare development platform. Want to take it for a quick spin? Use <a href="https://developers.cloudflare.com/pages/get-started/c3/">C3</a> to scaffold a new Next.js application with just one command.</p><p>To learn more about our Next.js integration, check out our <a href="https://developers.cloudflare.com/pages/framework-guides/nextjs/deploy-a-nextjs-site/">Next.js framework guide</a>.</p>
    <div>
      <h3>What’s next for the convergence of Workers and Pages?</h3>
      <a href="#whats-next-for-the-convergence-of-workers-and-pages">
        
      </a>
    </div>
    <p>While today’s launch represents just a few of the many upcoming additions to converge Pages and Workers, we also wanted to share a few milestones that are on the horizon, planned later in 2024</p><p><b>Pages features coming soon to Workers</b></p><ul><li><p><b>Workers CI/CD.</b> Later this year, we plan to bring the <a href="https://www.cloudflare.com/learning/serverless/glossary/what-is-ci-cd/">CI/CD system</a> from Cloudflare Pages to Cloudflare Workers. Connect your repositories to Cloudflare and trigger builds for your Workers with every commit.</p></li><li><p><b>Serve static assets from Workers.</b> You will be able to deploy and serve static assets as part of Workers – just like you can with Pages today – and build Workers using full-stack frameworks! This will also extend to Workers for Platforms, allowing you to build platforms that let your customers deploy complete, full-stack applications that serve both dynamic and static assets.</p></li><li><p><b>Workers</b> <a href="https://developers.cloudflare.com/pages/configuration/preview-deployments"><b>preview URLs</b></a><b>.</b> Preview versions of your Workers with every change and share a unique URL with your team for testing.</p></li></ul><p><b>Workers features coming soon to Pages</b></p><ul><li><p><b>Add</b> <a href="https://developers.cloudflare.com/workers/observability/logging/tail-workers/"><b>Tail Workers</b></a> <b>to Pages projects.</b> Get observability into your Pages Functions by capturing <code>console.log()</code> messages, unhandled exceptions, and request metadata, and then forward the information to external destinations.</p></li><li><p><a href="https://developers.cloudflare.com/workers/observability/logging/logpush/"><b>Workers Trace Events Logpush</b></a><b>.</b> Push your Pages Functions logs to supported destinations like <a href="https://developers.cloudflare.com/r2/">R2</a>, Datadog, or any HTTP destination for long term storage, auditing, and compliance.</p></li><li><p><a href="https://developers.cloudflare.com/workers/configuration/versions-and-deployments/gradual-deployments/"><b>Gradual Deployments</b></a><b>.</b> Gradually deploy new versions of your Pages Function to reduce risk when making changes to critical applications.</p></li></ul><p>You might also notice that the Pages and Workers interfaces in the Cloudflare Dash will begin to look more similar through the rest of this year. These changes aren’t just superficial, or us porting over functionality from one product to another. Under-the-hood, we are unifying the way that Workers and Pages projects are composed and then deployed to our network, ensuring that as we add new products and features, they can work with both Pages and Workers on day one.</p><p>In the meantime, bring your monorepo, a wrangler.toml, and your favorite databases to Pages and let’s rock! Be sure to show off what you’ve built in the <a href="https://discord.cloudflare.com/">Cloudflare Developer Discord</a> or by giving us a shout at <a href="https://twitter.com/CloudflareDev">@CloudflareDev</a>.</p> ]]></content:encoded>
            <category><![CDATA[Developer Week]]></category>
            <category><![CDATA[Cloudflare Pages]]></category>
            <category><![CDATA[Wrangler]]></category>
            <category><![CDATA[Cloudflare Workers]]></category>
            <guid isPermaLink="false">4P2K139AXugqOLE4sR5wIu</guid>
            <dc:creator>Nevi Shah</dc:creator>
            <dc:creator>Adam Murray</dc:creator>
            <dc:creator>Igor Minar</dc:creator>
        </item>
        <item>
            <title><![CDATA[Improving Worker Tail scalability]]></title>
            <link>https://blog.cloudflare.com/improving-worker-tail-scalability/</link>
            <pubDate>Fri, 01 Sep 2023 13:00:46 GMT</pubDate>
            <description><![CDATA[ We’re excited to announce improvements to Workers Tail that means it can now be enabled for Workers at any size and scale ]]></description>
            <content:encoded><![CDATA[ 
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/56gEEDPmOntJoXI16u8qU5/0ed51f115308dc4941b6553fbdaed0f0/image2-15.png" />
            
            </figure><p>Being able to get real-time information from applications in production is extremely important. Many times software passes local testing and automation, but then users report that something isn’t working correctly. Being able to quickly see what is happening, and how often, is critical to debugging.</p><p>This is why we originally developed the Workers Tail feature - to allow developers the ability to view requests, exceptions, and information for their Workers and to provide a window into what’s happening in real time. When we developed it, we also took the opportunity to build it on top of our own Workers technology using products like Trace Workers and Durable Objects. Over the last couple of years, we’ve continued to iterate on this feature - allowing users to quickly access logs <a href="/introducing-workers-dashboard-logs/">from the Dashboard</a> and via <a href="/10-things-i-love-about-wrangler/">Wrangler CLI</a>.</p><p>Today, we’re excited to announce that tail can now be enabled for Workers at any size and scale! In addition to telling you about the new and improved scalability, we wanted to share how we built it, and the changes we made to enable it to scale better.</p>
    <div>
      <h3>Why Tail was limited</h3>
      <a href="#why-tail-was-limited">
        
      </a>
    </div>
    <p>Tail leverages <a href="https://developers.cloudflare.com/workers/runtime-apis/durable-objects/#durable-objects">Durable Objects</a> to handle coordination between the Worker producing messages and consumers like <code>wrangler</code> and the Cloudflare dashboard, and Durable Objects are a great choice for handling real-time communication like this. However, when a single Durable Object instance starts to receive a very high volume of traffic - like the kind that can come with tailing live Workers - it can see some performance issues.</p><p>As a result, Workers with a high volume of traffic could not be supported by the original Tail infrastructure. Tail had to be limited to Workers receiving 100 requests/second (RPS) or less. This was a significant limitation that resulted in many users with large, high-traffic Workers having to turn to their own tooling to get proper observability in production.</p><p>Believing that every feature we provide should scale with users during their development journey, we set out to improve Tail's performance at high loads.</p>
    <div>
      <h3>Updating the way filters work</h3>
      <a href="#updating-the-way-filters-work">
        
      </a>
    </div>
    <p>The first improvement was to the existing filtering feature. When starting a Tail with <a href="https://developers.cloudflare.com/workers/wrangler/commands/#tail"><code>wrangler tail</code></a> (and now with the Cloudflare dashboard) users have the ability to filter out messages based on information in the requests or logs.Previously, this filtering was handled within the Durable Object, which meant that even if a user was filtering out the majority of their traffic, the Durable Object would still have to handle every message. Often users with high traffic Tails were using many filters to better interpret their logs, but wouldn’t be able to start a Tail due to the 100 RPS limit.</p><p>We moved filtering out of the Durable Object and into the Tail message producer, preventing any filtered messages from reaching the Tail Durable Object, and thereby reducing the load on the Tail Durable Object. Moving the filtering out of the Durable Object was the first step in improving Tail’s performance at scale.</p>
    <div>
      <h3>Sampling logs to keep Tails within Durable Object limits</h3>
      <a href="#sampling-logs-to-keep-tails-within-durable-object-limits">
        
      </a>
    </div>
    <p>After moving log filtering outside of the Durable Object, there was still the issue of determining when Tails could be started since there was no way to determine to what degree filters would reduce traffic for a given Tail, and simply starting a Durable Object back up would mean that it more than likely hit the 100 RPS limit immediately.</p><p>The solution for this was to add a safety mechanism for the Durable Object while the Tail was running.</p><p>We created a simple controller to track the RPS hitting a Durable Object and sample messages until the desired volume of 100 RPS is reached. As shown below, sampling keeps the Tail Durable Object RPS below the target of 100.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7a0f6KNAQCBfodwsGwzlEs/340c5f194ea626f41552f090787257a0/image4-12.png" />
            
            </figure><p>When messages are sampled, the following message appears every five seconds to let the user know that they are in sampling mode:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7jSffNOJOWuhVam9g2kjo2/daafee133ea30515a5b1ca30fbe559e7/image3-9.png" />
            
            </figure><p>This message goes away once the Tail is stopped or filters are applied that drop the RPS below 100.</p>
    <div>
      <h3>A final failsafe</h3>
      <a href="#a-final-failsafe">
        
      </a>
    </div>
    <p>Finally as a last resort a failsafe mechanism was added in the case the Durable Object gets fully overloaded. Since RPS tracking is done within the Durable Object, if the Durable Object is overloaded due to an extremely large amount of traffic, the sampling mechanism will fail.</p><p>In the case that an overload is detected, all messages forwarded to the Durable Object are stopped periodically to prevent any issues with Workers infrastructure.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7FXCXIYrmzHVJHFlRF1wXQ/d454b9bffab6eeddb19ec5718636113e/image1-24.png" />
            
            </figure><p>Here we can see a user who had a large amount of traffic that started to become sampled. As the traffic increased, the number of sampled messages grew. Since the traffic was too fast for the sampling mechanism to handle, the Durable Object got overloaded. However, soon excess messages were blocked and the overload stopped.</p>
    <div>
      <h3>Try it out</h3>
      <a href="#try-it-out">
        
      </a>
    </div>
    <p>These new improvements are in place currently and available to all users 🎉</p><p>To Tail Workers via the Dashboard, log in, navigate to your Worker, and click on the Logs tab. You can then start a log stream via the default view.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/F5Z80VaPFuPW71NWvfA3g/27e7fb654ac3eac556611c81a2ad0a1d/image5-9.png" />
            
            </figure><p>If you’re using the Wrangler CLI, you can start a new Tail by running <code>wrangler tail</code>.</p>
    <div>
      <h3>Beyond Worker tail</h3>
      <a href="#beyond-worker-tail">
        
      </a>
    </div>
    <p>While we're excited for tail to be able to reach new limits and scale, we also recognize users may want to go beyond the live logs provided by Tail.</p><p>For example, if you’d like to push log events to additional destinations for a historical view of your application’s performance, we offer <a href="https://developers.cloudflare.com/workers/observability/logpush/">Logpush</a>. If you’d like more insight into and control over log messages and events themselves, we offer <a href="https://developers.cloudflare.com/workers/observability/tail-workers/">Tail Workers</a>.</p><p>These products, and others, can be read about in our <a href="https://developers.cloudflare.com/logs/">Logs documentation</a>. All of them are available for use today.</p> ]]></content:encoded>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Wrangler]]></category>
            <category><![CDATA[Logs]]></category>
            <category><![CDATA[Developer Platform]]></category>
            <guid isPermaLink="false">7JrxctC3rnpXqgmtN5ffYL</guid>
            <dc:creator>Joshua Johnson</dc:creator>
            <dc:creator>Adam Murray</dc:creator>
        </item>
        <item>
            <title><![CDATA[Improved local development with wrangler and workerd]]></title>
            <link>https://blog.cloudflare.com/wrangler3/</link>
            <pubDate>Wed, 17 May 2023 13:00:15 GMT</pubDate>
            <description><![CDATA[ We’re proud to announce the release of Wrangler v3 – the first version of Wrangler with local-by-default development, powered by Miniflare v3 and the open-source Workers `workerd` runtime. ]]></description>
            <content:encoded><![CDATA[ 
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3iSHHNyNYsb21AEw80h3lW/953b982411c18fcb0721afc8dd83ac7e/image5-7.png" />
            
            </figure><p>For over a year now, we’ve been working to improve the Workers local development experience. Our goal has been to improve parity between users' local and production environments. This is important because it provides developers with a fully-controllable and easy-to-debug local testing environment, which leads to increased developer efficiency and confidence.</p><p>To start, we integrated <a href="https://github.com/cloudflare/miniflare">Miniflare</a>, a fully-local simulator for Workers, directly <a href="/miniflare/">into Wrangler</a>, the Workers CLI. This allowed users to develop locally with Wrangler by running <code>wrangler dev --local</code>. Compared to the <code>wrangler dev</code> default, which relied on remote resources, this represented a significant step forward in local development. As good as it was, it couldn’t leverage the actual Workers runtime, which led to some inconsistencies and behavior mismatches.</p><p>Last November, we <a href="/miniflare-and-workerd/">announced the experimental version of Miniflare v3,</a> powered by the newly open-sourced <a href="https://github.com/cloudflare/workerd"><code>workerd</code> runtime</a>, the same runtime used by Cloudflare Workers. Since then, we’ve continued to improve upon that experience both in terms of accuracy with the real runtime and in cross-platform compatibility.</p><p>As a result of all this work, we are proud to announce the release of Wrangler v3 – the first version of Wrangler with local-by-default development.</p>
    <div>
      <h2>A new default for Wrangler</h2>
      <a href="#a-new-default-for-wrangler">
        
      </a>
    </div>
    <p>Starting with Wrangler v3, users running <code>wrangler dev</code> will be leveraging Miniflare v3 to run your Worker locally. This local development environment is effectively as accurate as a production Workers environment, providing an ability for you to test every aspect of your application before deploying. It provides the same runtime and bindings, but has its own simulators for KV, R2, D1, Cache and Queues. Because you’re running everything on your machine, you won’t be billed for operations on KV namespaces or R2 buckets during development, and you can try out paid-features like Durable Objects for free.</p><p>In addition to a more accurate developer experience, you should notice performance differences. Compared to remote mode, we’re seeing a 10x reduction to startup times and 60x reduction to script reload times with the new local-first implementation. This massive reduction in reload times drastically improves developer velocity!</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3iwuiO3yvOuQQLFa9DbQZU/21379c38d9ce9a73e0f7a1c6eb8fbfb4/image4-12.png" />
            
            </figure><p>Remote development isn’t going anywhere. We recognise many developers still prefer to test against real data, or want to test Cloudflare services like <a href="https://developers.cloudflare.com/images/image-resizing/resize-with-workers">image resizing</a> that aren’t implemented locally yet. To run <code>wrangler dev</code> on Cloudflare’s network, just like previous versions, use the new <code>--remote</code> flag.</p>
    <div>
      <h2>Deprecating Miniflare v2</h2>
      <a href="#deprecating-miniflare-v2">
        
      </a>
    </div>
    <p>For users of Miniflare, there are two important pieces of information for those updating from v2 to v3. First, if you’ve been using Miniflare’s CLI directly, you’ll need to switch to <code>wrangler dev</code>. Miniflare v3 no longer includes a CLI. Secondly, if you’re using Miniflare’s API directly, upgrade to <code>miniflare@3</code> and follow the <a href="https://miniflare.dev/get-started/migrating">migration guide</a>.</p>
    <div>
      <h2>How we built Miniflare v3</h2>
      <a href="#how-we-built-miniflare-v3">
        
      </a>
    </div>
    <p>Miniflare v3 is now built using <code>workerd</code>, the open-source Cloudflare Workers runtime. As <code>workerd</code> is a server-first runtime, every configuration defines at least one socket to listen on. Each socket is configured with a service, which can be an external server, disk directory or most importantly for us, a Worker! To start a <code>workerd</code> server running a Worker, create a <code>worker.capnp</code> file as shown below, run <code>npx workerd serve worker.capnp</code> and visit <a href="http://localhost:8080">http://localhost:8080</a> in your browser:</p>
            <pre><code>using Workerd = import "/workerd/workerd.capnp";


const helloConfig :Workerd.Config = (
 services = [
   ( name = "hello-worker", worker = .helloWorker )
 ],
 sockets = [
   ( name = "hello-socket", address = "*:8080", http = (), service = "hello-worker" )
 ]
);


const helloWorker :Workerd.Worker = (
 modules = [
   ( name = "worker.mjs",
     esModule =
       `export default {
       `  async fetch(request, env, ctx) {
       `    return new Response("Hello from workerd! 👋");
       `  }
       `}
   )
 ],
 compatibilityDate = "2023-04-04",
);</code></pre>
            <p>If you’re interested in what else <code>workerd</code> can do, check out the <a href="https://github.com/cloudflare/workerd/tree/main/samples">other samples</a>. Whilst <code>workerd</code> provides the runtime and bindings, it doesn’t provide the underlying implementations for the other products in the Developer Platform. This is where Miniflare comes in! It provides simulators for KV, R2, D1, Queues and the Cache API.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/44vdcPO7sdaTtBi0u0HMgE/85e6510a0f8689284add4318e09c4c2c/image1-43.png" />
            
            </figure>
    <div>
      <h3>Building a flexible storage system</h3>
      <a href="#building-a-flexible-storage-system">
        
      </a>
    </div>
    <p>As you can see from the diagram above, most of Miniflare’s job is now providing different interfaces for data storage. In Miniflare v2, we used a custom key-value store to back these, but this had <a href="https://github.com/cloudflare/miniflare/issues/167">a</a> <a href="https://github.com/cloudflare/miniflare/issues/247">few</a> <a href="https://github.com/cloudflare/miniflare/issues/530">limitations</a>. For Miniflare v3, we’re now using the industry-standard <a href="https://sqlite.org/index.html">SQLite</a>, with a separate blob store for KV values, R2 objects, and cached responses. Using SQLite gives us much more flexibility in the queries we can run, allowing us to support future unreleased storage solutions. 👀</p><p>A separate blob store allows us to provide efficient, ranged, <a href="https://streams.spec.whatwg.org/#example-rbs-pull">streamed access</a> to data. Blobs have unguessable identifiers, can be deleted, but are otherwise immutable. These properties make it possible to perform atomic updates with the SQLite database. No other operations can interact with the blob until it's committed to SQLite, because the ID is not guessable, and we don't allow listing blobs. For more details on the rationale behind this, check out the <a href="https://github.com/cloudflare/miniflare/discussions/525">original GitHub discussion</a>.</p>
    <div>
      <h3>Running unit tests inside Workers</h3>
      <a href="#running-unit-tests-inside-workers">
        
      </a>
    </div>
    <p>One of Miniflare’s primary goals is to provide a great local testing experience. Miniflare v2 provided <a href="https://miniflare.dev/testing/vitest">custom environments</a> for popular Node.js testing frameworks that allowed you to run your tests <i>inside</i> the Miniflare sandbox. This meant you could import and call any function using Workers runtime APIs in your tests. You weren’t restricted to integration tests that just send and receive HTTP requests. In addition, these environments provide per-test isolated storage, automatically undoing any changes made at the end of each test.</p><p>In Miniflare v2, these environments were relatively simple to implement. We’d already reimplemented Workers Runtime APIs in a Node.js environment, and could inject them using Jest and Vitest’s APIs into the global scope.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6UrAr6zl1SsIbG2Qyvq1p2/40113914d049e7ad928c16373dab7fa7/image3-13.png" />
            
            </figure><p>For Miniflare v3, this is much trickier. The runtime APIs are implemented in a separate <code>workerd</code> process, and you can’t reference JavaScript classes across a process boundary. So we needed a new approach…</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/44s7Z0ZD3r5hQpdCxr1atZ/8b1d395872b13a1123cf77e25ab07533/image7-7.png" />
            
            </figure><p>Many test frameworks like Vitest use Node’s built-in <a href="https://nodejs.org/api/worker_threads.html"><code>worker_threads</code></a> module for running tests in parallel. This module spawns new operating system threads running Node.js and provides a <code>MessageChannel</code> interface for communicating between them. What if instead of spawning a new OS thread, we spawned a new <code>workerd</code> process, and used WebSockets for communication between the Node.js host process and the <code>workerd</code> “thread”?</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5jGThLJfIpVq47I9KaxaS3/86a1ff8b9739f21e6629eb8f8b793ffa/image8-8.png" />
            
            </figure><p>We have a proof of concept using Vitest showing this approach can work in practice. Existing Vitest IDE integrations and the Vitest UI continue to work without any additional work. We aren’t quite ready to release this yet, but will be working on improving it over the next few months. Importantly, the <code>workerd</code> “thread” needs access to Node.js built-in modules, which we recently started <a href="/workers-node-js-asynclocalstorage/">rolling out support for</a>.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/HqXRYKmlaionjMJK7PW6i/974cb97c5b694db5c3f567f628d861ed/image2-23.png" />
            
            </figure>
    <div>
      <h3>Running on every platform</h3>
      <a href="#running-on-every-platform">
        
      </a>
    </div>
    <p>We want developers to have this great local testing experience, regardless of which operating system they’re using. Before open-sourcing, the Cloudflare Workers runtime was originally only designed to run on Linux. For Miniflare v3, we needed to add support for macOS and Windows too. macOS and Linux are both Unix-based, making porting between them relatively straightforward. Windows on the other hand is an entirely different beast… 😬</p><p>The <code>workerd</code> runtime uses <a href="https://github.com/capnproto/capnproto/tree/master/c%2B%2B/src/kj">KJ</a>, an alternative C++ base library, which is already cross-platform. We’d also migrated to the <a href="https://bazel.build/">Bazel</a> build system in preparation for open-sourcing the runtime, which has good Windows support. When compiling our C++ code for Windows, we use LLVM's MSVC-compatible compiler driver <a href="https://llvm.org/devmtg/2014-04/PDFs/Talks/clang-cl.pdf"><code>clang-cl</code></a>, as opposed to using Microsoft’s Visual C++ compiler directly. This enables us to use the "same" compiler frontend on Linux, macOS, and Windows, massively reducing the effort required to compile <code>workerd</code> on Windows. Notably, this provides proper support for <code>#pragma once</code> when using symlinked virtual includes produced by Bazel, <code>__atomic_*</code> functions, a standards-compliant preprocessor, GNU statement expressions used by some KJ macros, and understanding of the <code>.c++</code> extension by default. After switching out <a href="https://github.com/mrbbot/workerd/blob/5e10e308e6683f8f88833478801c07da4fe01063/src/workerd/server/workerd.c%2B%2B#L802-L808">unix API calls for their Windows equivalents</a> using <code>#if _WIN32</code> preprocessor directives, and fixing a bunch of segmentation faults caused by execution order differences, we were finally able to get <code>workerd</code> running on Windows! No WSL or Docker required! 🎉</p>
    <div>
      <h2>Let us know what you think!</h2>
      <a href="#let-us-know-what-you-think">
        
      </a>
    </div>
    <p>Wrangler v3 is now generally available! Upgrade by running <code>npm install --save-dev wrangler@3</code> in your project. Then run <code>npx wrangler dev</code> to try out the new local development experience powered by Miniflare v3 and the open-source Workers runtime. Let us know what you think in the <code>#wrangler</code> channel on the <a href="https://discord.com/invite/cloudflaredev">Cloudflare Developers Discord</a>, and please <a href="https://github.com/cloudflare/workers-sdk/issues/new/choose">open a GitHub issue</a> if you hit any unexpected behavior.</p> ]]></content:encoded>
            <category><![CDATA[Developer Week]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Serverless]]></category>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[Wrangler]]></category>
            <category><![CDATA[Miniflare]]></category>
            <category><![CDATA[Developer Platform]]></category>
            <guid isPermaLink="false">6XGVmk1ZbylTfVULuFs2jk</guid>
            <dc:creator>Brendan Coll</dc:creator>
            <dc:creator>Adam Murray</dc:creator>
        </item>
        <item>
            <title><![CDATA[So long, and thanks for all the deployments:  deprecating Wrangler v1]]></title>
            <link>https://blog.cloudflare.com/deprecating-wrangler-v1/</link>
            <pubDate>Thu, 16 Feb 2023 19:46:33 GMT</pubDate>
            <description><![CDATA[ Version 1 of Wrangler has served us well for years. But with a new major version to focus on, it’s time to say goodbye ]]></description>
            <content:encoded><![CDATA[ 
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/759SbuM7qO646ytnmnYHN4/d4bcf6ed7e01aebd99614910394586fc/Developer-Challenges.png" />
            
            </figure><p><a href="https://workers.cloudflare.com/">Cloudflare Workers</a> allow developers to deploy code instantly across the globe. <a href="https://github.com/cloudflare/workers-sdk">Wrangler</a> is the CLI tool we build (and use!) to create, modify, and upload Workers. We recently <a href="/wrangler-v2-beta/">announced a new version of Wrangler</a> with <a href="/10-things-i-love-about-wrangler/">a bunch of new features</a> – including <a href="/10-things-i-love-about-wrangler/#4-local-mode">offline development</a>, <a href="/10-things-i-love-about-wrangler/#2-zero-config-startup">zero-config startup</a>, and <a href="/10-things-i-love-about-wrangler/#7-on-demand-developer-tools-for-debugging-">developer tools support</a>. Since then, we’ve been working hard to make the developer experience with version 2 as smooth and enjoyable as possible. We’re confident in what we’ve built and are now planning to officially deprecate version 1.</p>
    <div>
      <h3>What’s happening?</h3>
      <a href="#whats-happening">
        
      </a>
    </div>
    <p>Version 1 of Wrangler (<a href="https://www.npmjs.com/package/@cloudflare/wrangler">@cloudflare/wrangler</a> on npm) is now deprecated, which means no new features or bug fixes will be published unless they’re critical. Beginning August 2023, no further updates will be provided and the <a href="https://github.com/cloudflare/wrangler-legacy">Wrangler v1 GitHub repo</a> will be archived. We strongly recommend you upgrade to version 2 (<a href="https://www.npmjs.com/package/wrangler">wrangler</a> on npm) to receive continued support. We have a <a href="https://developers.cloudflare.com/workers/wrangler-legacy/migration/">migration guide</a> to make this process easy!</p>
    <div>
      <h3>Why?</h3>
      <a href="#why">
        
      </a>
    </div>
    <p>Our goal is to make development on the Cloudflare platform as smooth and enjoyable as possible. Whether that means <a href="https://github.com/cloudflare/workers-sdk/pull/1735">simplifying common workflows</a>, <a href="https://github.com/cloudflare/workers-sdk/pull/82">incorporating powerful tools into the Wrangler codebase</a>, or <a href="https://github.com/cloudflare/workers-sdk/pull/1350">opening up Wrangler for use as a library</a>, we want Wrangler to be a one-stop shop for developing on Cloudflare.</p><p>With that in mind, last year we set out to align our product with our goals. Wrangler was the primary way developers interacted with our platform, but the codebase was difficult to maintain and had spiraled in complexity. Weighing our options, we found that the best way forward was a total rewrite of Wrangler, culminating in the 2.0 release.</p><p>Typically, <a href="https://semver.org/#:~:text=Given%20a%20version,incompatible%20API%20changes">semver-major releases</a> (such as 1.x to 2.0) introduce breaking changes into a codebase – making it non-trivial to update to the latest version of software. While some breakage was inevitable with the release of a new major version of Wrangler, we aimed to ensure smooth upgrades. We <a href="https://github.com/cloudflare/workers-sdk/pull/733">provided detailed deprecation messages</a> and <a href="https://developers.cloudflare.com/workers/wrangler-legacy/migration/deprecations/">documented breaking changes</a> wherever they occurred. We carefully <a href="https://github.com/cloudflare/workers-sdk/issues/1519">monitored issue reports</a>, and responded with <a href="https://github.com/cloudflare/workers-sdk/pull/1595">updates to fix problems</a>. We monitored download statistics of both versions of wrangler, and celebrated internally when <a href="https://npmtrends.com/@cloudflare/wrangler-vs-wrangler">downloads for version 2 of Wrangler surpassed downloads for version 1 on npm</a>.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/KgIP3OZCjcjEX2nzNSS5N/50784457e9e54426dc9dcf0bd4295b60/HMs_w-V8fT6F7MaZcOWZ0QxZcg1EBnM14PPt_svfEF-5ZKRwUxa5NBjYYNMdeZKht-vIMNzlUOi8ngNcKbLXc5oa8t2GiL8F3vASyuBJpzd0JvwLaqRXgyLwPClk.png" />
            
            </figure><p>Download statistics for @cloudflare/wrangler (version 1, in blue) and wrangler (version 2, in orange). Source: <a href="https://npmtrends.com/@cloudflare/wrangler-vs-wrangler">https://npmtrends.com/@cloudflare/wrangler-vs-wrangler</a></p>
    <div>
      <h3>What do I need to do?</h3>
      <a href="#what-do-i-need-to-do">
        
      </a>
    </div>
    <p>For most of our users, deprecation of version 1 will be invisible – they’re already on version 2! If you’re still on version 1, please upgrade – we have a <a href="https://developers.cloudflare.com/workers/wrangler/migration/migrating-from-wrangler-1/">migration guide</a> that details everything you need to do to update to the latest and greatest version. If you encounter any bugs, unexpected behavior, or anything blocking you from upgrading, <a href="https://github.com/cloudflare/workers-sdk/issues/new/choose">file an issue</a>! If you’re not using Wrangler, <a href="https://developers.cloudflare.com/workers/get-started/guide/">give it a shot</a>! We’re really proud of what we’ve built, and we want your feedback on how we can continue to make it even better.</p> ]]></content:encoded>
            <category><![CDATA[Wrangler]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[Developer Platform]]></category>
            <guid isPermaLink="false">64WRubOO5bpu7V0WeQs2np</guid>
            <dc:creator>Cass Fridkin</dc:creator>
            <dc:creator>Elizabeth Rapoport</dc:creator>
        </item>
        <item>
            <title><![CDATA[Doubling down on local development with Workers: Miniflare meets workerd]]></title>
            <link>https://blog.cloudflare.com/miniflare-and-workerd/</link>
            <pubDate>Fri, 18 Nov 2022 14:00:00 GMT</pubDate>
            <description><![CDATA[ Today, we’re taking local development to the next level by releasing Miniflare 3, powered by the open-source workerd runtime, along with support for migrating existing dashboard projects and using real data locally. ]]></description>
            <content:encoded><![CDATA[ 
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/dwWDZZWvAwOWqtzMwqqA8/0ed1217e005b7d723b60acf47de62e95/image3-38.png" />
            
            </figure><p>Local development gives you a fully-controllable and easy-to-debug testing environment. At the start of this year, we brought this experience to Workers developers by <a href="/miniflare/">launching Miniflare 2.0</a>: a local Cloudflare Workers simulator. Miniflare 2 came with features like step-through debugging support, detailed <code>console.log</code>s, pretty <a href="https://miniflare.dev/developing/source-maps">source-mapped</a> error pages, <a href="https://miniflare.dev/developing/live-reload">live reload</a> and a highly-configurable <a href="https://miniflare.dev/testing/jest">unit testing environment</a>. Not only that, but we also incorporated Miniflare into Wrangler, our Workers CLI, to enable <code>wrangler dev</code>’s --<code>local</code> mode.</p><p>Today, we’re taking local development to the next level! In addition to introducing new support for migrating existing projects to your local development environment, we're making it easier to work with your remote data—locally! Most importantly, we're releasing a much more accurate Miniflare 3, powered by the <a href="/workerd-open-source-workers-runtime/">recently open-sourced <code>workerd</code> runtime</a>—the same runtime used by Cloudflare Workers!</p>
    <div>
      <h3>Enabling local development with workerd</h3>
      <a href="#enabling-local-development-with-workerd">
        
      </a>
    </div>
    <p>One of the superpowers of having a local development environment is that you can test changes without affecting users in production. A great local environment offers a level of fidelity on par with production.</p><p>The way we originally approached local development was with Miniflare 2, which reimplemented Workers runtime APIs in JavaScript. Unfortunately, there were <a href="https://github.com/cloudflare/miniflare/issues?page=1&amp;q=is%3Aissue+label%3A%22behaviour+mismatch%22">subtle behavior mismatches</a> between these re-implementations and the real Workers runtime. These types of issues are really difficult for developers to debug, as they don’t appear locally, and step-through debugging of deployed Workers isn’t possible yet. For example, the following Worker returns responses successfully in Miniflare 2, so we might assume it’s safe to publish:</p>
            <pre><code>let cachedResponsePromise;
export default {
  async fetch(request, env, ctx) {
    // Let's imagine this fetch takes a few seconds. To speed up our worker, we
    // decide to only fetch on the first request, and reuse the result later.
    // This works fine in Miniflare 2, so we must be good right?
    cachedResponsePromise ??= fetch("https://example.com");
    return (await cachedResponsePromise).clone();
  },
};</code></pre>
            <p>However, as soon as we send multiple requests to our deployed Worker, it fails with <code>Error: Cannot perform I/O on behalf of a different request</code>. The problem here is that response bodies created in one request’s handler cannot be accessed from a different request's handler. This limitation allows Cloudflare to improve overall Worker performance, but it was almost impossible for Miniflare 2 to detect these types of issues locally. In this particular case, the best solution is to <a href="https://developers.cloudflare.com/workers/examples/cache-using-fetch/">cache using <code>fetch</code> itself</a>.</p><p>Additionally, because the Workers runtime uses a very recent version of V8, it supports some JavaScript features that aren’t available in all versions of Node.js. This meant a few features implemented in Workers, like <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findLast"><code>Array#findLast</code></a>, weren’t always available in Miniflare 2.</p><p>With the Workers runtime <a href="/workerd-open-source-workers-runtime/">now open-sourced</a>, Miniflare 3 can leverage the same implementations that are deployed on Cloudflare’s network, giving bug-for-bug compatibility and practically eliminating behavior mismatches. ?</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6VB6hw88YFoVMQWokJ0eIr/dda37612c76ed09051c4e997cf789c70/image4-26.png" />
            
            </figure><p>Miniflare 3’s new simplified architecture using worked</p><p>This radically simplifies our implementation too. We were able to remove <b>over 50,000</b> lines of code from Miniflare 2. Of course, we still kept all the Miniflare special-sauce that makes development fun like live reload and detailed logging. ?</p><a href="https://github.com/cloudflare/miniflare/pull/392"><img src="http://staging.blog.mrk.cfdata.org/content/images/2022/11/image5-15.png" /></a>
<p></p>
    <div>
      <h3>Local development with real data</h3>
      <a href="#local-development-with-real-data">
        
      </a>
    </div>
    <p>We know that many developers choose to test their Workers remotely on the Cloudflare network as it gives them the ability to test against real data. Testing against fake data in staging and local environments is sometimes difficult, as it never quite matches the real thing.</p><p>With Miniflare 3, we’re blurring the lines between local and remote development, by bringing real data to your machine as an experimental opt-in feature. If enabled, Miniflare will read and write data to namespaces on the Cloudflare network, as your Worker would when deployed. This is only supported with <a href="https://developers.cloudflare.com/workers/runtime-apis/kv/">Workers KV</a> for now, but we’re exploring similar solutions for <a href="https://developers.cloudflare.com/r2/">R2</a> and <a href="/introducing-d1/">D1</a>.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6lSKVsotKwkVeNIXGo3XoK/c10227a6bec12bb7ea72c44e72cb3f39/image2-46.png" />
            
            </figure><p>Miniflare’s system for accessing real KV data, reads and writes are cached locally for future accesses</p>
    <div>
      <h3>A new default for Wrangler</h3>
      <a href="#a-new-default-for-wrangler">
        
      </a>
    </div>
    <p>With Miniflare 3 now effectively as accurate as the real Workers environment, and the ability to access real data locally, we’re revisiting the decision to make remote development the initial Wrangler experience. In a future update, <code><b>wrangler dev --local</b></code><b> will become the default</b>. <code>--local</code> will no longer be required. Benchmarking suggests this will bring an approximate <b>10x reduction to startup</b> and a massive <b>60x reduction to script reload</b> times! Over the next few weeks, we’ll be focusing on further optimizing Wrangler’s performance to bring you the fastest Workers development experience yet!</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4qal4ZCSp4RwfzHJf5FTBa/43d3f6e244136954aeb084c7c798d632/image1-63.png" />
            
            </figure>
    <div>
      <h3><code>wrangler init --from-dash</code></h3>
      <a href="#wrangler-init-from-dash">
        
      </a>
    </div>
    <p>We want all developers to be able to take advantage of the improved local experience, so we’re making it easy to start a local Wrangler project from an existing Worker that’s been developed in the Cloudflare dashboard. With <a href="https://nodejs.org/">Node.js</a> installed, run <code>`npx wrangler init` --`from-dash &lt;your_worker_name&gt;`</code>in your terminal to set up a new project with all your existing code and bindings such as KV namespaces configured. You can now seamlessly continue development of your application locally, taking advantage of all the developer experience improvements Wrangler and Miniflare provide. When you’re ready to deploy your worker, run <code>npx wrangler publish</code>.</p>
    <div>
      <h3>Looking to the future</h3>
      <a href="#looking-to-the-future">
        
      </a>
    </div>
    <p>Over the next few months, the Workers team is planning to further improve the local development experience with a specific focus on automated testing. Already, we’ve released a <a href="https://developers.cloudflare.com/workers/wrangler/api/#unstable_dev">preliminary API</a> for programmatic end-to-end tests with <code>wrangler dev</code>, but we’re also investigating ways of bringing <a href="https://miniflare.dev/testing/jest">Miniflare 2’s Jest/Vitest environments</a> to <code>workerd</code>. We’re also considering creating extensions for popular IDEs to make developing workers even easier. ?</p><p>Miniflare 3.0 is now included in Wrangler! Try it out by running <code>npx wrangler@latest dev --experimental-local</code>. Let us know what you think in the <code>#wrangler</code> channel on the <a href="https://discord.gg/cloudflaredev">Cloudflare Developers Discord</a>, and please <a href="https://github.com/cloudflare/wrangler2/issues/new/choose">open a GitHub issue</a> if you hit any unexpected behavior.</p> ]]></content:encoded>
            <category><![CDATA[Developer Week]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Miniflare]]></category>
            <category><![CDATA[Wrangler]]></category>
            <guid isPermaLink="false">QtR4nYtrKq40SS7vGNN9N</guid>
            <dc:creator>Brendan Coll</dc:creator>
        </item>
        <item>
            <title><![CDATA[Improving Workers TypeScript support: accuracy, ergonomics and interoperability]]></title>
            <link>https://blog.cloudflare.com/improving-workers-types/</link>
            <pubDate>Fri, 18 Nov 2022 14:00:00 GMT</pubDate>
            <description><![CDATA[ Today, we’re excited to announce the next major release of Workers TypeScript definitions with a bunch of improvements, and the open-sourcing of the new automatic generation scripts. ]]></description>
            <content:encoded><![CDATA[ 
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6q7OqfYCQg4hWl6fxHoOq6/308a694c52ae40e073bc40b25e8dbe23/image2-47.png" />
            
            </figure><p><a href="https://www.typescriptlang.org/">TypeScript</a> makes it easy for developers to write code that doesn’t crash, by catching type errors before your program runs. We want developers to take advantage of this tooling, which is why one year ago, we <a href="/automatically-generated-types/">built a system to automatically generate TypeScript types</a> for the Cloudflare Workers runtime. This enabled developers to see code completions in their IDEs for Workers APIs, and to type check code before deploying. Each week, <a href="https://github.com/cloudflare/workers-types/pull/210">a new version of the types would be published</a>, reflecting the most recent changes.</p><p>Over the past year, we’ve received lots of feedback from customers and internal teams on how we could improve our types. With the switch to the Bazel build system in <a href="/workerd-open-source-workers-runtime/">preparation for open-sourcing the runtime</a>, we saw an opportunity to rebuild our types to be more accurate, easier to use, and simpler to generate. Today, we’re excited to announce the next major release of <code>@cloudflare/workers-types</code> with a bunch of new features, and the open-sourcing of the <a href="https://github.com/cloudflare/workerd/tree/main/types">fully-rewritten automatic generation scripts</a>.</p>
    <div>
      <h3>How to use TypeScript with Workers</h3>
      <a href="#how-to-use-typescript-with-workers">
        
      </a>
    </div>
    <p>Setting up TypeScript in Workers is easy! If you’re just getting started with Workers, install <a href="https://nodejs.org/">Node.js</a>, then run <code>npx wrangler init</code> in your terminal to generate a new project. If you have an existing Workers project and want to take advantage of our improved typings, install the latest versions of TypeScript and <code>@cloudflare/workers-types</code> with <code>npm install --save-dev typescript @cloudflare/workers-types@latest</code>, then create a <code>tsconfig.json</code> file with the following contents:</p>
            <pre><code>{
  "compilerOptions": {
    "target": "esnext",
    "module": "esnext",
    "lib": ["esnext"],
    "types": ["@cloudflare/workers-types"]
  }
}</code></pre>
            <p>Your editor will now highlight issues and give you code completions as you type, leading to a less error-prone and more enjoyable developer experience.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3Q1weJrUhhrrT7QIUkGMIw/c32d14dd8965a8b5598496045ac4fe2b/image3-39.png" />
            
            </figure><p>Editor highlighting incorrect use of <code>set</code> instead of <code>put</code>, and providing code completions</p>
    <div>
      <h3>Improved interoperability with standard types</h3>
      <a href="#improved-interoperability-with-standard-types">
        
      </a>
    </div>
    <p>Cloudflare Workers implement many of the same runtime APIs as browsers, and we’re working to improve our standards compliance even more with the <a href="/introducing-the-wintercg/">WinterCG</a>. However, there will always be fundamental differences between what browsers and Workers can do. For example, browsers can play audio files, whereas Workers have direct access to Cloudflare’s network for storing globally-distributed data. This mismatch means that the runtime APIs and types provided by each platform are different, which in turn makes it difficult to use Workers types with frameworks, like <a href="https://remix.run/">Remix</a>, that run the same files on the Cloudflare network and in the browser. These files need to be type-checked against <a href="https://raw.githubusercontent.com/microsoft/TypeScript/main/lib/lib.dom.d.ts"><code>lib.dom.d.ts</code></a>, which is incompatible with our types.</p><p>To solve this problem, we now generate a separate version of our types that can be selectively imported, without having to include <code>@cloudflare/workers-types</code> in your <code>tsconfig.json</code>’s <code>types</code> field. Here’s an example of what this looks like:</p>
            <pre><code>import type { KVNamespace } from "@cloudflare/workers-types";

declare const USERS_NAMESPACE: KVNamespace;</code></pre>
            <p>In addition, we automatically generate a diff of our types against TypeScript’s <a href="https://raw.githubusercontent.com/microsoft/TypeScript/main/lib/lib.webworker.d.ts"><code>lib.webworker.d.ts</code></a>. Going forward, we’ll use this to identify areas where we can further improve our spec-compliance.</p>
    <div>
      <h3>Improved compatibility with compatibility dates</h3>
      <a href="#improved-compatibility-with-compatibility-dates">
        
      </a>
    </div>
    <p>Cloudflare maintains strong backwards compatibility promises for all the APIs we provide. We use <a href="https://developers.cloudflare.com/workers/platform/compatibility-dates/">compatibility flags and dates</a> to make breaking changes in a backwards-compatible way. Sometimes these compatibility flags change the types. For example, the <a href="https://developers.cloudflare.com/workers/platform/compatibility-dates#global-navigator"><code>global_navigator</code></a> flag adds a new <code>navigator</code> global, and the <a href="https://developers.cloudflare.com/workers/platform/compatibility-dates#new-url-parser-implementation"><code>url_standard</code></a> flag changes the <code>URLSearchParams</code> constructor signature.</p><p>We now allow you to select the version of the types that matches your compatibility date, so you can be sure you’re not using features that won’t be supported at runtime.</p>
            <pre><code>{
  "compilerOptions": {
    ...
    "types": ["@cloudflare/workers-types/2022-08-04"]
  }
}</code></pre>
            
    <div>
      <h3>Improved integration with Wrangler</h3>
      <a href="#improved-integration-with-wrangler">
        
      </a>
    </div>
    <p>In addition to compatibility dates, your Worker environment configuration also impacts the runtime and type API surface. If you have bindings such as <a href="https://developers.cloudflare.com/workers/wrangler/configuration/#kv-namespaces">KV namespaces</a> or <a href="https://developers.cloudflare.com/workers/wrangler/configuration/#r2-buckets">R2 buckets</a> configured in your <code>wrangler.toml</code>, these need to be reflected in TypeScript types. Similarly, <a href="https://developers.cloudflare.com/workers/wrangler/configuration/#bundling">custom text, data and WebAssembly module rules</a> need to be declared so TypeScript knows the types of exports. Previously, it was up to you to create a separate ambient TypeScript file containing these declarations.</p><p>To keep <code>wrangler.toml</code> as the single source of truth, you can now run <code>npx wrangler types</code> to generate this file automatically.</p><p>For example, the following <code>wrangler.toml</code>…</p>
            <pre><code>kv_namespaces = [{ binding = "MY_NAMESPACE", id = "..." }]
rules = [{ type = "Text", globs = ["**/*.txt"] }]</code></pre>
            <p>…generates these ambient types:</p>
            <pre><code>interface Env {
  MY_NAMESPACE: KVNamespace;
}
declare module "*.txt" {
  const value: string;
  export default value;
}</code></pre>
            
    <div>
      <h3>Improved integrated documentation and changelogs</h3>
      <a href="#improved-integrated-documentation-and-changelogs">
        
      </a>
    </div>
    <p>Code completions provide a great way for developers new to the Workers platform to explore the API surface. We now include the documentation for standard APIs from TypeScript’s official types in our types. We’re also starting the process of bringing <a href="https://developers.cloudflare.com/workers/runtime-apis/">docs for Cloudflare specific APIs</a> into them too.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4N4SjX4uCcnhULQ6BeRfD9/d678d5a385b812670f70f331796c3fcc/image4-27.png" />
            
            </figure><p>For developers already using the Workers platform, it can be difficult to see how types are changing with each release of <code>@cloudflare/workers-types</code>. To avoid type errors and highlight new features, we now generate a detailed changelog with each release that <a href="https://github.com/cloudflare/workers-types/pull/291#issuecomment-1274541965">splits out new, changed and removed definitions</a>.</p>
    <div>
      <h3>How does type generation work under the hood?</h3>
      <a href="#how-does-type-generation-work-under-the-hood">
        
      </a>
    </div>
    <p>As mentioned earlier, we’ve completely rebuilt the <a href="https://github.com/cloudflare/workerd/tree/main/types">automatic type generation scripts</a> to be more reliable, extensible and maintainable. This means developers will get improved types as soon as new versions of the runtime are published. Our system now uses <code>workerd</code>’s new <a href="https://github.com/cloudflare/workerd/blob/200ded3d8469371f9ece6a00d4012e26637e5abc/src/workerd/jsg/rtti.h">runtime-type-information (RTTI) system</a> to query types of Workers runtime APIs, rather than attempting to extract this information from parsed C++ ASTs.</p>
            <pre><code>// Encode the KV namespace type without any compatibility flags enabled
CompatibilityFlags::Reader flags = {};
auto builder = rtti::Builder(flags);
auto type = builder.structure&lt;KvNamespace&gt;();
capnp::TextCodec codec;
auto encoded = codec.encode(type);
KJ_DBG(encoded); // (name = "KvNamespace", members = [ ... ], ...)</code></pre>
            <p>We then pass this RTTI to a TypeScript program that uses the <a href="https://github.com/microsoft/TypeScript/wiki/Using-the-Compiler-API">TypeScript Compiler API</a> to generate declarations and perform AST transformations to tidy them up. This is built into <code>workerd</code>’s Bazel build system, meaning generating types is now a single <code>bazel build //types:types</code> command. We leverage Bazel’s cache to rebuild as little as possible during generation.</p>
            <pre><code>import ts, { factory as f } from "typescript";

const keyParameter = f.createParameterDeclaration(
  /* decorators */ undefined,
  /* modifiers */ undefined,
  /* dotDotDotToken */ undefined,
  "key",
  /* questionToken */ undefined,
  f.createTypeReferenceNode("string")
);
const returnType = f.createTypeReferenceNode("Promise", [
  f.createUnionTypeNode([
    f.createTypeReferenceNode("string"),
    f.createLiteralTypeNode(f.createNull()),
  ]),
]);
const getMethod = f.createMethodSignature(
  /* modifiers */ undefined,
  "get",
  /* questionToken */ undefined,
  /* typeParameters */ undefined,
  [keyParameter],
  returnType
);
const kvNamespace = f.createInterfaceDeclaration(
  /* decorators */ undefined,
  /* modifiers */ undefined,
  "KVNamespace",
  /* typeParameters */ undefined,
  /* heritageClauses */ undefined,
  [getMethod]
);

const file = ts.createSourceFile("file.ts", "", ts.ScriptTarget.ESNext);
const printer = ts.createPrinter();
const output = printer.printNode(ts.EmitHint.Unspecified, kvNamespace, file);
console.log(output); // interface KVNamespace { get(key: string): Promise&lt;string | null&gt;; }</code></pre>
            
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6d9euawkfvZmWDJeIRw0Yn/b0a19f0287fc55c2b869b0ee56c71a81/image1-64.png" />
            
            </figure><p>Whilst the auto-generated types <i>correctly</i> describe the JavaScript interface of Workers runtime APIs, TypeScript provides additional features we can use to provide <i>higher-fidelity</i> types and improve developer ergonomics. Our system allows us to handwrite partial TypeScript “overrides” that get merged with the auto-generated types. This enables us to…</p><ul><li><p>Add type parameters (generics) to types such as <a href="https://github.com/cloudflare/workerd/blob/aad867dfbaf6293fce9af70e08f82e1aa07dbdd5/src/workerd/api/streams/readable.h#L300-L318"><code>ReadableStream</code></a> and avoid <code>any</code> typed values.</p></li><li><p>Specify the correspondence between input and output types with method overloads. For example, <a href="https://github.com/cloudflare/workerd/blob/aad867dfbaf6293fce9af70e08f82e1aa07dbdd5/src/workerd/api/kv.h#L117-L125"><code>KVNamespace#get()</code></a> should return a <code>string</code> when the <code>type</code> argument is <code>text</code>, but <code>ArrayBuffer</code> when it’s <code>arrayBuffer</code>.</p></li><li><p>Rename types to match TypeScript standards and reduce verbosity.</p></li><li><p>Fully-replace a type for more accurate declarations. For example, we replace <a href="https://github.com/cloudflare/workerd/blob/aad867dfbaf6293fce9af70e08f82e1aa07dbdd5/src/workerd/api/web-socket.h#L384-L406"><code>WebSocketPair</code></a> with a <code>const</code> declaration for better types with <code>Object.values()</code>.</p></li><li><p>Provide types for values that are internally untyped such as the <code>Request#cf</code> object.</p></li><li><p>Hide internal types that aren’t usable in your workers.</p></li></ul><p>Previously, these overrides were defined in separate TypeScript files to the C++ declarations they were overriding. This meant they often fell out-of-sync with the original declarations. In the new system, overrides are defined alongside the originals with C++ macros, meaning they can be reviewed alongside runtime implementation changes. See the <a href="https://github.com/cloudflare/workerd/blob/aad867dfbaf6293fce9af70e08f82e1aa07dbdd5/src/workerd/jsg/README.md#typescript">README for <code>workerd</code>’s JavaScript glue code</a> for many more details and examples.</p>
    <div>
      <h3>Try typing with workers-types today!</h3>
      <a href="#try-typing-with-workers-types-today">
        
      </a>
    </div>
    <p>We encourage you to upgrade to the latest version of <code>@cloudflare/workers-types</code> with <code>npm install --save-dev @cloudflare/workers-types@latest</code>, and try out the new <code>wrangler types</code> command. We’ll be publishing a new version of the types with each <code>workerd</code> release. Let us know what you think on the <a href="https://discord.gg/cloudflaredev">Cloudflare Developers Discord</a>, and please <a href="https://github.com/cloudflare/workerd/issues/new">open a GitHub issue</a> if you find any types that could be improved.</p> ]]></content:encoded>
            <category><![CDATA[Developer Week]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Wrangler]]></category>
            <guid isPermaLink="false">7eNVYoR4NxTj3mypa2LM7U</guid>
            <dc:creator>Brendan Coll</dc:creator>
        </item>
        <item>
            <title><![CDATA[Get started with Cloudflare Workers with ready-made templates]]></title>
            <link>https://blog.cloudflare.com/cloudflare-workers-templates/</link>
            <pubDate>Tue, 15 Nov 2022 14:00:00 GMT</pubDate>
            <description><![CDATA[ Today, we’re excited to share a collection of ready-made templates to help you build your next application on Cloudflare Workers ]]></description>
            <content:encoded><![CDATA[ 
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7mcyGMehbK3CHWrn4SVbYc/8667083e5fa68f72bcf2a6f871efd8fb/image1-30.png" />
            
            </figure><p>One of the things we prioritize at Cloudflare is enabling developers to build their applications on our developer platform with ease. We’re excited to share a collection of ready-made templates that’ll help you start building your next application on Workers. We want developers to get started as quickly as possible, so that they can focus on building and innovating and avoid spending so much time configuring and setting up their projects.</p>
    <div>
      <h3>Introducing <a href="https://workers.new/templates">Cloudflare Workers Templates</a></h3>
      <a href="#introducing">
        
      </a>
    </div>
    <p><a href="https://workers.cloudflare.com/">Cloudflare Workers</a> enables you to build applications with exceptional performance, reliability, and scale. We are excited to share a collection of templates that helps you get started quickly and give you an idea of what is possible to build on our developer platform.</p><p>We have made available a set of starter templates highlighting different use cases of Workers. We understand that you have different ideas you will love to build on top of Workers and you may have questions or wonder if it is possible. These sets of templates go beyond the convention ‘Hello, World’ starter. They’ll help shape your idea of what kind of applications you can build with Workers as well as other products in the Cloudflare Developer Ecosystem.</p><p>We are excited to introduce a new collection of starter templates <a href="https://workers.new/templates">workers.new/templates</a>. This shortcut will serve you a collection of templates that you can immediately start using to build your next application.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5jEO1oooCk1wae8CfqkiKP/8cd2f203ec83c3b48f446ff4324e4918/1-3.png" />
            
            </figure><p>Cloudflare Workers Template Collection</p>
    <div>
      <h3>How to use Cloudflare Workers templates</h3>
      <a href="#how-to-use-cloudflare-workers-templates">
        
      </a>
    </div>
    <p>We created this collection of templates to support you in getting started with Workers. Some examples listed showcase a use-case with a combination of multiple Cloudflare developer platform products to build applications similar to ones you might use every day. We know that Workers are being used today for different use-cases, we want to showcase some of them to you.</p><p>We have templates for building an <a href="https://github.com/cloudflare/templates/tree/main/pages-image-sharing">image sharing website with Pages Functions</a>, <a href="https://github.com/cloudflare/templates/tree/main/stream/upload/direct-creator-uploads">direct creator upload to Cloudflare Stream</a>, <a href="https://github.com/cloudflare/templates/tree/main/worker-example-request-scheduler">Durable Object-powered request scheduler</a> and many more.</p><p>One example to highlight is a template that lets you accept payment for video content. It is powered by <a href="https://developers.cloudflare.com/pages/platform/functions/">Pages Functions</a>, <a href="https://www.cloudflare.com/products/cloudflare-stream/">Cloudflare Stream</a> and <a href="https://stripe.com/en-gb-nl/payments/checkout">Stripe Checkout</a>.  This app shows how you can use Cloudflare Workers with external payment and authentication systems to create a logged-in experience, without ever having to manage a database or persist any state yourself.</p><p>Once a user has paid, Stripe Checkout redirects to a URL that verifies a token from Stripe, and generates a <a href="https://developers.cloudflare.com/stream/viewing-videos/securing-your-stream/">signed URL</a> using Cloudflare Stream to view the video. This signed URL is only valid for a specified amount of time, and access can be restricted by country or IP address.</p><p>To use the template, you need to either click the deploy with Workers button or open the template with Stackblitz.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7kuOBGeAbjC8nqlBCYRq67/348194b08a7f8985619c5fad7f0f3d8c/image4-11.png" />
            
            </figure><p>The <i>Deploy with Workers</i> button will redirect you to a page where you can authorize GitHub to deploy a fork of the repository using GitHub actions while opening with StackBlitz creates a new fork of the template for you to start working with.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5JEDKuhUdxfJ5nMjSyPEKm/7f73f1b7175825ad544da1ec975268f3/image2-25.png" />
            
            </figure><p>Deploy to Workers Demo</p><p>These templates also comes bundled with additional features I would like to share with you:</p>
    <div>
      <h3>Integrated <a href="https://developers.cloudflare.com/workers/platform/deploy-button/#:~:text=Deploy%20buttons%20let%20you%20deploy,make%20sharing%20your%20work%20easier.">Deploy with Workers</a> Button</h3>
      <a href="#integrated-button">
        
      </a>
    </div>
    <p>We added a deploy button to all templates listed in the <a href="https://github.com/cloudflare/templates">templates repository</a> and the <a href="https://workers.new/templates">collection website</a>, so you can quickly get up to speed with your code. The deploy with Workers button lets you deploy your code in under five minutes, it uses a <a href="https://github.com/marketplace/actions/deploy-to-cloudflare-workers-with-wrangler">GitHub action</a> powered with Cloudflare Workers to do this.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7kkLQ4b0wvl1V7u7CndQ2d/23a6f6d2374800b1496a1b684dbaf166/image3-19.png" />
            
            </figure><p>GitHub Repository with Deploy to Workers Button</p>
    <div>
      <h3>Support for Test Driven Development</h3>
      <a href="#support-for-test-driven-development">
        
      </a>
    </div>
    <p>As developers, we need to write tests for our code to ensure we’re shipping quality production grade software and also ensure that our code is bug-free. We support writing tests in Workers using the Wrangler <a href="https://developers.cloudflare.com/workers/wrangler/api/"><i>unstable_dev</i></a> API to write integration and end-to-end tests. We want to enable not just the developer experience but also nudge developers to follow best practices and prioritize TDD in development. We configured a number of templates to support integration tests against a local server, this will serve as a template to help you set up tests in your projects.</p><p>Here’s an example using Wrangler’s <a href="https://developers.cloudflare.com/workers/wrangler/api/#unstable_dev">unstable_dev</a> API and <a href="https://vitest.dev/">Vitest</a> test framework to test the code written in an example ‘Hello worker’ starter template:</p>
            <pre><code>import { unstable_dev } from 'wrangler';
import { describe, expect, it, beforeAll, afterAll } from 'vitest';

describe('Worker', () =&gt; {
 let worker;

 beforeAll(async () =&gt; {
   worker = await unstable_dev('index.js', {}, { disableExperimentalWarning: true });
 });

 afterAll(async () =&gt; {
   await worker.stop();
 });

 it('should return Hello worker!', async () =&gt; {
   const resp = await worker.fetch();
   if (resp) {
     const text = await resp.text();
     expect(text).toMatchInlineSnapshot(`"Hello worker!"`);
   }
 });
});</code></pre>
            
    <div>
      <h3>Online IDE Integration with StackBlitz</h3>
      <a href="#online-ide-integration-with-stackblitz">
        
      </a>
    </div>
    <p>We announced <a href="/cloudflare-stackblitz-partnership/">StackBlitz’s partnership with Cloudflare Workers</a> during Platform Week early this year. We believe a developer’s experience should be of utmost priority because we want them to build with ease on our developer platform.</p><p>StackBlitz is an online development platform for building web applications. It is powered by <a href="https://blog.stackblitz.com/posts/introducing-webcontainers/">WebContainers</a>, the first WebAssembly-based operating system which boots Node.js environments in milliseconds, securely within your browser tab.</p><p>We made it even easier to get started with Workers with an integrated <b><i>Open with StackBlitz</i></b> button for each starter template, making it easier to create a fork of a template and the great thing is you only need a web browser to build your application.</p><div></div><p>Everything we’ve highlighted in this post, all leads to one thing - <i>How can we create a better experience for developers getting started with Workers</i>. We introduce these ready-made templates to make you more efficient, bring you a wholesome developer experience and help improve your time to deployment. We want you to spend less time getting started with building on the Workers developer platform, so what are you waiting for?</p>
    <div>
      <h3>Next Steps</h3>
      <a href="#next-steps">
        
      </a>
    </div>
    <p>You can start building your own Worker today using the <a href="https://workers.new/template">available templates</a> provided in the templates collection to help you get started. If you would like to contribute your own templates to the collection, be sure to <a href="https://github.com/cloudflare/templates">send in a pull request</a> we’re more than happy to review and add to the growing collection. Share what you have built with us in the <i>#builtwith</i> channel on our Discord community. Make sure to follow us on <a href="https://twitter.com/cloudflaredev">Twitter</a> or join <a href="https://discord.gg/cloudflaredev">our Discord</a> Developers Community server.</p> ]]></content:encoded>
            <category><![CDATA[Developer Week]]></category>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[Wrangler]]></category>
            <category><![CDATA[Cloudflare Stream]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Video]]></category>
            <category><![CDATA[Developer Platform]]></category>
            <guid isPermaLink="false">2FW0xuk7RWElCGndiI6nAu</guid>
            <dc:creator>Gift Egwuenu</dc:creator>
        </item>
        <item>
            <title><![CDATA[Introducing Direct Uploads for Cloudflare Pages]]></title>
            <link>https://blog.cloudflare.com/cloudflare-pages-direct-uploads/</link>
            <pubDate>Tue, 10 May 2022 13:01:06 GMT</pubDate>
            <description><![CDATA[ Pages now supports direct uploads to give you more power to build and iterate how you want and with the tools you want ]]></description>
            <content:encoded><![CDATA[ <p></p><p>With Pages, we are constantly looking for ways to improve the developer experience. One of the areas we are keen to focus on is removing any barriers to entry for our users regardless of their use case or existing set up. Pages is an all-in-one solution with an automated Continuous Integration (CI) pipeline to help you build and deploy your site with one commit to your projects’ repositories hosted on GitHub or GitLab.</p><p>However, we realize that this excluded repositories that used a source control provider that Pages didn’t yet support and required varying build complexities. Even though Pages continues to build first-class integrations – for example, we <a href="/cloudflare-pages-partners-with-gitlab/">added GitLab support</a> in November 2021 – there are numerous providers to choose from, some of which use `git` alternatives like <a href="https://subversion.apache.org/">SVN</a> or <a href="https://www.mercurial-scm.org/">Mercurial</a> for their version control systems. It’s also common for larger companies to self-host their project repositories, guarded by a mix of custom authentication and/or proxy protocols.</p><p>Pages needed a solution that worked regardless of the repository’s source location and accommodate build project’s complexity. Today, we’re thrilled to announce that Pages now supports direct uploads to give you more power to build and iterate how you want and with the tools you want.</p>
    <div>
      <h2>What are direct uploads?</h2>
      <a href="#what-are-direct-uploads">
        
      </a>
    </div>
    <p>Direct uploads enable you to push your build artifacts directly to Pages, side-stepping the automatic, done-for-you CI pipeline that Pages provides for GitHub and GitLab repositories. This means that connecting a Pages project to a git repository is optional. In fact, using git or any version control system is optional!</p><p>Today, you can bring your assets directly to Pages by dragging and dropping them into our dashboard or pushing them through Wrangler CLI. You also have the power to use your own CI tool whether that’s something like <a href="http://developers.cloudflare.com/pages/how-to/use-direct-upload-with-continuous-integration/">GitHub Actions or CircleCI</a> to handle your build. Taking your output directory you can bring these files directly to Pages to create a new project and all subsequent deployments after that. Every deployment will be distributed right to the Cloudflare network within seconds.</p>
    <div>
      <h2>How does it work?</h2>
      <a href="#how-does-it-work">
        
      </a>
    </div>
    <p>After using your preferred CI tooling outside of Pages, there are two ways to bring your pre-built assets and create a project with the direct uploads feature:</p><ol><li><p>Use the Wrangler CLI</p></li><li><p>Drag and drop them into the Pages interface</p></li></ol>
    <div>
      <h3>Wrangler CLI</h3>
      <a href="#wrangler-cli">
        
      </a>
    </div>
    <p>With an estimated 43k weekly Wrangler downloads, you too can use it to iterate quickly on your Pages projects right through the command line. With Wrangler (now with brand-new <a href="/10-things-I-love-about-wrangler">updates</a>!), you can both create your project and new deployments with a single command.</p><p>After Wrangler is installed and authenticated with your Cloudflare account, you can execute the following command to get your site up and running:</p>
            <pre><code>npx wrangler pages publish &lt;directory&gt;</code></pre>
            <div></div>
<p></p><p>Integration with Wrangler provides not only a great way to publish changes in a fast and consecutive manner, but also enables a seamless workflow between CI tooling for building right to Pages for deployment. Check out our tutorials on using <a href="http://developers.cloudflare.com/pages/how-to/use-direct-upload-with-continuous-integration/">CircleCI and GitHub Actions</a> with Pages!</p>
    <div>
      <h3>Drag and drop</h3>
      <a href="#drag-and-drop">
        
      </a>
    </div>
    <p>However, we realize that sometimes you just want to get your site deployed instantaneously without any additional set up or installations. In fact, getting started with Pages shouldn’t have to require extensive configuration. The drag and drop feature allows you to take your pre-built assets and virtually drag them onto the Pages UI. With either a zip file or a single folder of assets, you can watch your project deploy in just a few short seconds straight to the 270+ cities in our network.</p><div></div>
<p></p>
    <div>
      <h2>What can you build?</h2>
      <a href="#what-can-you-build">
        
      </a>
    </div>
    <p>With this ease of deploying projects, the possibilities of what you can build are still endless. You can enjoy the fruits of Pages in a project created with direct uploads including but not limited to unique preview URLs, integration with Workers, Access and Web Analytics, and custom redirects/headers.</p><p>In thinking about your developer setup, direct uploads provide the flexibility to build the way you want such as:</p><ul><li><p>Designing and building your own CI workflow</p></li><li><p>Utilizing the CI tooling of your choice</p></li><li><p>Accommodating complex monorepo structures</p></li><li><p>Implementing custom CI logic for your builds.</p></li></ul>
    <div>
      <h2>Migrating from Workers Sites</h2>
      <a href="#migrating-from-workers-sites">
        
      </a>
    </div>
    <p>We’ll have to admit, the idea of publishing assets directly to our network came from a sister product to Pages called <a href="/workers-sites/">Workers Sites</a> and the resemblance is striking! However, Pages affords many feature enhancements to the developer experience that show as a pain point on Workers Sites.</p><p>With Pages direct uploads, you can enjoy the freedom and flexibility of customizing your workflow that Workers Sites provides while including an interface to track and share changes and manage production/preview environments. <a href="https://developers.cloudflare.com/pages/migrations/migrating-from-workers/">Check out our tutorial</a> on how to migrate over from Workers Sites.</p><p>This release immediately unlocks a broad range of use cases, allowing the most basic of projects to the most advanced to start deploying their websites to Pages today. Refer to our <a href="https://developers.cloudflare.com/pages/platform/direct-upload/">developer documentation</a> for more technical details. As always, head over to the <a href="https://discord.gg/cloudflaredev">Cloudflare Developers Discord</a> server and let us know what you think in the #direct-uploads-beta channel.</p>
    <div>
      <h2>Join us at Cloudflare Connect!</h2>
      <a href="#join-us-at-cloudflare-connect">
        
      </a>
    </div>
    <p>Calling all New York City developers! If you’re interested in learning more about Cloudflare Pages, join us for a series of workshops on how to build a full stack application on Thursday, May 12th. Follow along with demonstrations of using Pages alongside other products like Workers, Images and Cloudflare Gateway, and hear directly from our product managers. <a href="https://events.www.cloudflare.com/flow/cloudflare/connect2022nyc/landing/page/page">Register now</a>!</p> ]]></content:encoded>
            <category><![CDATA[Platform Week]]></category>
            <category><![CDATA[Cloudflare Pages]]></category>
            <category><![CDATA[Product News]]></category>
            <category><![CDATA[Serverless]]></category>
            <category><![CDATA[Wrangler]]></category>
            <guid isPermaLink="false">54zX3KuZvT6IeXghtXaDt6</guid>
            <dc:creator>Nevi Shah</dc:creator>
            <dc:creator>Greg Brimble</dc:creator>
            <dc:creator>John Fawcett</dc:creator>
            <dc:creator>Sid Chatterjee</dc:creator>
        </item>
        <item>
            <title><![CDATA[10 things I love about Wrangler v2.0]]></title>
            <link>https://blog.cloudflare.com/10-things-i-love-about-wrangler/</link>
            <pubDate>Mon, 09 May 2022 13:00:07 GMT</pubDate>
            <description><![CDATA[ We are proud to announce that Wrangler goes public today for general usage, and can’t wait to see what people build with it ]]></description>
            <content:encoded><![CDATA[ <p></p><p>Last November, <a href="/wrangler-v2-beta/">we announced</a> the beta release of a full rewrite of Wrangler, our CLI for building Cloudflare Workers. Since then, we’ve been working round the clock to make sure it's feature complete, bug-free, and easy to use. We are proud to announce that Wrangler goes public today for general usage, and can’t wait to see what people build with it!</p><p>Rewrites can be scary. Our goal for this version of Wrangler was backward compatibility with the original version, while significantly improving the developer experience. I'd like to take this opportunity to present 10 reasons why you should upgrade to the new Wrangler!</p>
    <div>
      <h3>1. It's simpler to install:</h3>
      <a href="#1-its-simpler-to-install">
        
      </a>
    </div>
    
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2iw5RCJVagbVV6ME253GWC/fe280e63ee2fcf7c18fdfaedd83ae0be/image7-1.png" />
            
            </figure><p><i>A simpler way to get started.</i></p><p>Previously, folks would have to install <code>@cloudflare/wrangler</code> globally on a system. This made it hard to use different versions of Wrangler across projects. Further, it was hard to install on some CI systems because of lack of access to a user's root folder.  Sometimes, folks would forget to add the <code>@cloudflare</code> scope when installing, confusing them when a completely unrelated package was installed and didn't work as expected.</p><p>Let's fix that. We've simplified this by now publishing to the <code>wrangler</code> package, so you can run <code>npm install wrangler</code> and it works as expected. You can also install it locally to a project's <code>package.json</code>, like any other regular npm package. It also works across a much broader range of CPU architectures and operating systems, so you can use it on more machines.</p><p>This makes it a lot more convenient when starting. But why stop there?</p>
    <div>
      <h3>2. Zero config startup:</h3>
      <a href="#2-zero-config-startup">
        
      </a>
    </div>
    
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6Ws2aTtoakQ32HRr61DSn1/e72267324fadc0f664c8a7860d18e493/image1-13.png" />
            
            </figure><p><i>Get started with zero configuration</i></p><p>It's now much simpler to get started with a new project. Previously, you would have to create a <code>wrangler.toml</code> configuration file, and fill it in with details about your cloudflare account, how the project was structured, setting up a custom build process and so on. We heard feedback from many of you who would get frustrated during this step, and how it would take many minutes before you could get to developing a simple Worker.</p><p>Let's fix that. You no longer need to create a configuration file when starting, and none of the fields are mandatory. Wrangler infers details about your account and project as you start developing, and you can add configuration incrementally when you need to.</p><p>In fact, you don't even need to install Wrangler to start! You can create a Worker (say, as <code>index.js</code>) and use <code>npx</code> (a utility that comes installed with <code>node.js</code>) to fetch Wrangler from the npm registry and start developing immediately!</p><div></div>
<p></p><p>This is great for extremely simple Workers, but why stop there?</p>
    <div>
      <h3>3. <code>wrangler init my-worker -y</code>, one liner to set up a full project:</h3>
      <a href="#3-wrangler-init-my-worker-y-one-liner-to-set-up-a-full-project">
        
      </a>
    </div>
    <p>We noticed users would struggle to set up a project with Wrangler, even after they'd installed Wrangler and configured <code>wrangler.toml</code>. Most users want to set up a <code>package.json</code>, commonly use <code>typescript</code> to write code, and set up <code>git</code> to track changes in this project. So, we expanded the <code>wrangler init &lt;project name&gt;</code> command to set up a production grade project. You can optionally choose to use <code>typescript</code>, install the official type definitions for Workers, and use <code>git</code> to track changes.</p><p>My favorite trick here is to pass <code>-y</code> to accept all questions without asking. Try running <code>npx wrangler init my-worker -y</code> in your terminal today!</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4L7voFxn3ddNCdIoUgMqas/73cf4dc0ccf428e1dfc170c03055376a/image5-1.png" />
            
            </figure><p><i>One line to set up a full Workers project</i></p>
    <div>
      <h3>4. <code>--local</code> mode:</h3>
      <a href="#4-local-mode">
        
      </a>
    </div>
    <p>Wrangler typically runs a development server on our global network, setting up a local proxy when developing, so you can develop against a "real" environment in the cloud. This is great for making sure the code you develop will behave the same in development, and after you deploy it to production. The trade-off here is it's harder to develop code when you have a bad Internet connection, or if you're running tests on a CI machine. It's also marginally slower to iterate while coding. Users have asked us for a long time to be able to 'run' their code locally on their machines, so that they can iterate quickly and run tests in environments like CI.</p><p>Wrangler now lets you develop on your machine by simply calling <code>wrangler dev --local</code>, and no additional configuration. This is powered by <a href="https://miniflare.dev">Miniflare</a>, a fully featured simulator of the Cloudflare Workers runtime. You can even toggle across 'edge' and 'local' modes by tapping the 'L' hotkey when developing; however you prefer!</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3zC0yCCFhNhagjbOWfwITV/f050f23608405a71d4d6055fa4ee2209/image2-4.png" />
            
            </figure><p><i>Local mode, powered by Miniflare.</i></p>
    <div>
      <h3>5. Tail any Worker, any time:</h3>
      <a href="#5-tail-any-worker-any-time">
        
      </a>
    </div>
    
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6zCLJukTN9Uc4DFpdUmm51/393f31ed3cc88b16c3de2b503f1e5245/image6-4.png" />
            
            </figure><p><i>Tail your logs anywhere, anytime.</i> </p><p>It's useful to be able to "tail" a Worker's output to a terminal, and see what's going on in real time. While you can already view these logs in the Workers dashboard, some people are more comfortable seeing the logs in their terminal, and then slicing and dicing to debug any issues that may be occuring. Previously, you would have to checkout a Worker's repository locally, install dependencies, and then call <code>wrangler tail</code> in the project folder. This was clearly cumbersome, and relied on developer expertise to see something as simple as a Worker's logs.</p><p>Now you can simply call <code>npx wrangler tail &lt;worker name&gt;</code> in your terminal, without any configuration or setup, and immediately see the logs that you expect. We use this ourselves to quickly inspect our production Workers and see what's going on inside them!</p>
    <div>
      <h3>6. Better warnings and errors, everywhere:</h3>
      <a href="#6-better-warnings-and-errors-everywhere">
        
      </a>
    </div>
    <p>One of the worst feelings a developer can face is being presented with an error when writing code, and not knowing how to fix it and proceed. We heard feedback from many of you who were frustrated with the lack of error messages, and how you would spend hours trying to figure out what went wrong. We've now added new error and warning messages, so you can easily spot the problems in your code. When possible, we also include steps you can follow to fix your Worker, including things that you can simply copy and paste! This makes Wrangler much more friendly to use, and we promise the experience will only get better.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4vKCpjFLpx71tU1eTJEMl5/a696f5d0971f65cd1db8b7479ecf0787/image3-3.png" />
            
            </figure>
    <div>
      <h3>7. On-demand developer tools for debugging:</h3>
      <a href="#7-on-demand-developer-tools-for-debugging">
        
      </a>
    </div>
    <p>We introduced initial support for debugging Workers in Wrangler <a href="/profiling-your-workers-with-wrangler">in September</a> which enables debugging a Worker directly on our global network. However, getting started with debugging was still a bit cumbersome, because you would have to start Wrangler with an <code>--inspect</code> flag, then open a special page in your browser (<code>chrome://inspect</code>), configuring it to detect Wrangler running on a special port, and then launching the debugger. This would also mean you might have lost any debugging messages that were logged before you opened the Chrome developer tools.</p><p>We fixed this. Now you don't need to pass any special flags when starting up. You can simply hit the <code>D</code> hotkey when developing and a developer tools instance pops up in your browser. And by buffering the messages before you even start up the devtools, you don't lose any logs or errors! You can also use VS Code developer tools to directly hook into your Worker's debugging session!</p>
    <div>
      <h3>8. A modern module system:</h3>
      <a href="#8-a-modern-module-system">
        
      </a>
    </div>
    <p>Modern JavaScript isn't simply about the syntax that the language supports, but also writing code as modules, and leveraging the extremely broad ecosystem of community libraries and frameworks. Previously, Wrangler required that you set up <code>webpack</code> or a custom build with bundlers (like <code>rollup</code>, <code>vite</code>, or <code>esbuild</code>, to name a few) to consume libraries and modules. This introduces a lot of friction, especially when starting a new project and trying out new ideas.</p><p>Now, support for npm modules comes out of the box, with no extra configuration required! You can install any package from the <a href="http://npmjs.com/">npm registry</a>, organize your own code with modules, and it all works as expected. We're also introducing an experimental <code>node.js</code> compatibility mode for using <code>node.js</code> modules that wouldn't previously work without setting up your own polyfills! This means you can use popular frameworks and libraries that you're already familiar with while focusing on delivering value to your users.</p>
    <div>
      <h3>9. Closes many outstanding issues:</h3>
      <a href="#9-closes-many-outstanding-issues">
        
      </a>
    </div>
    <p>A rewrite should be judged not just by the new features that are implemented, but by how many existing issues are resolved. We went through hundreds of outstanding issues and bugs with Wrangler, and are happy to say that we solved almost all of them! Across the board, every command and feature got a facelift, bug fixes, and test coverage to make sure it doesn't break in the future. Developers on using Cloudflare Workers will be glad to hear that simply upgrading Wrangler will immediately fix previous concerns and problems. Which leads us to my absolute favorite feature...</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7o0yX40KcaE8j27F9bya4t/5f0da5100ef84878727629ec96c3dfd5/image9.png" />
            
            </figure>
    <div>
      <h3>10. A commitment to improve:</h3>
      <a href="#10-a-commitment-to-improve">
        
      </a>
    </div>
    
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2RzDQhFclIpVBwnHQEoQ6l/5e3092af38651c6e175c34fa38a6ad61/image8.png" />
            
            </figure><p><i>The effort into building wrangler v2.0, visualised.</i> </p><p>Wrangler has always been special software for us. It represents the primary interface that developers use to interact and use Cloudflare Workers, and we have major plans for the future. We have invested time, effort and resources to make sure Wrangler is the best tool for developers to use, and we're excited to see what the future holds. This is a commitment to our users and community that we will only keep improving on this foundation, and folks can expect their feedback and concerns to be heard loud and clear.</p> ]]></content:encoded>
            <category><![CDATA[Platform Week]]></category>
            <category><![CDATA[Wrangler]]></category>
            <category><![CDATA[Developers]]></category>
            <guid isPermaLink="false">37mGbexsYqNbE5dmM4vMLX</guid>
            <dc:creator>Sunil Pai</dc:creator>
        </item>
        <item>
            <title><![CDATA[wrangler 2.0 — a new developer experience for Cloudflare Workers]]></title>
            <link>https://blog.cloudflare.com/wrangler-v2-beta/</link>
            <pubDate>Tue, 16 Nov 2021 13:59:22 GMT</pubDate>
            <description><![CDATA[ We're excited to announce the second-generation of our developer tooling for Cloudflare Workers. It’s a new developer experience that’s out-of-the-box, lightning fast, and can even run Workers on a local machine. (Yes!) ]]></description>
            <content:encoded><![CDATA[ <p></p><p>Much of a developer’s work is about making trade-offs: consistency versus availability, speed over correctness, you name it. While there will always be different technical trade-offs to consider, we believe there are some that you, as a developer, should never need to make.</p><p>One of those decisions is an easy-to-use development environment. Whether you’re onboarding a new developer to your team or you simply want to develop faster, it’s important that even the smallest of things are optimized for speed and simplicity.</p><p>That’s why we're excited to announce the second-generation of our developer tooling for Cloudflare Workers. It’s a new developer experience that’s out-of-the-box, lightning fast, and can even run Workers on a local machine. (Yes!)</p><p>If you’re already familiar with our existing tools, we’re not just talking about the wrangler CLI, we’re talking about its next major release: wrangler 2.0. Stick around to get a sneak-peak at the new experience.</p>
    <div>
      <h3>No config? No problem</h3>
      <a href="#no-config-no-problem">
        
      </a>
    </div>
    <p>We’ve made it much easier to get started with Cloudflare Workers. All you need is a single JavaScript file to run a Worker -- no configuration needed. You don't even need to decide on a name!</p><p>When you run <code>wrangler dev &lt;filename&gt;</code>, your code is automatically bundled and deployed to a development environment. Then, you can send HTTP requests to that environment using a localhost proxy. Here’s what that looks like in-action:</p><div></div>
    <div>
      <h3>Live debugging, just like that</h3>
      <a href="#live-debugging-just-like-that">
        
      </a>
    </div>
    <p>Now there’s a completely redesigned experience for debugging a Worker. With a simple command you get access to a remote debugger, the same used by Chrome when you click “Inspect,” which provides an interactive view of logs, exceptions, and requests. It feels like your Worker is running locally, yet it’s actually running on the Cloudflare network.</p><div></div><p>A debugger that “just works” and auto-detects your changes makes <i>all</i> the difference when you’re just trying to code. We’ve also made a number of improvements to make the debugging experience even easier:</p><ul><li><p>Keybind shortcuts, to quickly toggle features or open a window.</p></li><li><p>Support for “--public ”, to automatically serve your static assets.</p></li><li><p>Faster and more reliable file-watching.</p></li></ul><p>To start a debugging session, just run: <code>wrangler dev &lt;filename&gt;</code>, then hit the “D” keybind.</p>
    <div>
      <h3>Local mode? Flip a switch</h3>
      <a href="#local-mode-flip-a-switch">
        
      </a>
    </div>
    <p>Another aspect of the new debugging experience is the ability to switch to “local mode,” which runs your Worker on your local machine. In fact, you can easily switch between “network” and “local” mode with just a keybind shortcut.</p><div></div><p>How does this work? Recently, we announced that <a href="https://github.com/cloudflare/miniflare">Miniflare</a> (created by <a href="https://twitter.com/_mrbbot">Brendan Coll</a>), a project to locally emulate Workers in Node.js, has joined the Cloudflare organization. Miniflare is great for unit testing and situations where you’d like to debug Workers without an Internet connection. Now we’ve integrated it directly into the local development experience, so you can enjoy the benefits of both the network and your localhost!</p>
    <div>
      <h3>Let us know what you think!</h3>
      <a href="#let-us-know-what-you-think">
        
      </a>
    </div>
    <p>Serverless should be simple. We’re really excited about these improvements to the developer experience for Workers, and we have a <i>lot</i> more planned.</p><p>While we’re still working on wrangler 2.0, you can try the beta release by running: <code>npm install wrangler@beta</code> or by visiting the <a href="https://github.com/cloudflare/wranglerv2">repository</a> to see what we’re working on. If you’re already using wrangler to deploy existing applications, we recommend continuing to use wrangler 1.0 until the 2.0 release is officially out. We will continue to develop and maintain wrangler 1.0 until we’re finished with backwards-compatibility for 2.0.</p><p>If you’re starting a project or want to try out the new experience, we’d love to hear your feedback! Let us know what we’re missing or what you’d like to see in wrangler 2.0. You can create a feature request or start a discussion in the <a href="https://github.com/cloudflare/wranglerv2">repository</a>. (we’ll merge them into the existing wrangler repository when 2.0 is out of beta).</p><p>Thank you to all of our developers out there, and we look forward to seeing what you build!</p>
    <div>
      <h3>Watch on Cloudflare TV</h3>
      <a href="#watch-on-cloudflare-tv">
        
      </a>
    </div>
    <div></div><p></p> ]]></content:encoded>
            <category><![CDATA[Full Stack Week]]></category>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Wrangler]]></category>
            <category><![CDATA[Developer Platform]]></category>
            <guid isPermaLink="false">1bz4lkxX4UPI3IDoREY8Ll</guid>
            <dc:creator>Ashcon Partovi</dc:creator>
            <dc:creator>Sunil Pai</dc:creator>
        </item>
        <item>
            <title><![CDATA[Bringing OAuth 2.0 to Wrangler]]></title>
            <link>https://blog.cloudflare.com/wrangler-oauth/</link>
            <pubDate>Thu, 23 Sep 2021 12:59:07 GMT</pubDate>
            <description><![CDATA[ In this blog, we will look into what the OAuth 2.0 protocol is, and how it can help improve the authorization process in the command-line interface tool Wrangler used to manage your Cloudflare Workers. ]]></description>
            <content:encoded><![CDATA[ <p>Over the course of this summer, I had the incredible opportunity to join the Workers Developer Productivity team and help improve the developer experience of Workers. Today, I’ll talk about my project to implement the OAuth 2.0 login protocol for <a href="https://github.com/cloudflare/wrangler">Wrangler</a>, the Workers command line interface (CLI).</p><p>Wrangler needs to be authorized in order to carry out its job. API tokens are one way to authorize Wrangler, but they do not provide the best user experience as the user needs to manually copy and paste their tokens. This is where the OAuth 2.0 protocol comes into play.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6prT6vWuey4xFTsR91Z1ue/87ec6eae381905664e37e8991a7da7f5/image2-32.png" />
            
            </figure>
    <div>
      <h2>Wrangler login and OAuth 2.0</h2>
      <a href="#wrangler-login-and-oauth-2-0">
        
      </a>
    </div>
    <p>Previously, the <code>wrangler login</code> command used <a href="/improving-the-wrangler-startup-experience/">API tokens</a> to authenticate Wrangler. However, managing API tokens can sometimes be cumbersome, since you need to go to the Cloudflare dashboard to create or modify a token. By using OAuth 2.0, we can allow users to directly choose permissions or scopes from Wrangler. OAuth 2.0 helps simplify the login process while making it more secure.</p><p>OAuth 2.0 is an industry-standard protocol for allowing users to authorize applications without having to share a password. In order to understand this protocol, we need to define some terminology:</p><ul><li><p><b><b><b>Resource Owner:</b></b></b> an entity capable of granting access to a protected resource. This is the user.</p></li><li><p><b><b><b>Resource Server:</b></b></b> the server hosting the protected resource. This is the Cloudflare API.</p></li><li><p><b><b><b>Client:</b></b></b> an application making protected resource requests on behalf of the resource owner and with its authorization. This is Wrangler, making API calls on the behalf of the user.</p></li><li><p><b><b><b>Authorization Server:</b></b></b> The server issuing access tokens to the client after successfully authenticating the resource owner and obtaining authorization. This is our OAuth 2.0 service provider.</p></li></ul><p>The protocol has several flows, but they all share the same objective. The resource owner needs to explicitly grant permission to the client, which can then receive an access token from the authorization server. With this access token, the client is authorized to access protected resources stored on the resource server.</p>
    <div>
      <h3>Authorization Code Flow</h3>
      <a href="#authorization-code-flow">
        
      </a>
    </div>
    <p>Among the different types of flows that make up the OAuth 2.0 protocol, Wrangler implements the Authorization Code Flow with PKCE challenges. Let’s take a look at what this entails!</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6vlJMwWGD9MD4xuLYUBiLi/f4a044f5e8e8086ef605a2afa032ce58/image1-28.png" />
            
            </figure><p>When running <code>wrangler login</code>, the user is first prompted to log in to the Cloudflare dashboard. Once they are logged in, they are redirected to an authorization page, where they can decide to grant or deny authorization to Wrangler. If authorization is granted, Wrangler receives an authorization grant from the OAuth service provider. Once received, Wrangler exchanges the authorization grant for an access token and a refresh token. At this point, Wrangler stores both of these tokens on disk and uses the access token to make authorized API calls. Since the access token is short-lived, refresh tokens are used to update an expired access token. Throughout this flow, Wrangler and the OAuth service provider also use additional measures to verify the identity of each other, as later described in the Security section of this blog.</p><div></div>
<p></p>
    <div>
      <h3>Use what you need, only when you need it</h3>
      <a href="#use-what-you-need-only-when-you-need-it">
        
      </a>
    </div>
    <p>In addition to providing a smoother developer experience, the new <code>wrangler login</code> also allows a user to specify which scopes they need. For example, if you would like to have an OAuth token with just account and user read permissions, you can do so by running:</p>
            <pre><code>wrangler login --scopes account:read user:read</code></pre>
            <p>For more information about the currently available scopes, you can run <code>wrangler login --scopes-list</code> or visit the Wrangler login <a href="https://developers.cloudflare.com/workers/cli-wrangler/commands#login">documentation</a>.</p>
    <div>
      <h3>Revoke access at any time</h3>
      <a href="#revoke-access-at-any-time">
        
      </a>
    </div>
    <p>The OAuth 2.0 protocol also defines a flow to revoke authorization from Wrangler. In this workflow, a user can deny Wrangler access to protected resources by simply using the command <code>wrangler logout</code>. This command will make a request to the OAuth 2.0 service provider and invalidate the refresh token, which will automatically invalidate the associated access token.</p>
    <div>
      <h2>Security</h2>
      <a href="#security">
        
      </a>
    </div>
    <p>The OAuth integration also brings improved security by using Cross-Site Request Forgery (CSRF) states, Proof Key for Code Exchange (PKCE) challenges, and short-lived access tokens.</p><p>Throughout the first part of the <code>wrangler login</code> flow, Wrangler needs to request an authorization grant. In order to avoid the possibility of a forged response, Wrangler includes a CSRF state in the parameters of the authorization code request. The CSRF state is a unique randomly generated value, which is used to confirm the response received from the OAuth service provider. In addition to the CSRF state, Wrangler will also include a PKCE <code>code_challenge</code>. This <code>code_challenge</code> will be used by the OAuth service provider to verify that Wrangler is the same application when exchanging the authorization grant for an access token. The PKCE challenge is a protection against stolen authorization grants. As the OAuth service provider will reject access token requests if it cannot verify the PKCE <code>code_challenge</code>.</p><p>The final way the new OAuth workflow improves security is by making access tokens short-lived. In this sense, if an access token gets stolen, how can we notify the resource server that the access token should not be trusted? Well, we can’t really. So, there are three options: 1) wait until the expiration time; 2) use the refresh token to get a new access token, which invalidates the previous access token; or 3) invalidate both refresh and access tokens. This provides us with three ways to protect resources from bad actors with stolen access tokens.</p>
    <div>
      <h2>What’s next</h2>
      <a href="#whats-next">
        
      </a>
    </div>
    <p>OAuth 2.0 integration is now available in the 1.19.3 version release of <a href="https://github.com/cloudflare/wrangler">Wrangler</a>. Try it out and let us know your experience. If you prefer the API tokens or global API keys, no worries. You can still access them using the <a href="https://developers.cloudflare.com/workers/cli-wrangler/commands#config"><code>wrangler config</code></a> command.</p><p>I would also like to thank the Workers team and other Cloudflare teams for the incredible internship experience. This opportunity gave me a glimpse into what industry software development looks like, and the opportunity to dive deep into a meaningful project. I enjoyed the responsiveness and teamwork during the internship, making this a great summer.</p> ]]></content:encoded>
            <category><![CDATA[Wrangler]]></category>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[Serverless]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Developer Platform]]></category>
            <guid isPermaLink="false">1o4lGmSFlwdyOAv24Hl4ua</guid>
            <dc:creator>Mengqi Chen</dc:creator>
        </item>
        <item>
            <title><![CDATA[Profiling Your Workers with Wrangler]]></title>
            <link>https://blog.cloudflare.com/profiling-your-workers-with-wrangler/</link>
            <pubDate>Sat, 18 Sep 2021 12:59:17 GMT</pubDate>
            <description><![CDATA[ To help measure performance of our customers’ Workers, we’re beginning to integrate with the Chrome DevTools protocol. ]]></description>
            <content:encoded><![CDATA[ <p></p><p>In the year since Cloudflare’s launch of Workers Unbound, developers have unlocked the ability to run computationally intensive workloads on the Cloudflare edge network — like image processing, game logic, and other complex algorithms. With all that additional computing power comes a host of questions around performance. Our customers often ask us how they can profile or monitor their Workers to see where they spend the most CPU time, or to see whether their changes improve performance.</p><p>Here at Cloudflare, we not only want to build the fastest, most affordable, and most flexible compute platform at the edge; we also want to make the lives of our developers easier in building their applications. To do this, Cloudflare has begun to integrate with existing tools — places our developers feel comfortable and efficient in their day-to-day work. To help measure performance of our customers’ Workers, we’re beginning to integrate with the Chrome DevTools protocol. Just like you can use chrome://inspect to debug your Node backend, you can also use it to profile your Cloudflare Workers.</p>
    <div>
      <h3>Introducing Chrome DevTools Integration (Beta)</h3>
      <a href="#introducing-chrome-devtools-integration-beta">
        
      </a>
    </div>
    <p>We’re starting off this integration with beta support for local CPU profiling, using Wrangler. To show off how to use this feature, I’m going to be optimizing a simple JavaScript program which outputs the first thousand integers separated by a space. Let’s start by installing the latest version of <a href="https://github.com/cloudflare/wrangler/#installation">Wrangler</a>. We’ll also need a Worker cloned down to your local machine. I’ll be using <a href="https://github.com/kabirsikand/workers-profiling-example/blob/main/slow-worker.js">Workers Profiling Example</a>, but feel free to use any CPU intensive Worker for this tutorial.</p><p>For reference, my sample code is below. You’ll notice this code is intentionally performing a computation that will slow down our Worker.</p>
            <pre><code>addEventListener("fetch", event =&gt; {
  event.respondWith(handleRequest(event.request));
});

async function handleRequest(request) {
  let body = '';
  for (let i = 0; i &lt; 1000; ++i) {
    body = body + ' ' + i;
  }

  return new Response(body, {
    headers: { 'content-type': 'text/plain' },
  });
}</code></pre>
            <p>To confirm this, we’ll run Chrome DevTools and profile our Worker locally. In the directory of your sample project, <code>run wrangler dev --inspect</code>. To launch the DevTools, open <code>chrome://inspect</code> in Chrome or Chromium. You’ll see Chrome’s DevTools homepage pop up:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/79e6ioOYPp1SjNBLWEhLWK/d910cbfd5f0ee881541d497c60798baf/image1-22.png" />
            
            </figure><p>Click ‘Configure’ and add <code>localhost://9230</code> as one of the targets. You should see <code>wrangler[{Worker name}]</code> appear under “Remote Targets”, where {Worker name} is the name of your project.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5i0wiIOb2mQG9ZPZseyEdk/2b98a89b3e815f9be0583d10fee9e94e/image2-27.png" />
            
            </figure><p>Click ‘inspect’, then in the popup, ‘Profiler’.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2Kc0LIb3k3O1ldfl18jCBP/380c4f36d6b5d97521a2e3b92aad3ddb/image4-21.png" />
            
            </figure><p>Click ‘Start’ and, in a different browser tab, make a few requests to your site, then click ‘Stop’. It should be available locally on localhost:8787.</p><p>Analyze the flame graph. For my Slow Worker, I see the following graph:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4cA7Ng90JMS4Nt6LOOZI0p/28dda2434c4244a9c9ec4c01bc5e9f1b/image3-25.png" />
            
            </figure><p>When I click on <code>handleRequest</code>, I see the following annotated source of my Worker:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2rQDvm2MGfpBNwWgT7nobE/246a004a99f6e3322a8cd4be0e02b6f6/image5-19.png" />
            
            </figure><p>In particular, it shows that, unsurprisingly, most of the time is being spent on memory allocations in the body of the loop. Note that the profiler is not always accurate with regard to exact timing, but does paint a picture of your largest bottlenecks.</p>
    <div>
      <h3>Understanding the Profile</h3>
      <a href="#understanding-the-profile">
        
      </a>
    </div>
    <p>The profiler works by gathering a stack trace of your program at a sampled rate, so remember that the profile is an approximation of where your code tends to spend the majority of its execution time, and is not meant to be perfectly accurate. In fact, functions that execute in less than 100 microseconds have a chance to not appear in the profile at all.</p>
    <div>
      <h3>What’s Next?</h3>
      <a href="#whats-next">
        
      </a>
    </div>
    <p>With the Workers platform, we’re striving to build in the <a href="https://www.cloudflare.com/learning/performance/what-is-observability/">observability</a> our users expect out of a robust compute platform. We’d love to hear more from the community about ways we can improve visibility into the code you’re writing on the edge. If you haven’t already, please join the Cloudflare Workers Discord community at <a href="https://discord.gg/PX8s2TmJ7s">https://discord.gg/PX8s2TmJ7s</a>. Happy building!</p><div></div><p></p> ]]></content:encoded>
            <category><![CDATA[Speed Week]]></category>
            <category><![CDATA[Wrangler]]></category>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Developer Platform]]></category>
            <guid isPermaLink="false">5qfyGhFsuFodg8NQiKq0BX</guid>
            <dc:creator>Joshua Nelson</dc:creator>
            <dc:creator>Kabir Sikand</dc:creator>
        </item>
        <item>
            <title><![CDATA[Introducing logs from the dashboard for Cloudflare Workers]]></title>
            <link>https://blog.cloudflare.com/introducing-workers-dashboard-logs/</link>
            <pubDate>Tue, 24 Aug 2021 14:00:00 GMT</pubDate>
            <description><![CDATA[ Many developers know the feeling: “It worked in the local testing suite, it worked in our staging environment, but… it’s broken in production?” Testing can reduce mistakes and debugging can help find them, but logs give us the tools to understand and improve what we are creating. ]]></description>
            <content:encoded><![CDATA[ 
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2Mixl8Zirzu4SzNfiqgXgm/a7c1855d9797cf5d815d61d4cf53e735/Workers-Observability-Shim-Github-Header.png" />
            
            </figure><p>If you’re writing code: what can go wrong, will go wrong.</p><p>Many developers know the feeling: “It worked in the local testing suite, it worked in our staging environment, but… it’s broken in production?” Testing can reduce mistakes and debugging can help find them, but logs give us the tools to understand and improve what we are creating.</p>
            <pre><code>if (this === undefined) {
  console.log("there’s no way… right?") // Narrator: there was.
}</code></pre>
            <p>While logging can help you understand when the seemingly impossible is actually possible, it’s something that no developer really wants to set up or maintain on their own. That’s why we’re excited to launch a new addition to the Cloudflare Workers platform: logs and exceptions from the dashboard.</p><p>Starting today, you can view and filter the <code>console.log</code> output and exceptions from a Worker… at no additional cost with no configuration needed!</p>
    <div>
      <h3>View logs, just a click away</h3>
      <a href="#view-logs-just-a-click-away">
        
      </a>
    </div>
    <p>When you view a Worker in the dashboard, you’ll now see a “Logs” tab which you can click on to view a detailed stream of logs and exceptions. Here’s what it looks like in action:</p><div></div>
<p></p><p>Each log entry contains an event with a list of logs, exceptions, and request headers if it was triggered by an HTTP request. We also automatically redact sensitive URLs and headers such as Authorization, Cookie, or anything else that appears to have a sensitive name.</p><p>If you are in the Durable Objects <a href="/durable-objects-open-beta/">open beta</a>, you will also be able to view the logs and requests sent to <i>each</i> Durable Object. This is a great tool to help you understand and debug the interactions between your Worker and a Durable Object.</p><p>For now, we support filtering by event status and type. Though, you can expect more filters to be added to the dashboard very soon! Today, we support advanced filtering with the wrangler CLI, which will be discussed later in this blog.</p>
    <div>
      <h3>console.log(), and you’re all set</h3>
      <a href="#console-log-and-youre-all-set">
        
      </a>
    </div>
    <p>It’s really simple to get started with logging for Workers. Simply invoke one of the standard <a href="https://developer.mozilla.org/en-US/docs/Web/API/console">console</a> APIs, such as <code>console.log()</code>, and we handle the rest. That’s it! There’s no extra setup, no configuration needed, and no hidden logging fees.</p>
            <pre><code>function logRequest (request) {
  const { cf, headers } = request
  const { city, region, country, colo, clientTcpRtt  } = cf
  
  console.log("Detected location:", [city, region, country].filter(Boolean).join(", "))
  if (clientTcpRtt) {
     console.debug("Round-trip time from client to", colo, "is", clientTcpRtt, "ms")
  }

  // You can also pass an object, which will be interpreted as JSON.
  // This is great if you want to define your own structured log schema.
  console.log({ headers })
}</code></pre>
            <p>In fact, you don’t even need to use <code>console.log</code> to view an event from the dashboard. If your Worker doesn’t generate any logs or exceptions, you will still be able to see the request headers from the event.</p>
    <div>
      <h3>Advanced filters, from your terminal</h3>
      <a href="#advanced-filters-from-your-terminal">
        
      </a>
    </div>
    <p>If you need more advanced filters you can use <a href="https://github.com/cloudflare/wrangler">wrangler</a>, our command-line tool for deploying Workers. We’ve updated the <code>wrangler tail</code> command to support sampling and a new set of advanced filters. You also no longer need to install or configure <code>cloudflared</code> to use the command. Not to mention it’s <i>much</i> faster, no more waiting around for logs to appear. Here are a few examples:</p>
            <pre><code># Filter by your own IP address, and if there was an uncaught exception.
wrangler tail --format=pretty --ip-address=self --status=error

# Filter by HTTP method, then apply a 10% sampling rate.
wrangler tail --format=pretty --method=GET --sampling-rate=0.1

# Filter using a generic search query.
wrangler tail --format=pretty --search="TypeError"</code></pre>
            <p>We recommend using the “pretty” format, since wrangler will output your logs in a colored, human-readable format. (We’re also working on a similar display for the dashboard.)</p><div></div>
<p></p><p>However, if you want to access structured logs, you can use the “json” format. This is great if you want to pipe your logs to another tool, such as <a href="https://stedolan.github.io/jq/tutorial/">jq</a>, or save them to a file. Here are a few more examples:</p>
            <pre><code># Parses each log event, but only outputs the url.
wrangler tail --format=json | jq .event.request?.url

# You can also specify --once to disconnect the tail after receiving the first log.
# This is useful if you want to run tests in a CI/CD environment.
wrangler tail --format=json --once &gt; event.json</code></pre>
            
    <div>
      <h3>Try it out!</h3>
      <a href="#try-it-out">
        
      </a>
    </div>
    <p>Both logs from the dashboard and <code>wrangler tail</code> are available and free for existing Workers customers. If you would like more information or a step-by-step guide, check out any of the resources below.</p><ul><li><p>Go to the <a href="https://dash.cloudflare.com?to=/:account/workers/overview">dashboard</a> and look at some logs!</p></li><li><p>Read the <a href="https://developers.cloudflare.com/workers/learning/logging-workers">getting started</a> guide for logging.</p></li><li><p>Look at the tail logs API <a href="https://api.cloudflare.com/#worker-tail-logs-properties">reference</a>.</p></li></ul> ]]></content:encoded>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[Logs]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Product News]]></category>
            <category><![CDATA[Dashboard]]></category>
            <category><![CDATA[Wrangler]]></category>
            <guid isPermaLink="false">4YuFI6zhgNP0dnoJv7d0NH</guid>
            <dc:creator>Ashcon Partovi</dc:creator>
        </item>
        <item>
            <title><![CDATA[Introducing workers.new, custom builds, and improved logging for Workers]]></title>
            <link>https://blog.cloudflare.com/workers-new-custom-builds-and-improved-logging/</link>
            <pubDate>Fri, 16 Apr 2021 13:00:00 GMT</pubDate>
            <description><![CDATA[ In the spirit of quickly solving problems, we’re excited to launch three new improvements to the Workers experience, so you can take your next idea and ship it even faster. ]]></description>
            <content:encoded><![CDATA[ <p></p><p>Cloudflare Workers® aims to be the easiest and most powerful platform for developers to build and deploy their applications. With Workers, you can quickly solve problems without having to wonder: “is this going to scale?”</p><p>You write the JavaScript and we handle the rest, from distribution to scaling and concurrency.</p><p>In the spirit of quickly solving problems, we’re excited to launch three new improvements to the Workers experience, so you can take your next idea and ship it even faster.</p>
    <div>
      <h3>Introducing... workers.new</h3>
      <a href="#introducing-workers-new">
        
      </a>
    </div>
    
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6UTg9II2dZ8I5FpUREylkU/a3f3fe46379174ebe33db97fad860f25/unnamed-4.png" />
            
            </figure><p>First, we’re introducing <a href="https://workers.new">https://workers.new</a>, a shortcut that takes you directly to a JavaScript editor for creating a new Worker. Anytime you have a cool idea, need a quick fix to a problem, or just want to debug some JavaScript, you now have a simple way to go from idea to prototype. What’s more is you don’t even need to deploy the Worker to try it out!</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5owqpkMvx9ZvZypSdLbE1Z/083f9e136c9043cf5b54378b64b12357/unnamed-1.gif" />
            
            </figure><p>We’ve also updated the default Worker template to help you go a few steps beyond the typical “Hello, World!”. When you open the editor, you’ll now see a few examples that demonstrate how to redirect requests, modify headers, and parse responses.</p>
    <div>
      <h3>Customize your build scripts</h3>
      <a href="#customize-your-build-scripts">
        
      </a>
    </div>
    
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7luFgXD6s8A1HJw9L2gXPY/34c3c78668b0d4437c51ea22d54f88a8/unnamed--1--2.png" />
            
            </figure><p>For developers who want to deploy more complex applications, like those with external libraries or written in other languages like TypeScript, we recommend using our command-line tool, <a href="https://github.com/cloudflare/wrangler#-wrangler">wrangler</a>.</p><p>Previously, wrangler has supported three project types: JavaScript, Rust, and webpack. By far, we’ve found that webpack is the most widely used among the community, since it has built-in support for bundling npm packages. Yet, as more developers started to use wrangler, they’ve wanted to customize their webpack configurations or even use other JavaScript bundlers.</p><p>That’s why we’re excited to release custom builds for wrangler! Now you can provide wrangler with a custom build script and upload directory, which works with all of the wrangler commands including <code>wrangler dev</code> and <code>wrangler publish</code>.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/71hynCM98BoveG11Ozv8LL/b8c209da0cf2634f7c74ae5036be5f7a/unnamed-5.png" />
            
            </figure><p>This means you can use any JavaScript bundler you want: webpack, Rollup, Parcel, esbuild, and many more! We’ve put together a few templates that you can copy if you want to get started with custom builds. Make sure to <a href="https://developers.cloudflare.com/workers/cli-wrangler/install-update#update">update</a> wrangler to release 1.16 or later and check out our <a href="https://developers.cloudflare.com/workers/cli-wrangler/configuration#build">documentation</a> about custom builds and additional configuration options.</p><ul><li><p><a href="https://github.com/cloudflare/service-worker-custom-build">webpack</a></p></li><li><p><a href="https://github.com/cloudflare/durable-objects-webpack-commonjs">webpack with Durable Objects</a></p></li><li><p><a href="https://github.com/cloudflare/modules-rollup-esm">Rollup</a></p></li><li><p><a href="https://github.com/cloudflare/durable-objects-rollup-esm">Rollup with Durable Objects</a></p></li></ul>
    <div>
      <h3>Viewing logs and exceptions</h3>
      <a href="#viewing-logs-and-exceptions">
        
      </a>
    </div>
    <p>Ever wanted to see the <code>console.log()</code> output or uncaught exceptions from a deployed Worker?</p><p>In case you missed it, <code>wrangler tail</code> allows you to see a live stream of your Worker’s logs and exceptions. Today, we’re improving <code>wrangler tail</code> by making it easier to use and more accessible to developers.</p><p>First, we wanted to improve the terminal output. Previously, <code>wrangler tail</code> would only output log entries as JSON. While this was useful when piping through to tools like <code>jq</code>, it was generally hard to digest. That’s why we created a new “pretty” format that is much easier to read and takes full advantage of your terminal’s color codes.</p>
            <pre><code>$ wrangler tail --format=&lt;json|pretty&gt;</code></pre>
            
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3QeRUqMOW6FfedIi03nLgQ/1e0f669424c6cacaa216c7c149d2eb5c/unnamed--1-.gif" />
            
            </figure><p>If you have suggestions for how we can improve <code>wrangler tail</code>, feel free to pop in the #wrangler channel on the Workers <a href="https://discord.com/invite/cloudflaredev">Discord</a>. We’re excited to see what you ship with these improvements!</p>
    <div>
      <h3>A sneak preview</h3>
      <a href="#a-sneak-preview">
        
      </a>
    </div>
    <p>As we like to say at Cloudflare, we’re just getting started. While we have plans to add improvements to wrangler... where else could we introduce logs?</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/GXS8Vlb9Hfq5Jufmsgc7Y/baae39c001495d15521539b7f04abcd7/image3-8.png" />
            
            </figure><p>Stay tuned.</p> ]]></content:encoded>
            <category><![CDATA[Developer Week]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[Wrangler]]></category>
            <category><![CDATA[Product News]]></category>
            <guid isPermaLink="false">4mqJidVbcm65xGJzWTA6Ro</guid>
            <dc:creator>Ashcon Partovi</dc:creator>
        </item>
        <item>
            <title><![CDATA[Developer Challenges]]></title>
            <link>https://blog.cloudflare.com/developer-week-challenges/</link>
            <pubDate>Mon, 12 Apr 2021 14:00:00 GMT</pubDate>
            <description><![CDATA[ Developer week is here! Throughout the week we are running a series of Developer Challenges that give you the perfect excuse to play with our new features. See how many of the challenges you can get through. ]]></description>
            <content:encoded><![CDATA[ <p></p><p>Welcome to Developer Week at Cloudflare! We are excited to announce we are running a series of Developer Challenges throughout the week to give you the excuse you needed to play with all our new features.</p><p>Between now and April 19 you’ll get to know the Cloudflare developer tools and walk away with a fun new app (or five) to your name. You’ll also become a part of the Cloudflare Developer community!</p><p>We hope that some of you will be inspired to create your next project using <a href="https://workers.cloudflare.com/">Cloudflare Workers,</a> <a href="https://www.cloudflare.com/products/workers-kv/">Workers KV</a>, <a href="https://pages.cloudflare.com/">Pages</a>, <a href="https://developers.cloudflare.com/workers/learning/using-durable-objects">Durable Objects</a> and all the developer-focussed products that Cloudflare offers. There’s already a vibrant community building applications using the Workers ecosystem; we hope the Developer Challenges inspire you to build on Cloudflare.</p>
    <div>
      <h2>What are Developer Challenges?</h2>
      <a href="#what-are-developer-challenges">
        
      </a>
    </div>
    <p>We know that some people are new to the Cloudflare services for developers and that some of you have been using them for a while, so we have come up with two streams of challenges.</p><p>If you’re just getting started with Cloudflare, there will be a new challenge each day of the week that will help you level up your knowledge in no time. There’s also an extra bonus challenge over the weekend if you’re feeling inspired.</p><p>For Cloudflare’s current power users, there are two challenges — one for the week and one for the weekend. Both are designed to build upon your current knowledge and have some fun with.</p>
    <div>
      <h2>Why Participate?</h2>
      <a href="#why-participate">
        
      </a>
    </div>
    <p>The Cloudflare Developer Challenges give you a great opportunity to try out Cloudflare products in a guided manner. They start off with the basics and gradually get more complex. But don’t worry — there is a great community on our Discord server that will help answer any questions you may have along the way.</p><p>This is also an opportunity to connect with like-minded people and hear how some of our power users are making the most of what’s on offer.</p><p>We are really excited to see what you’ll build, and can’t wait to share it with our community on Cloudflare TV!</p>
    <div>
      <h2>How to Participate</h2>
      <a href="#how-to-participate">
        
      </a>
    </div>
    
    <div>
      <h3>Step 1: join our community on Discord</h3>
      <a href="#step-1-join-our-community-on-discord">
        
      </a>
    </div>
    <p>Join our Discord server <a href="https://discord.com/invite/cloudflaredev">here</a>. Details of each challenge will be posted in a separate Discord channel. This is where you’ll find specific details of what we’re looking for, as well as the resources you’ll need to get started.</p>
    <div>
      <h3>Step 2: check out the daily challenges</h3>
      <a href="#step-2-check-out-the-daily-challenges">
        
      </a>
    </div>
    <p>Once you have introduced yourself on Discord, read through the challenge and get started with the resources. If you have any questions, ask away!</p>
    <div>
      <h3>Step 3 build your app.</h3>
      <a href="#step-3-build-your-app">
        
      </a>
    </div>
    <p><b>(This is the hard part).</b></p>
    <div>
      <h3>Step 4: share what you’ve built!</h3>
      <a href="#step-4-share-what-youve-built">
        
      </a>
    </div>
    <p>We’d love to see what you’ve built, and are really excited to feature some of the solutions on Cloudflare TV, so make sure you take a screenshot to share on Twitter and tag us @CloudflareDev and #DevChallenges.</p><p>This blog post will be updated daily with the new challenges, please join the <a href="https://discord.com/invite/cloudflaredev">Discord</a> server to participate.</p><h2><a></a>Dev Challenge #1</h2>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3w3251b6dzir8QECzOPqPY/0953b73900a8c9659debeeacff25d29d/Hello-World.png" />
            
            </figure>
    <div>
      <h3>New to Cloudflare: Hello Worker!</h3>
      <a href="#new-to-cloudflare-hello-worker">
        
      </a>
    </div>
    <p>Deploy your first Cloudflare Worker with Wrangler by following this tutorial:<a href="https://egghead.io/courses/introduction-to-cloudflare-workers-5aa3">Introduction to Cloudflare Workers</a>.</p><p>When you’ve finished, take a screenshot and share in on Twitter, tag us @CloudflareDev and #DevChallenges.</p>
    <div>
      <h3>Power Users: Portfolio Project Challenge</h3>
      <a href="#power-users-portfolio-project-challenge">
        
      </a>
    </div>
    <p>This is your challenge for the week. Get creative and show off your skills and experience, using as many of the Cloudflare products as you can combine. More details can be found here: <a href="https://egghead.io/projects/introduction-to-cloudflare-workers">Portfolio Details</a>.</p><hr /><h2><a></a>Dev Challenge #2</h2>
    <div>
      <h3>New to Cloudflare: Pick a path Framework:</h3>
      <a href="#new-to-cloudflare-pick-a-path-framework">
        
      </a>
    </div>
    <ul><li><p>Gatsby</p></li><li><p>Next.js</p></li><li><p>Vue</p></li><li><p>React</p></li><li><p>Hugo</p></li><li><p>Zola</p></li><li><p>Jekyll</p></li></ul><p>Choose your own framework and build out a site for your blogs (Lorem Ipsum blogs count).Here are some really good resources:</p><p><a href="https://developers.cloudflare.com/pages/how-to">Pages Docs</a><a href="https://developers.cloudflare.com/pages/how-to">Pages HowTo</a></p><p>Don’t forget to let us know how you got on, take a screenshot and share in on Twitter, tag us @CloudflareDev and #DevChallenges.</p>
    <div>
      <h3>Super Users: Continue the Portfolio Project Challenge</h3>
      <a href="#super-users-continue-the-portfolio-project-challenge">
        
      </a>
    </div>
    <p><a href="https://egghead.io/projects/introduction-to-cloudflare-workers">Portfolio Details</a></p><hr /><h2><a></a>Dev Challenge #3</h2>
    <div>
      <h3>New to Cloudflare: Discord Bots</h3>
      <a href="#new-to-cloudflare-discord-bots">
        
      </a>
    </div>
    <p>Build a Discord Bot with Cloudflare Workers.<a href="https://www.youtube.com/watch?v=xRt9PwphmY8">Discord Bot Tutorial</a>Then get creative and store your images in KV.<a href="https://developers.cloudflare.com/workers/runtime-apis/kv">KV Docs</a></p><p>Take a screenshot of your bot in action and share it in on Twitter, tag us @CloudflareDev and #DevChallenges.</p>
    <div>
      <h3>Power Users: Continue the Portfolio Project Challenge</h3>
      <a href="#power-users-continue-the-portfolio-project-challenge">
        
      </a>
    </div>
    <p><a href="https://egghead.io/projects/introduction-to-cloudflare-workers">Portfolio Details</a></p><hr /><h2><a></a>Dev Challenge #4</h2>
    <div>
      <h3>New to Cloudflare: Random Rendering</h3>
      <a href="#new-to-cloudflare-random-rendering">
        
      </a>
    </div>
    <p>Using the UnSplash API, render random images. Work through these two tutorials:</p><p><a href="https://developers.cloudflare.com/pages/tutorials/build-an-api-with-workers">Build an API with workers</a><a href="https://egghead.io/courses/build-a-serverless-api-with-cloudflare-workers-d67ca551">Build a serverless API with workers</a></p><p>Then take off the tutorial safety wheels, and see if you can render random images of a fixed size using this <a href="https://unsplash.com/documentation#supported-parameters">information</a>.</p><p>We’re intrigued to see what your first image is, take a screenshot of what you do end up with and share it in on Twitter, tag us @CloudflareDev and #DevChallenges.</p>
    <div>
      <h3>Power Users: Continue the Portfolio Project Challenge</h3>
      <a href="#power-users-continue-the-portfolio-project-challenge">
        
      </a>
    </div>
    <p><a href="https://egghead.io/projects/introduction-to-cloudflare-workers">Portfolio Details</a></p><hr /><h2><a></a>Dev Challenge #5</h2>
    <div>
      <h3>New to Cloudflare: Workers-Repo-Hunt</h3>
      <a href="#new-to-cloudflare-workers-repo-hunt">
        
      </a>
    </div>
    <p>We’ve all seen Product Hunt, but what about building out Workers-Repo-Hunt?Build an app where people can submit and upvote open source code that uses Workers.This is a tough one, here are some useful resources:</p><p><a href="https://developers.cloudflare.com/workers/runtime-apis/kv">KV Docs</a><a href="https://developers.cloudflare.com/workers/tutorials/deploy-a-react-app-with-create-react-app">React Docs</a><a href="https://developers.cloudflare.com/workers/runtime-apis/response#parameters">Form Docs</a></p><p>But you’re going to have to get creative and work a lot of it out. Don’t forget to ask for help, ideas and advice on Discord — and to share what you’ve worked out too.</p><p>We can’t wait to see what you end up with, so make sure you take a screenshot and share in on Twitter, tag us @CloudflareDev and #DeveloperChallenges.</p>
    <div>
      <h3>Power Users: Last day for the Portfolio Project Challenge</h3>
      <a href="#power-users-last-day-for-the-portfolio-project-challenge">
        
      </a>
    </div>
    <p><a href="https://egghead.io/projects/introduction-to-cloudflare-workers">Portfolio Details</a></p><p>We’re expecting amazing things, so take a screenshot of what you build and share it with us on Twitter. Don’t forget to tag us @CloudflareDev and use the hashtag #DevChallenges.</p><hr /><h2><a></a>Dev Challenge #6</h2>
    <div>
      <h3>New to Cloudflare: Day and Night</h3>
      <a href="#new-to-cloudflare-day-and-night">
        
      </a>
    </div>
    <p>Build an app that shows a different background photo or colour depending on whether it is day or night in the region it is being viewed from.</p><p>Use Workers to run as a cron trigger to update the background with HTML Rewriter.</p><p>Try these resources:<a href="https://egghead.io/courses/build-a-serverless-api-with-cloudflare-workers-d67ca551?utm_source=rss&amp;utm_medium=feed&amp;utm_campaign=rss_feed">API Tutorial</a><a href="https://developers.cloudflare.com/workers/tutorials/localize-a-website">HTML Rewriter Docs</a><a href="https://developers.cloudflare.com/workers/platform/cron-triggers">Cron Trigger Docs</a></p><p>We can’t wait to see what you end up with, so make sure you take a screenshot and share in on Twitter, tag us @CloudflareDev and #DeveloperChallenges.</p>
    <div>
      <h3>Super Users: Remind me again…..</h3>
      <a href="#super-users-remind-me-again">
        
      </a>
    </div>
    <p>Aren’t we all a bit forgetful at the moment?Build out a Reminder App using cron triggers and Twilio.</p><p>Here’s some resources that will help:<a href="https://developers.cloudflare.com/workers/tutorials/build-a-jamstack-app">To-do List Tutorial</a><a href="https://developers.cloudflare.com/workers/tutorials/github-sms-notifications-using-twilio">Twilio Tutorial</a><a href="https://developers.cloudflare.com/workers/platform/cron-triggers">Cron Trigger Docs</a></p><p>This is a tough gig — we haven’t built it out ourselves yet, so are even more excited to see what you can come up with. Share in on Twitter, tag us @CloudflareDev and use the hashtag #DeveloperChallenges.</p> ]]></content:encoded>
            <category><![CDATA[Developer Week]]></category>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Wrangler]]></category>
            <category><![CDATA[Serverless]]></category>
            <category><![CDATA[Developer Platform]]></category>
            <guid isPermaLink="false">7G4RG2RWBbJGkCO5xtWp8m</guid>
            <dc:creator>Gretchen Scott</dc:creator>
        </item>
        <item>
            <title><![CDATA[Durable Objects, now in Open Beta]]></title>
            <link>https://blog.cloudflare.com/durable-objects-open-beta/</link>
            <pubDate>Wed, 31 Mar 2021 13:00:00 GMT</pubDate>
            <description><![CDATA[ As of today, Durable Objects beta access is available to anyone with a Cloudflare Workers® subscription. ]]></description>
            <content:encoded><![CDATA[ <p></p><p>Back in September, we <a href="/introducing-workers-durable-objects/">announced</a> Durable Objects - a new paradigm for stateful serverless.</p><p>Since then, we’ve seen incredible demand and countless unlocked opportunities on our platform. We’ve watched large enterprises build applications from complex API features to real-time games in a matter of days from inception to launch. We’ve heard from developers that Durable Objects lets them spend time they used to waste configuring and deploying databases on building features for their apps. More than anything, we’ve heard that you want to start building with Durable Objects now.</p><p>As of today, Durable Objects beta access is available to anyone with a Cloudflare Workers® subscription - you can enable them now in the <a href="https://dash.cloudflare.com/">dashboard</a> by navigating to “Workers” and then “Durable Objects”. You can also upgrade to the <a href="https://github.com/cloudflare/wrangler/releases/tag/v1.15.0-custom-builds-rc.2">latest version of Wrangler</a> to deploy Durable Objects!</p><p>Durable Objects are still in beta and are being made available to you for testing purposes. Storage is capped per-account at 10 GB of data, and there is no associated SLA for Object availability or durability.</p><p><strong><a href="https://dash.cloudflare.com">Enable beta access now »</a></strong></p>
    <div>
      <h3>What are Durable Objects?</h3>
      <a href="#what-are-durable-objects">
        
      </a>
    </div>
    <p>Durable Objects provide two things: coordination across multiple Workers and strongly consistent edge storage.</p><p>Normally Cloudflare’s network executes a Worker wherever the client’s network request is terminated. This means there can be many instances of your Worker running at a given time all over the world, shown below.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7KDw6tGDQlvRrae4PS7AGM/eb4cb08f52b3a5f989531ac06214894c/image3-54.png" />
            
            </figure><p>By contrast, a Durable Object is defined by a JavaScript class and an ID. There is only ever one instance of a Durable Object with a given ID running anywhere in the world. All Workers making subrequests for the Durable Object with that ID are routed to the same instance - letting them coordinate across multiple requests. The Durable Object instance can then make requests to downstream APIs and store data with our strongly consistent storage API.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5HLQ06eTIRyAl30bPTlVov/975cd2e8aa2360c4eab7e4c5a6d440ef/image1-65.png" />
            
            </figure><p>In this example shown above, we’ve chosen our application’s user ID as the Durable Object’s ID.  When a Worker needs access to a specific user’s data, they can contact the Object with that user’s ID.  That Object can then handle API calls and data access specific to that individual user.</p><p>Remember that Durable Objects scale incredibly well across multiple Object IDs, but that each Object itself is backed by a single-thread. You should be careful to choose an ID for your Objects that minimizes the number of requests processed by a single object.  In our example above, if our user API grew to be too complicated, we might decide to have a separate ID for each combination of a user ID and an API endpoint to host in a single object.</p><p>For more on Durable Objects, see the <a href="https://developers.cloudflare.com/workers/learning/using-durable-objects">docs</a> and the announcement <a href="/introducing-workers-durable-objects/">blog</a>.</p>
    <div>
      <h3>Pricing</h3>
      <a href="#pricing">
        
      </a>
    </div>
    <p>While there’s no charge to use Durable Objects during the beta period, we want to share pricing, so you can build your applications with confidence.</p><p>When you use Durable Objects, you are billed for the compute time your Object uses as well as the storage API operations your Object performs.</p><p>Durable Objects are significantly cheaper than comparable compute and storage offerings from the other major cloud providers.</p><p>As announced on the Workers Unbound <a href="/introducing-workers-unbound/">blog</a>, Durable Objects bills the standard Workers' platform rates for long-running compute time.</p><table><tr><td><p>
</p></td><td><p><b>Compute</b></p></td><td><p></p></td></tr><tr><td><p></p></td><td><p>Durable Objects</p></td><td><p>AWS Lambda</p></td></tr><tr><td><p>Price per request</p></td><td><p>\$0.15 / MM</p></td><td><p>\$0.20-0.28 / MM</p></td></tr><tr><td><p>Compute ($ per MM GB-sec)</p></td><td><p>\$12.50</p></td><td><p>\$16.67 - \$22.92 (depending on geo)</p></td></tr><tr><td><p>Data Transfer</p></td><td><p>\$0.09 / GB</p></td><td><p>\$0.09/GB - \$0.15/GB (depending on geo)</p></td></tr></table><p>*Based on pricing disclosed on aws.amazon.com/lambda/pricing as of March 16, 2021. AWS’ published duration pricing is based on 1 GB-sec, which has been multiplied by one million on this table for readability. AWS price ranges reflect different regional pricing. All prices rounded to the nearest two decimal places. Data Transfer for AWS is based on Data Transfer OUT From Amazon EC2 to Internet above 1 GB / month, for up to 9.999 TB / month.</p><p>Durable Objects charges per storage operation for reads, writes and deletes and per GB-Month for data stored. Operations are metered in 4 KB increments - for example, an 8 KB read or write would be billed as two operations. When compared to AWS DynamoDB, Durable Objects charge less for every type of operation, and depending on the size of your operations, your savings could be significant. All price comparisons we’re showing below are based on single-region, strongly consistent DynamoDB storage. AWS charges extra for multi-region and transactionally consistent storage, which is already included for Durable Objects. If you use these features in DynamoDB, your savings will be even greater.</p><table><tr><td><p>
</p></td><td><p><b>Storage</b></p></td><td><p></p></td></tr><tr><td><p></p></td><td><p>Durable Objects</p></td><td><p>AWS DynamoDB</p></td></tr><tr><td><p>Price per MM read request</p></td><td><p>\$0.20 / MM / 4 KB</p></td><td><p>\$0.25 - \$0.375 / MM / 4 KB</p></td></tr><tr><td><p>Price per MM write request</p></td><td><p>\$1.00 / MM / 4 KB</p></td><td><p>\$1.25 - \$1.88 / MM / 1 KB</p></td></tr><tr><td><p>Price per MM delete request</p></td><td><p>\$1.00 / MM regardless of size</p></td><td><p>\$1.25 - \$1.88 / MM / 1 KB</p></td></tr><tr><td><p>Price per GB stored data</p></td><td><p>\$0.20 / GB</p></td><td><p>\$0.25 / GB</p></td></tr></table><p>*Based on pricing disclosed on aws.amazon.com/dynamodb/pricing/on-demand/ as of March 16, 2021. AWS price ranges reflect different regional pricing. All prices rounded to the nearest two decimal places.</p><p>We chose to meter our requests in 4 KB increments across the board to provide the lowest prices with the greatest flexibility. Deletes do not have a size limit.</p><p>We’ve seen that the vast majority of requests are actually smaller than 4 KB in size - Workers KV, our global, eventually consistent data store, has a median value size in the low single KB range.</p>
    <div>
      <h3>Giving developers more for less</h3>
      <a href="#giving-developers-more-for-less">
        
      </a>
    </div>
    <p>Not only are Durable Objects less expensive, they have a unique design that lets you do more than a traditional database layer.</p><p>Each Durable Object runs custom code that you write. After your Durable Object makes a request to a downstream API or to our storage API, the value can be cached in-memory for no-cost, low latency lookups.</p><p>Unlike major cloud-provider databases, Durable Objects are replicated to multiple distinct regions by default for high availability with no additional cost. With other cloud providers, this feature generally drives up costs - not to mention the increased complexity of self-managing multiple regions.</p><p>Durable Objects also provide strong consistency across operations by default. While many systems charge more for higher levels of consistency, running transactionally consistent storage from a Durable Object comes at no additional charge.</p>
    <div>
      <h3>Building together</h3>
      <a href="#building-together">
        
      </a>
    </div>
    <p>Since announcing Durable Objects, we’ve continued to add features to the platform, including:</p><ul><li><p>Smarter initial placement for user-named Objects, for lower latency access after initial creation.</p></li><li><p><a href="/supporting-jurisdictional-restrictions-for-durable-objects/">Jurisdictional Restrictions</a>, allowing developers to restrict their Durable Objects to only run and store data in specific regions. This helps with compliance with data localization obligations.</p></li><li><p>Wrangler support for uploading Durable Objects.</p></li><li><p>Platform stability and increased capacity.</p></li></ul><p>As we continue to add to the platform, we’re excited to see what you’re building as well. Come hang out in <a href="https://discord.gg/TGG8Fw4zKP">our Discord</a> to ask questions and share what you’re building on Durable Objects!</p>
    <div>
      <h3>Watch on Cloudflare TV</h3>
      <a href="#watch-on-cloudflare-tv">
        
      </a>
    </div>
    <div></div>
<p></p><p></p> ]]></content:encoded>
            <category><![CDATA[Product News]]></category>
            <category><![CDATA[Durable Objects]]></category>
            <category><![CDATA[Beta]]></category>
            <category><![CDATA[Serverless]]></category>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[Wrangler]]></category>
            <guid isPermaLink="false">4WhPejVq17N90XRDJfKiig</guid>
            <dc:creator>Greg McKeon</dc:creator>
        </item>
        <item>
            <title><![CDATA[Random Employee Chats at Cloudflare]]></title>
            <link>https://blog.cloudflare.com/random-employee-chats-cloudflare/</link>
            <pubDate>Sat, 20 Mar 2021 12:00:00 GMT</pubDate>
            <description><![CDATA[ We developed the Random Employee Chats application internally, with the goal of recreating the pre-pandemic informal interactions. Here's how we moved from a shared spreadsheet to Cloudflare Workers to automate the entire process. ]]></description>
            <content:encoded><![CDATA[ <p>Due to the COVID-19 pandemic, most Cloudflare offices closed in March 2020, and employees began working from home. Having online meetings presented its own challenges, but preserving the benefits of casual encounters in physical offices was something we struggled with. Those informal interactions, like teams talking next to the coffee machine, help form the social glue that holds companies together.</p><p>In an attempt to recreate that experience, David Wragg, an engineer at Cloudflare, introduced “Random Engineer Chats” (We’re calling them “Random Employee Chats” here since this can be applied to any team). The idea is that participants are randomly paired, and the pairs then schedule a 30-minute video call. There’s no fixed agenda for these conversations, but the participants might learn what is going on in other teams, gain new perspectives on their own work by discussing it, or meet new people.</p><p>The first iteration of Random Employee Chats used a shared spreadsheet to coordinate the process. People would sign up by adding themselves to the spreadsheet, and once a week, David would randomly form pairs from the list and send out emails with the results. Then, each pair would schedule a call at their convenience. This process was the minimum viable implementation of the idea, but it meant that the process relied on a single person.</p>
    <div>
      <h3>Moving to Cloudflare Workers</h3>
      <a href="#moving-to-cloudflare-workers">
        
      </a>
    </div>
    <p>We wanted to automate these repetitive manual tasks, and naturally, we wanted to use <a href="https://workers.cloudflare.com/">Cloudflare Workers</a> to do it. This is a great example of a complete application that runs entirely in Cloudflare Workers on the edge with no backend or origin server.</p><p>The technical requirements included:</p><ul><li><p>A user interface so people can sign up</p></li><li><p>Storage to keep track of the participants</p></li><li><p>A program that automatically pairs participants and notifies each pair</p></li><li><p>A program that reminds people to register for the next sessions</p></li></ul><p>Workers met all of these requirements, and the resulting application runs in Cloudflare's edge network without any need to run code or store data on other platforms. The Workers script supplies the UI that returns static HTML and JavaScript assets, and for storage, Workers KV keeps track of people who signed in.</p><p>We also recently announced <a href="https://developers.cloudflare.com/workers/platform/cron-triggers">Workers Cron Triggers</a> which allow us to run a Cloudflare Workers script on a defined schedule. The Workers Cron Triggers are perfect for pairing people up before the sessions and reminding users to register for the next session.</p>
    <div>
      <h3>The User Interface</h3>
      <a href="#the-user-interface">
        
      </a>
    </div>
    
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/26ih1wWQgNslI8kNjBYq1d/20676f1eef4c8052cc6ec2dda8c06eb7/Random-Engineer-Chat-Dashboard-1.png" />
            
            </figure><p>The interface is very simple. It shows the list of participants and allows users to register for the next session.</p><p>When a user clicks on the register button, it calls an API that adds a key in Workers KV:</p>
            <pre><code>key: register:ID
value: {"name":"Sven Sauleau","picture":"picture.jpg","email":"example@cloudflare.com"}</code></pre>
            <p>User information is stored in Workers KV and displayed in the interface to create the list of participants. The user information gets deleted during pairing so the list is ready for the next round of chats. We require weekly sign-ups from participants who want to participate in the chats to confirm their availability.</p><p>The code for the interface can be found <a href="https://github.com/cloudflare/random-employee-chat/tree/master/src/workers/randengchat/public">here</a> and the API is <a href="https://github.com/cloudflare/random-employee-chat/blob/master/src/workers/randengchat/server/index.js">here</a>.</p>
    <div>
      <h3>Forming the pairs</h3>
      <a href="#forming-the-pairs">
        
      </a>
    </div>
    <p>A Random Employee Chat is a one-on-one conversation, so at a set time, the application puts participants into pairs. Each Monday morning at 0800 UTC, a Workers cron job runs the pairing script which is deployed using <a href="https://developers.cloudflare.com/workers/cli-wrangler">Wrangler</a>.</p><p>Wrangler supports configuring the schedule for a job using the familiar cron notation. For instance, our wrangler.toml has:</p>
            <pre><code>name = "randengchat-cron-pair"
type = "webpack"
account_id = "..."
webpack_config = "webpack.config.js"
…

kv_namespaces = [...]

[triggers]
crons = ["0 8 * * 2"]</code></pre>
            <p>The pairing script is the most intricate part of the application, so let’s run through its code. First, we list the users that are currently registered. This is done using the <a href="https://developers.cloudflare.com/workers/runtime-apis/kv#listing-by-prefix">list</a> function in Workers KV extracting keys with the prefix <code>register:</code>.</p>
            <pre><code>const list = await KV_NAMESPACE.list({ prefix: "register:" });</code></pre>
            <p>If we don’t have an even number of participants, we remove one person from the list (David!).</p><p>Then, we create all possible pairs and attach a weight to them.</p>
            <pre><code>async function createWeightedPairs() {
  const pairs = [];
  for (let i = 0; i &lt; keys.length - 1; i++) {
    for (let j = i + 1; j &lt; keys.length; j++) {
      const weight = (await countTimesPaired(...)) * -1;
      pairs.push([i, j, weight]);
    }
  }
  return pairs;
}</code></pre>
            <p>For example, suppose four people have registered (Tom, Edie, Ivie and Ada), that’s 6 possible pairs (<a href="https://www.wolframalpha.com/input/?i=4+choose+2">4 choose 2</a>). We might end up with the following pairs and their associated weights:</p>
            <pre><code>(Tom, Edie, 1)
(Tom, Ivie, 0)
(Tom, Ada, 1)
(Edie, Ivie, 2)
(Edie, Ada, 0)
(Ivie, Ada, 2)</code></pre>
            <p>The weight is calculated using the number of times a pair matched in the past to avoid scheduling chats between people that already met. More sophisticated factors could be taken into account, such as the same office or timezone, when they last met, and etc.</p><p>We keep track of how many times the pair matched using a count kept in KV:</p>
            <pre><code>async function countTimesPaired(key) {
  const v = await DB.get(key, "json");
  if (v !== null &amp;&amp; v.count) {
    return v.count;
  }
  return 0;
}</code></pre>
            <p>The people form a complete graph with people as nodes and the edges weighted by the number of times the two people connected by the edge have met.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/anoEru6iUYXNlVFxpCk4w/67d7587b1440044c1a9072545dc8cce6/image5-20.png" />
            
            </figure><p>Next, we run a weighted matching algorithm, in our case the <a href="https://en.wikipedia.org/wiki/Blossom_algorithm">Blossom algorithm</a>, which will find a maximum matching on the graph (a set of edges that maximize the number of pairs of people connected with each person appearing exactly once). As we use the weighted form of the Blossom algorithm we also minimize the path weights. This has the effect of finding the optimal set of pairs minimizing the number of times people have met previously.</p><p>In the case above the algorithm suggests the optimal pairs are  (Tom, Ivie) and (Edie, Ada). In this case, those pairs have never met before.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5Fi6gV8b7uZHZMVR7jouFF/0e7ef8ef4cdcd6dde01e4fb637bc964c/image2-18.png" />
            
            </figure><p>The pairs are recorded in Workers KV with their updated matching count to refine the weights at future sessions:</p>
            <pre><code>key: paired:ID
value: {"emails":["left@cloudflare.com","right@cloudflare.com", "count": 1]}</code></pre>
            <p>A notification is sent to each pair of users to notify them that they matched.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7xVSUWDwEFKqY2KS9Mupwj/0e7e502307c3a67fc6e7d124a08a5101/image4-17.png" />
            
            </figure><p>Once the pairing is done, all <code>register:</code> keys are deleted from KV.</p><p>All the pairing logic is <a href="https://github.com/cloudflare/random-employee-chat/blob/master/src/workers/cron-pair/index.js">here</a>.</p>
    <div>
      <h3>Reminders</h3>
      <a href="#reminders">
        
      </a>
    </div>
    <p>The application sends users a reminder to sign up every week. For the reminder, we use another Workers cron job that runs every Thursday at 1300 UTC. The schedule in Wrangler is</p>
            <pre><code>[triggers]
crons = ["0 13 * * 5"]</code></pre>
            <p>This script is much simpler than the pairing script. It simply sends a message to a room in our company messaging platform that notifies all members of the channel.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7ACIIWbP4COwxXbImfqiQE/78488aeabc86a3a1b6d382ffe32f42a2/image3-19.png" />
            
            </figure><p>All the reminder code is <a href="https://github.com/cloudflare/random-employee-chat/blob/master/src/workers/cron-reminder/index.js">here</a>.</p><p>We hope you find this code useful and that it inspires you to use Workers, Workers KV, Workers Unbound and Workers Cron Triggers to write large, real applications that run entirely without a backend server.</p> ]]></content:encoded>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[Cloudflare Workers KV]]></category>
            <category><![CDATA[Wrangler]]></category>
            <guid isPermaLink="false">3MzecqWNHhc0wbjnxE2kiX</guid>
            <dc:creator>Sven Sauleau</dc:creator>
            <dc:creator>David Wragg</dc:creator>
        </item>
        <item>
            <title><![CDATA[Announcing wrangler dev — the Edge on localhost]]></title>
            <link>https://blog.cloudflare.com/announcing-wrangler-dev-the-edge-on-localhost/</link>
            <pubDate>Wed, 26 Aug 2020 11:00:00 GMT</pubDate>
            <description><![CDATA[ A few weeks ago we announced a release candidate for wrangler dev — today, we're excited to take wrangler dev, the world’s first edge-based development environment, to GA with the release of wrangler 1.11. ]]></description>
            <content:encoded><![CDATA[ <p>Cloudflare Workers — our serverless platform — allows developers around the world to run their applications from our network of 200 datacenters, as close as possible to their users.</p><p>A few weeks ago <a href="/making-magic-reimagining-developer-experiences-for-the-world-of-serverless/">we announced</a> a release candidate for <code>wrangler dev</code> — today, we're excited to take <code>wrangler dev</code>, the world’s first edge-based development environment, to GA with the release of <a href="https://github.com/cloudflare/wrangler/releases/tag/v1.11.0">wrangler 1.11</a>.</p>
    <div>
      <h3>Think locally, develop globally</h3>
      <a href="#think-locally-develop-globally">
        
      </a>
    </div>
    <p>It was once assumed that to successfully run an application on the web, one had to go and acquire a server, set it up (in a data center that hopefully you had access to), and then maintain it on an ongoing basis. Luckily for most of us, that assumption was challenged with the emergence of the cloud. The cloud was always assumed to be centralized — large data centers in a single region (“us-east-1”), reserved for compute. The edge? That was for caching static content.</p><p>Again, assumptions are being challenged.</p><p>Cloudflare Workers is about moving compute from a centralized location to the edge. And it makes sense: if users are distributed all over the globe, why should all of them be routed to us-east-1, on the opposite side of the world, causing latency and degrading user experience?</p><p>But challenging one assumption caused others to come into view. One of the most obvious ones was: would a <i>local</i> development environment actually provide the best experience for someone looking to test their Worker code? Trying to fit the entire Cloudflare edge, with all its dependencies onto a developer’s machine didn’t seem to be the best approach. Especially given that the place the developer was going to run that code in production was mere milliseconds away from the computer they were running on.</p><p>When I was in college, getting started with programming, one of the biggest barriers to entry was installing all the dependencies required to run a single library. I would go as far as to say that the third, and often forgotten hardest problem in computer science is dependency management.</p><p>We’re not the first to try and unify development environments across machines — tools such as Docker aim to solve this exact problem by providing a prepackaged development environment.</p><p>Yet, packaging up the Workers runtime is not quite so simple.</p><p>Beyond the Workers runtime, there are many components that make up Cloudflare’s edge, including DNS resolution, the Cloudflare cache — all of those parts are what makes Cloudflare Workers so powerful. That means that without those components, a standalone runtime is insufficient to represent the behavior of Worker request handling. The reason to develop locally first is to have the opportunity to experiment without affecting production. Thus, having a local development environment that truly reflects production is a requirement.</p>
    <div>
      <h2><code>wrangler dev</code></h2>
      <a href="#wrangler-dev">
        
      </a>
    </div>
    <p><code>wrangler dev</code> provides all the convenience of a local development environment, without the headache of trying to reproduce the reality of production locally — and then having to keep the two environments in sync.</p><p>By running at the edge, it provides a high fidelity, consistent experience for all developers, without sacrificing the speedy feedback loop of a local development environment.</p>
    <div>
      <h3>Live reloading</h3>
      <a href="#live-reloading">
        
      </a>
    </div>
    
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6wQyrPucUMQo2M0sTdfmK9/8b924839302fb10d184a64debd0b0912/Announcing--wrangler-dev----the-Edge-on-localhost1.gif" />
            
            </figure><p>As you update your code, <code>wrangler dev</code> will detect changes, and push the new version of your code to the edge.</p>
    <div>
      <h3>console.log() at your fingertips</h3>
      <a href="#console-log-at-your-fingertips">
        
      </a>
    </div>
    
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6LsSXt9rGiJnEKhfuknAoC/8ca21ba6110e7a839b87c5392155a628/Announcing--wrangler-dev----the-Edge-on-localhost2.gif" />
            
            </figure><p>Previously to extract your console logs from the Workers runtime, you had to have the Workers Preview open in a browser window at all times. With <code>wrangler dev</code>, you can receive your own logs, directly to your terminal of choice.</p>
    <div>
      <h3>Cache API, KV, and more!</h3>
      <a href="#cache-api-kv-and-more">
        
      </a>
    </div>
    <p>Since <code>wrangler dev</code> runs on the edge, you can now easily test the state of a cache.put(), without having to deploy your Worker to production.</p><p><code>wrangler dev</code> will spin up a new KV namespace for development, so you don’t have to worry about affecting your production data.</p><p>And if you’re looking to test out some of the features provided on <a href="https://developers.cloudflare.com/workers/runtime-apis/request#incomingrequestcfproperties"><code>request.cf</code></a> that provide rich information about the request such as geo-location — they will all be provided from the Cloudflare data center.</p>
    <div>
      <h3>Get started</h3>
      <a href="#get-started">
        
      </a>
    </div>
    <p><code>wrangler dev</code> is now available in the latest version of Wrangler, the official Cloudflare Workers CLI.</p><p>To get started, follow our installation instructions <a href="https://developers.cloudflare.com/workers/cli-wrangler/install-update#update">here</a>.</p>
    <div>
      <h3>What’s next?</h3>
      <a href="#whats-next">
        
      </a>
    </div>
    <p><code>wrangler dev</code> is just our first foray into giving our developers more visibility and agility with their development process.</p><p>We recognize that we have a lot more work to do to meet our developers needs, including providing an easy testing framework for Workers, and allowing our customers to observe their Workers’ behavior in production.</p><p>Just as <code>wrangler dev</code> provides a quick feedback loop between our developers and their code, we love to have a tight feedback loop between our developers and our product. We love to hear what you’re building, how you’re building it, and how we can help you build it better.</p> ]]></content:encoded>
            <category><![CDATA[Wrangler]]></category>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[Serverless]]></category>
            <category><![CDATA[Developers]]></category>
            <guid isPermaLink="false">1Bl19f97iDwvy5L4uBGq5B</guid>
            <dc:creator>Rita Kozlov</dc:creator>
        </item>
    </channel>
</rss>