From Deno
Deno users will find 3va’s model familiar: everything is denied until you
grant it with --allow-* flags. The module system is different, though.
3va follows Node (package.json + node_modules), not Deno’s URL and
deno.json imports.
What doesn’t carry over
We ran a Deno 2.9 project unchanged:
import { join } from "@std/path"; // from deno.json "imports"
import ms from "ms"; // "ms": "npm:ms@^2.1.3"$ 3va run main.ts
Error: Cannot find module '@std/path'deno.json/deno.jsonc(imports,tasks,compilerOptions) are not read.npm:andjsr:specifiers in source (import ms from "npm:ms@2.1.3") aren’t supported:Cannot find module 'npm:ms@2.1.3'.https://imports aren’t supported.- The
Denoglobal doesn’t exist:Deno.serve,Deno.readTextFile,Deno.env,Deno.Commandall need a Node equivalent.
Step by step
-
Create a
package.jsonwith"type": "module". -
Install each dependency from its registry. 3va picks the registry from
--allow-net, so run one command per registry:3va install @std/path --allow-net=jsr.io # JSR 3va install ms --allow-net=registry.npmjs.org # npmDon’t combine hosts in one command. With
--allow-net=jsr.io,registry.npmjs.org, npm packages are looked up on JSR and fail (the install exits with code 1 and doesn’t add them topackage.json). -
Rewrite imports to bare specifiers:
"npm:ms@^2.1.3"→"ms","jsr:@std/path@^1"→"@std/path". -
Replace
Deno.*APIs:Deno 3va (Node API) Deno.serve(handler)http.createServer()Deno.readTextFile(p)fs.promises.readFile(p, "utf-8")Deno.env.get("X")process.env.XDeno.argsprocess.argv.slice(2)new Deno.Command(cmd)child_process.spawn(cmd)deno task xpackage.jsonscriptsdeno test+@std/assert3va test+expect -
Carry your permission flags over. They map almost one to one:
Deno 3va --allow-read,--allow-write,--allow-net,--allow-envsame names --allow-run--allow-child-process--allow-ffi--allow-ffi--allow-sys,--allow-hrtimeno equivalent -A/--allow-allno single flag; grant each capability One difference: importing local files and packages needs
--allow-readin 3va. Deno allows module loading without it.
Things to keep in mind
- JSR packages are installed without their JSR dependencies.
@std/pathinstalls, but loading it fails withCannot find module '@jsr/std__internal/os'. Until that’s fixed, prefer the npm version of a package when one exists. - Top-level
awaitdoesn’t work correctly yet: at module top level it gives you the Promise itself, and a file with noimport/exportfails to parse. This is very common in Deno code, so wrap such code in anasync function main(). - Web APIs are there:
fetch,Request/Response,WebSocket,URLPattern, web streams,crypto.randomUUID(),structuredClone,import.meta.dirnameandimport.meta.mainall exist. - Type-checking:
deno checkhas no counterpart. 3va strips types without checking them, so runtsc --noEmit(on Node) in CI.