Why Move a Legacy App to Workers?

Cloudflare Workers and similar serverless platforms keep pushing down costs while simplifying global application deployment. That combination makes legacy migrations increasingly attractive. The motivations typically fall into two categories: the constraints pushing teams off old infrastructure, and the benefits pulling them toward a serverless, zero-trust model.

Legacy setups usually suffer from inflexible compute that demands constant maintenance, leading to either capacity shortages or wasted spend. Managing VPN credentials adds friction and introduces security risk when done carelessly, and VPN client software often trips up non-technical users. On the pull side, serverless platforms bring instant scaling with no capacity ceilings and no idle cost, while zero-trust access eliminates separate credential systems by letting users authenticate through SSO. The accumulated infrastructure — VPN hardware, private cloud, old compute — can be retired entirely, simplifying operations and cutting costs.

What stops many organizations is the perceived migration effort. In practice, the platform features below collapse that effort into a few focused steps. This walkthrough uses a contrived Node.js application, Post Process, to illustrate a realistic migration path with four Cloudflare technologies: Workers for compute, Wrangler for tooling, Access for zero-trust security, and Argo Tunnel for secure origin connectivity.

Starting Point: Application and Architecture

The example application accepts an HTTP POST, parses the JSON body, performs text processing, and returns the result. It currently runs on Node.js on a laptop, behind a gateway that controls access.

The code is split cleanly into two modules. One module handles all Node.js-specific HTTP and preprocessing work. The other, postProcess.js, exposes a single function that takes a parsed JSON object and synchronously returns a plain JavaScript object ready for JSON serialization. That business-logic module is portable to Workers with no changes; only the HTTP layer needs to be rebuilt.

The Migration of Legacy Applications to Workers

Because the application is JavaScript, the business logic can be copied directly into the new Workers project. The same approach extends to other languages via WebAssembly; for those, a rewrite or transpilation step is required first.

Target Design

Three decisions shape the new Cloudflare-based architecture:

  1. Keep the business logic byte-for-byte identical, using the same .js asset.
  2. Build a new preprocessing and HTTP layer in Workers to replace the Node.js module.
  3. Put Cloudflare Access in front of the application for authentication.
curl -X POST https://postprocess-workers.kirk.workers.dev/postprocess --data '{"operation":"2","data":"Data-Gram!"}'

First Win: Zero-Trust Before Compute

A successful migration benefits from an early win — something useful that also eases the eventual cutover. Solving the security problem ahead of the compute problem is exactly that.

Using cloudflared, the terminal flow is minimal. Run cloudflared tunnel login to authenticate, then create a tunnel from the local server to the desired public hostname:

cloudflared tunnel --hostname postprocess.kschwenkler.com --url localhost:8080
const server = http.createServer((req, res) => {
    if (req.url == '/postprocess') {
        if(req.method == 'POST') {
                gatherPost(req, data => {
                        try{
                                jsonData = JSON.parse(data)
                        } catch (e) {
                                res.end('Invalid JSON payload! \n')
                                return
                        }
                        result = postProcess(jsonData)
                        res.write(JSON.stringify(result) + '\n');
                        res.end();
                })
        } else {
                res.end('Invalid Method, only POST is supported! \nPlease send a POST with data in format {"Operation":1","data","Data-Gram!"        }
    } else {
        res.end('Invalid request. Did you mean to POST to /postprocess? \n');
    }
});

Next, in the Cloudflare dashboard, attach an Access policy to that hostname. This example uses the Service Token mode, which generates a client-specific token attached to each HTTP POST; other modes suit interactive browser workflows better.

function postProcess (postJson) {
        const ServerVersion = "2.5.17"
        if(postJson != null && 'operation' in postJson && 'data' in postJson){
                var output
                var operation = postJson['operation']
                var data = postJson['data']
                switch(operation){
                        case "1":
                              output = String(data).toLowerCase()
                              break
                        case "2":
                              d = data + "\n"
                              output = d + d + d
                              break
                        case "3":
                              output = ServerVersion
                              break
                        default:
                              output = "Invalid Operation"
                }
                return {'Output': output}
        }
        else{
                return {'Error':'Invalid request, invalid JSON format'}
        }

At this point, any Internet-connected device holding the correct token can POST to the service still running on the laptop — no VPN required. This delivers a significant security upgrade in minutes, and routes production traffic through the target-state API gateway, preparing the path for surgical traffic shifting later.

The Migration of Legacy Applications to Workers Embedded Image - SEyGy4

Lifting the Application to Workers

With traffic secured and flowing through Cloudflare, the application itself can move. Wrangler simplifies the process.

The Node.js HTTP module needs rewriting; the business logic does not. A minimal Workers HTTP handler would grab the POST body, parse JSON, call postProcess(), and return the result. However, for a realistic path — where real applications are more complex — the migration uses Wrangler's Router template as a robust starting framework.

wrangler generate post-process-workers https://github.com/cloudflare/worker-template-router

After initialization, only the account_id in wrangler.toml and a few lines in index.js need updating. The critical line pulls in the original logic module:

const postProcess = require('./postProcess.js')

Copying the legacy postProcess.js into the project directory tells Wrangler to bundle the untouched business logic into the Workers deployment.

The Migration of Legacy Applications to Workers Embedded Image - xyupRs

Running wrangler publish puts the application on workers.dev for open testing. The test endpoint is publicly reachable (and can also be protected with Access if desired), so traffic can be validated from any device.

The Migration of Legacy Applications to Workers Embedded Image - 6hJT4z

Seamless Traffic Cutover

The final migration step — shifting production traffic without interruption — is the one most teams dread. The earlier security work pays off here. Because production traffic already routes through the Cloudflare network to the legacy app via Argo Tunnel, the cutover requires zero changes to IP addresses, SSL configuration, or any client-facing properties.

The Migration of Legacy Applications to Workers Embedded Image - szUT8j

The transition is a single wrangler publish after editing wrangler.toml to point at the production route. Cloudflare immediately sends production traffic to the new Workers application instead of the Argo Tunnel. The app emits a version header so easy verification via curl confirms which backend served the request.

The Migration of Legacy Applications to Workers Embedded Image - QxhwW8

Rollback is equally straightforward: either set wrangler.toml back to workers.dev-only mode and publish, or delete the route manually. Either action sends traffic back to the Argo Tunnel.

Practical Notes for Real Migrations

Real applications are rarely this simple. Multiple components with complex interactions each need individual handling. Argo Tunnel may remain in use to reach data stores or other out-of-network resources. Non-JavaScript modules might require WASM. In all of these cases, Wrangler keeps the operational burden manageable.

The exercise demonstrates the pattern: retrofit zero-trust access first for an immediate security win, then lift the application onto Workers, and finally shift traffic over the already-proxied path with a single publish. This sequence minimizes risk at each stage while steadily converging on the target architecture.