The Deno Deploy shutdown leaves a startup with two separate decisions: where its application will run, and who will maintain its runtime. Deno announced six more months of Deploy operation and another year of monthly runtime bug and security releases. Before moving production traffic, prove that the replacement preserves the behavior your customers depend on. [Deno's October 9 announcement](https://deno.com/blog/cloudflare) establishes those distinct windows.

A homepage loading on Workers is a useful first result. It does not prove that a session stays private, concurrent writes remain correct, or a failed cutover can be reversed. Those are the tests that should determine whether the migration is ready.

This is an acceptance framework for engineering leads with an existing Deno dependency. The examples below are proposed tests, not measured customer migrations or a promise that every application can follow the same route.

## Which Deno deadline applies to your application?

The hosting clock applies to Deno Deploy; the maintenance clock applies to the Deno runtime. Determine which dependency your production application has before scheduling work.

In the October 9 announcement, Deno says its entire team is joining Cloudflare. Deploy will operate for six months before shutting down. The runtime will receive monthly bug and security releases for another year, after which the team's development ends; the runtime remains open source. JSR continues, with its infrastructure moving to Cloudflare. Paying customers migrating to Workers are offered migration support. These commitments do not establish a fixed shutdown timestamp, a customer's contractual assistance scope, or a successor runtime maintenance team. Confirm those details directly when planning your cutover.

An application can use the runtime without using Deploy. A build pipeline running `deno task` faces different risks from an API that serves requests on Deploy. A third-party service can also use a Deno-compatible runtime: [Supabase describes its Edge Functions](https://supabase.com/docs/guides/functions) that way, alongside its own gateway and platform integrations. That does not make Supabase a Deploy customer or assign it Deploy's shutdown window.

For each production request path, write down the host that serves it and the runtime it executes. Then identify whether state or scheduled work also depends on Deploy. This gives you a short dependency trace for the application under review. A repository containing Deno configuration alone cannot answer it.

Older documentation can also lead you to the wrong deadline. Deno's existing [migration guide](https://docs.deno.com/deploy/migration_guide/) describes moving from **Deploy Classic to Deno Deploy**. Its destination is not Workers. The [Deploy overview](https://docs.deno.com/deploy/) also retains a historical Classic shutdown notice. Read both as documentation for that earlier transition, not as the complete migration instructions for the October 2026 announcement.

If both clocks apply, get the hosting replacement accepted before the hosting window closes. Plan runtime maintenance separately, including any Deno executable left in builds or internal jobs after the public service moves.

## Choose a destination by the behavior it can preserve

The right destination is the one that passes your application's acceptance tests and that your team can operate. An acquisition announcement does not settle that choice.

Use the following table to choose what to investigate first. Its requirements are engineering recommendations; the vendor commitments remain those stated in the announcements.

| Your application's situation | Candidate route | Evidence required before accepting it | Reason to reconsider |
| --- | --- | --- | --- |
| Deploy-hosted HTTP service with limited runtime-specific behavior | Evaluate managed Workers, including the announced support for paying customers | Real request paths, authentication, dependency execution, logs and failure recovery pass | A required API imports but cannot execute, or the data contract changes |
| Deno runtime APIs are central to the service | Evaluate a supported host that can run the needed runtime, or an explicit runtime rewrite | Used APIs and operational recovery work on the selected version and host | The route preserves today's code but leaves maintenance unresolved |
| Deno KV transactions protect application invariants | Choose storage from the transaction requirement before choosing its product name | Concurrent writes, conditional commits, expiry and restore preserve the invariant | A replacement passes sequential reads but loses conflicts or exposes stale state |
| Deno appears only in a build or development task | Review tooling separately from production hosting | Reproducible builds and a runtime maintenance plan | Hosting migration work is being scheduled for a host the app does not use |
| Another provider operates the Deno-compatible service | Verify that provider's own lifecycle and dependencies | Provider-specific support information and tests for your integration | Deploy's deadline has been assumed without evidence |
| Team is considering self-hosted workerd | Treat it as a separate operational proposal | Required features exist now and the team can deploy, diagnose and recover them | The plan relies on announced future distribution or tooling |

Cloudflare's [announcement](https://blog.cloudflare.com/deno-joins-cloudflare/) describes future work combining celld and workerd and supporting self-hosting. It also acknowledges the current single-instance limitation of workerd's Durable Objects implementation and incomplete surrounding tooling. Those limits matter when evaluating the proposed direction.

For a team weighing its own infrastructure, the separate question is operating responsibility. Our [self-hosting staffing and ownership article](/blog/self-hosting-startup-staffing-ownership) covers that decision. Here, the immediate question is whether the selected destination can pass the application's tests.

## Test executed paths, authentication and background work

A migration test must exercise the behavior that could fail on the destination. Successful compilation and matching HTTP status codes are only part of the evidence.

Start with a small staging harness that can send the same representative requests to the current application and the candidate replacement. Use synthetic records and separate test credentials. Use a fixed starting state so comparisons are meaningful, then record deliberate differences such as hostname or generated identifiers.

Deno's [Node and npm compatibility documentation](https://docs.deno.com/runtime/fundamentals/node/) concerns running Node applications in Deno. It does not prove that code using Deno APIs can run unchanged elsewhere. On Workers, [Node.js compatibility documentation](https://developers.cloudflare.com/workers/runtime-apis/nodejs/) distinguishes implemented APIs from partial support and nonfunctional stubs. An import can succeed while a later call fails.

Make rarely used paths explicit: the report exporter, attachment transformation, authentication callback, or task that accesses a filesystem or launches a subprocess. Include only features your application uses. Run the actual dependency operation rather than asserting that its module loads. Pin the destination configuration and compatibility date in the test record so a pass refers to a reproducible environment.

For HTTP behavior, compare response bodies, headers, redirects and cookies where they are part of the contract. Include malformed input, expired sessions and unauthorized requests. For a tenant-scoped service, give two synthetic accounts similarly shaped records and attempt access across their boundary. A response that contains the expected record but also another account's data must fail.

If the application schedules or queues work, exercise it separately. For example, accept a request, interrupt the worker before completion, then retry the delivery. Assert the resulting state and external effect, using a test receiver rather than a real customer's mailbox. Verify that failure is visible to a responder. A request returning success cannot prove its later task ran.

Write each result in a form another engineer can challenge: initial state, action, expected outcome, observed outcome and relevant trace. Label a gate “not applicable” with a reason when the app lacks that feature. A long checklist with unexplained green marks gives less evidence than a few tests tied to real failure modes.

## Deno KV and Workers KV need different acceptance tests

Similar storage names do not establish equivalent transaction or read behavior. If state correctness depends on Deno KV, document that dependency before selecting the replacement store.

[Deno KV's transaction documentation](https://docs.deno.com/deploy/kv/transactions/) describes optimistic concurrency control. Reads return versionstamps; an atomic operation can check key/versionstamp pairs alongside mutations. The commit succeeds only if the checked versions still match. Applications using those checks must handle a conflict and decide whether to retry.

[Workers KV documentation](https://developers.cloudflare.com/kv/concepts/how-kv-works/) describes an eventually consistent store whose changes can take 60 seconds or more to appear in other locations. It cautions against relying on immediate visibility even where a write occurred, and says KV is not ideal for atomic operations or transactional reads and writes. It points readers needing stronger consistency toward Durable Objects.

That is a concrete compatibility boundary, not a verdict against Workers. A cache and a uniqueness constraint can need different storage even inside the same application. Choosing another Cloudflare storage component also requires testing its actual guarantees and your implementation; its name alone does not supply the missing behavior.

Suppose a Deno application checks that an invitation key does not exist, then atomically creates the invitation and its lookup record. A naive port that performs a read followed by independent writes may pass every sequential test. Test two concurrent requests for the same invitation instead. The expected application outcome might be one accepted invitation, one conflict and a consistent lookup. Define that outcome from the existing contract before writing the replacement.

A second scenario tests visibility. Create a synthetic permission record, revoke it, and immediately attempt the protected action from a different geographic location. Specify whether revocation must apply immediately or whether the product permits delay. Judge the result against that security requirement; a successful storage API response is insufficient.

For expiry, create a short-lived record and check access around its boundary. Include a previously cached absence if creation visibility matters. For ordered lists, restore enough synthetic keys to test the application's pagination and ordering assumptions. Where versionstamps serve as cursors or application metadata, define how those references will work after conversion; do not quietly substitute destination timestamps.

## Find false greens before approving the cutover

A false green is a passing result that never exercised the condition it claims to test. Review the test design as carefully as the replacement code.

A local emulator can validate logic without reproducing how production requests and data are distributed. Requests from one machine can miss a visibility problem that affects another location. Sequential requests cannot establish concurrency safety. An empty database cannot reveal a conversion error in old records. Add the specific missing condition instead of running the same shallow test more times.

Watch for swallowed failures, too. A dependency error may be caught and converted into an empty result. The endpoint returns 200, but the export has lost rows. Assert the output's content and the expected error behavior. For retry tests, count the final effect, not just the number of requests accepted.

Shadow traffic needs care. Replay sanitized requests into isolated state, with email, payment and webhook destinations replaced by test receivers. A mirrored production write can create a second external effect. Decide in advance which comparisons can run read-only and which require a controlled staging scenario.

Acceptance tests should cover operational recovery, too. Seed a recognizable staging failure, then have someone diagnose it using the destination's logs and alerts. Check that credentials belong to the intended environment and that recovery instructions work for the person expected to respond. A correct application with inaccessible failure evidence is still difficult to recover under pressure.

## Prove rollback with writes and data reconciliation

Rollback is complete only when the old application can resume with correct state. Reversing traffic routing does not undo writes accepted by the destination.

Deno documents [KV backups to customer-controlled S3-compatible storage](https://docs.deno.com/deploy/kv/backup/) and use through the `denokv` tool. Inspect that option for export and recovery. It does not automatically translate data into Workers KV, D1 or another destination.

Restore a representative backup in isolation. Compare meaningful records, expiry behavior and relationships, not only object counts. Record the backup boundary and identify writes accepted afterward. A readable backup with missing recent transactions is insufficient for the rollback you intend to perform.

Then rehearse a failure after the candidate has accepted new writes. Freeze or otherwise control further writes, capture the destination's accepted changes, and reconcile them into the system that will resume serving as the source of truth. Define how duplicates, conflicting edits, deletions and interrupted jobs are handled. Use application identifiers and deliberate reconciliation rules; “copy everything back” leaves those questions unanswered.

For a small service, a planned write pause may make this manageable. A service that cannot pause needs a tested change-capture or replication design. Dual writes add their own failure cases: one side can succeed while the other fails. Rehearse that case before treating dual writes as recovery protection.

Finally, state the rollback boundary in the cutover decision. Before destination writes begin, returning traffic may be straightforward. Afterward, require the reconciliation procedure and its evidence. If the team cannot restore correct state within its chosen recovery requirement, the cutover is not ready.

## Use Kit if the migration exposes a hiring gap

Hire for a specific engineering gap once the acceptance work has shown what is missing. A shutdown deadline alone does not establish that the startup needs a permanent employee.

The gap might be temporary database conversion work, runtime compatibility experience, or ongoing operational responsibility. Define the needed outcome and duration first. A bounded interview exercise can ask a candidate to explain a failed conditional write, investigate an executed compatibility path, or reason through a rollback after one new record is created. Use synthetic data and a short exercise; production migration work should be paid.

Keep migration evidence and cutover decisions in your engineering tools. Kit fits the hiring process if you decide to recruit: it provides a place to manage applications and team review. It does not migrate your runtime or reconcile your database.

The immediate deliverable is a replacement that passes behavior, state and recovery tests before the hosting window closes. If those tests reveal a role you need to fill, [review Kit Hiring](/hiring) for that hiring step.