Deno Deploy
Deno Deploy is the simplest artifact of any Heximon platform: one self-contained script, no config file, no
deploy tree — just dist/deno-worker.js and a deployctl deploy call.
Configure the strategy
import { defineHeximonConfig } from "@heximon/build";
import { DenoDeployStrategy } from "@heximon/deno";
import { HttpPlugin } from "@heximon/http/compiler";
export default defineHeximonConfig({
platform: new DenoDeployStrategy(),
plugins: [new HttpPlugin()],
});
DenoDeployStrategy is an edge-class strategy, platform name "deno".
What vp build emits
vp build # → dist/deno-worker.js
deployctl deploy --project=<your-project> dist/deno-worker.js
The strategy resolves { noExternal: true } — every dependency (@heximon/*, npm deps, your app source) is
bundled into the one file, because Deno Deploy doesn't load node_modules. Only node:*-prefixed builtins
stay external, resolved against Deno's own Node-compat layer.
The generated deno-entry.js
import { createServer, H3FetchClient } from "@heximon/http";
import { routes } from "./router.js";
import { Platform } from "@heximon/runtime";
import { createApp } from "./apps/main.wiring.js";
let serverPromise;
async function boot() {
Platform.capture(Deno.env.toObject());
let server;
const internalClient = new H3FetchClient((input, init) =>
server.fetch(new Request(new URL(input, "http://localhost"), init)));
const app = await createApp({ InternalClient: internalClient });
server = createServer(routes, app);
return server;
}
export default {
async fetch(request) {
serverPromise ??= boot();
const server = await serverPromise;
return server.fetch(request);
},
};
Two details worth noting: there's no env argument threaded per request the way Cloudflare Workers gets one —
Deno env is ambient via Deno.env, captured once at isolate boot — and the entry does not export a
scheduled key. Crons register a different way entirely (next section).
Scheduled work
List SchedulePlugin and DenoWorkerPlugin reads the discovered cron expressions, baking one top-level
Deno.cron(name, expr, cb) registration per handler directly into deno-entry.js:
import type { ScheduledHandler } from "@heximon/schedule";
import { SessionRepository } from "./session-repository";
export class NightlyCleanup implements ScheduledHandler<"0 3 * * *", { name: "Nightly cleanup" }> {
public constructor(private readonly sessions: SessionRepository) {}
public handle(scheduledAt: Date): void {
this.sessions.purgeExpired(scheduledAt);
}
}
import { scheduled as heximonScheduled } from "./schedule-cron.js";
Deno.cron("Nightly cleanup", "0 3 * * *", async () => {
await heximonScheduled({ cron: "0 3 * * *", scheduledTime: Date.now() });
});
The DenoScheduleDriver adds no clock of its own — the platform fires the Deno.cron callback, which forwards
into the generated consumer and dispatches inside a fresh Context.run frame. scheduledAt is Date.now()
here, since Deno's cron callback receives no native scheduled-time argument the way Cloudflare's
controller.scheduledTime does.
Deno awaits the async callback before the invocation exits, so deferred work
inside the handler completes with no explicit waitUntil needed.
Platform limits
Deno Deploy is a V8-isolate edge runtime with none of Cloudflare's stateful primitives:
| Feature | Supported |
|---|---|
| HTTP controllers | Yes |
Scheduled cron (@heximon/schedule) | Yes — via Deno.cron() |
Queues (@heximon/queue) | No |
Durable Objects (@heximon/durable) | No |
Workflows (@heximon/workflow) | No |
Durable WebSocket (@heximon/websocket) | No |
Compiling a Durable Object or workflow against DenoDeployStrategy emits a PlatformEdgeUnsupported
diagnostic naming "deno" and the offending class — the build fails before any code is emitted.
A queue
handler gets its own diagnostic, PlatformFeatureUnsupported, for the same reason: the in-memory drain is
ephemeral on an edge isolate and the polling consumers are Node-only, so produce to an external queue from
the edge and consume it on a Node or Lambda worker instead.
Nitro path
On @heximon/nitro with a deno-deploy preset, the Nitro module selects DenoDeployStrategy automatically —
no heximon.platform entry needed on that path. The same DenoWorkerPlugin assembles the entry either way.
Dev
Deno Deploy has no Miniflare equivalent, so vp dev runs your app as a standard Node HTTP server — the
strategy's built-in NodeStrategy dev default — with the full build-error page, JSON preview,
recompile-on-change, and auto-reload preserved.
Ship it
deployctl deploy --project=<your-project> dist/deno-worker.js # add --prod for the production domain
DenoDeployStrategy implements the @heximon/deploy capability, so heximon deploy runs that
same command for you (the project name resolves from DENO_DEPLOY_PROJECT when set, and a "production"
environment adds --prod). Project teardown is dashboard/API-only — deployctl has no delete command, so
there's no heximon deploy --destroy for Deno.
See also
- Schedule —
ScheduledHandler, cron discovery, and the driver abstraction. - Deploy overview — the
supportedFeaturesgate shared across every platform. heximon deploy— the CLI's Deno-specific preflight and--projectresolution.
AWS Lambda
LambdaStrategy, lambda-entry.js, API Gateway HTTP API v2 event adapter, LambdaSqsQueueConsumer, per-invocation OTel flush.
Nitro
Run a Heximon app inside Nitro v3 with heximonNitroModule, heximonNitroVitePlugin for the dev loop, heximon.config.ts, NitroFetchClient, and one server directory that deploys to Node, Cloudflare Workers, Deno, Bun, and AWS Lambda.