sandbox/expose_http.md
You can run dev servers, preview apps, webhook receivers, or framework CLIs on any port and publish them instantly to a secure, random HTTPS URL.
Pass a port when creating the sandbox:
<deno-tabs group-id="sandbox-sdk"> <deno-tab value="js" label="JavaScript" default>import { Sandbox } from "@deno/sandbox";
await using sandbox = await Sandbox.create({ port: 8000 });
console.log(sandbox.id);
await sandbox.fs.writeTextFile(
"main.ts",
"export default { fetch: () => new Response('hello from a sandbox!') }",
);
const p = await sandbox.sh`deno serve --watch main.ts`.spawn();
console.log("deno now listening on", sandbox.url);
await p.output();
from deno_sandbox import DenoDeploy
sdk = DenoDeploy()
with sdk.sandbox.create(port=8000) as sandbox:
print(sandbox.id)
sandbox.fs.write_text_file(
"main.ts",
"export default { fetch: () => new Response('hello from a sandbox!') }"
)
p = sandbox.spawn("deno", args=["serve", "--watch", "main.ts"])
print(f"deno now listening on {sandbox.url}")
p.wait()
from deno_sandbox import AsyncDenoDeploy
sdk = AsyncDenoDeploy()
async with sdk.sandbox.create(port=8000) as sandbox:
print(sandbox.id)
await sandbox.fs.write_text_file(
"main.ts",
"export default { fetch: () => new Response('hello from a sandbox!') }"
)
p = await sandbox.spawn("deno", args=["serve", "--watch", "main.ts"])
print(f"deno now listening on {sandbox.url}")
await p.wait()
This can then be run by setting your Deploy token and executing:
deno run -A --watch main.ts
Setting the --watch flag allows the sandbox to restart automatically when code
changes are detected, for a low-fi hot-reload experience.
The URL stays live for the sandbox lifetime, making it perfect for short-lived QA links or agent generated previews.
Expose HTTP whenever you need to share the sandbox with teammates, bots, or external services:
next dev, astro dev, deno task dev) that should
be inspected from a browserBecause sandboxes are ephemeral, you do not need to manage DNS or certificates.
Each call to exposeHttp() returns a unique hostname under *.sandbox.deno.net
with TLS automatically configured.
All requests to a sandbox's URL will send HTTP traffic to the sandbox.
Sandboxes also support exposing HTTP on-demand:
<deno-tabs group-id="sandbox-sdk"> <deno-tab value="js" label="JavaScript" default>const previewUrl = await sandbox.exposeHttp({ port: 8000 });
console.log(`Preview ready at ${previewUrl}`);
preview_url = sandbox.expose_http(port=8000)
print(f"Preview ready at {preview_url}")
preview_url = await sandbox.expose_http(port=8000)
print(f"Preview ready at {preview_url}")
This is useful when you want to start a sandbox without HTTP exposure, then expose it later (for example, after some initialization or build steps).
:::info Security
When you call this API, the target HTTP service will be PUBLICLY EXPOSED WITHOUT AUTHENTICATION. Anyone with knowledge of the public domain will be able to send requests to the exposed service.
:::
Requests routed through the exposed URL show up alongside your Deploy logs and traces. Use the dashboard to:
sandbox.kill() to terminate the sandbox (and URL) ahead of schedule if
needed.import { Sandbox } from "@deno/sandbox";
await using sandbox = await Sandbox.create();
// Install dependencies
await sandbox.fs.writeTextFile(
"package.json",
JSON.stringify(
{
private: true,
scripts: { dev: "next dev" },
dependencies: {
next: "^15.0.0",
react: "^19.0.0",
"react-dom": "^19.0.0",
},
},
null,
2,
),
);
await sandbox.fs.mkdir("pages", { recursive: true });
await sandbox.fs.writeTextFile(
"pages/index.js",
`export default function Home() {
return (
<main style={{ fontFamily: "system-ui", padding: "2rem" }}>
<h1>Next.js sandbox</h1>
<p>Edit pages/index.js to get started.</p>
</main>
);
}
`,
);
await sandbox.sh`npm install`;
// Start the dev server
const server = await sandbox.spawn("npm", {
args: ["run", "dev"],
stdout: "inherit",
stderr: "inherit",
});
// Publish it
const previewUrl = await sandbox.exposeHttp({ port: 3000 });
console.log(`Preview ready at ${previewUrl}`);
await server.status; // keep running until the process exits
import json
from deno_sandbox import DenoDeploy
sdk = DenoDeploy()
with sdk.sandbox.create() as sandbox:
# Install dependencies
sandbox.fs.write_text_file(
"package.json",
json.dumps({
"private": True,
"scripts": {"dev": "next dev"},
"dependencies": {
"next": "^15.0.0",
"react": "^19.0.0",
"react-dom": "^19.0.0",
},
}, indent=2)
)
sandbox.fs.mkdir("pages", recursive=True)
sandbox.fs.write_text_file(
"pages/index.js",
"""export default function Home() {
return (
<main style={{ fontFamily: "system-ui", padding: "2rem" }}>
<h1>Next.js sandbox</h1>
<p>Edit pages/index.js to get started.</p>
</main>
);
}
"""
)
sandbox.spawn("npm", args=["install"]).wait()
# Start the dev server
server = sandbox.spawn("npm", args=["run", "dev"], stdout="inherit", stderr="inherit")
# Publish it
preview_url = sandbox.expose_http(port=3000)
print(f"Preview ready at {preview_url}")
server.wait() # keep running until the process exits
import json
from deno_sandbox import AsyncDenoDeploy
sdk = AsyncDenoDeploy()
async with sdk.sandbox.create() as sandbox:
# Install dependencies
await sandbox.fs.write_text_file(
"package.json",
json.dumps({
"private": True,
"scripts": {"dev": "next dev"},
"dependencies": {
"next": "^15.0.0",
"react": "^19.0.0",
"react-dom": "^19.0.0",
},
}, indent=2)
)
await sandbox.fs.mkdir("pages", recursive=True)
await sandbox.fs.write_text_file(
"pages/index.js",
"""export default function Home() {
return (
<main style={{ fontFamily: "system-ui", padding: "2rem" }}>
<h1>Next.js sandbox</h1>
<p>Edit pages/index.js to get started.</p>
</main>
);
}
"""
)
proc = await sandbox.spawn("npm", args=["install"])
await proc.wait()
# Start the dev server
server = await sandbox.spawn("npm", args=["run", "dev"], stdout="inherit", stderr="inherit")
# Publish it
preview_url = await sandbox.expose_http(port=3000)
print(f"Preview ready at {preview_url}")
await server.wait() # keep running until the process exits
Using Deno Sandbox in this way allows you to spin up full-featured framework
development servers with minimal code, useful for agents or developers who need
to spin up high-fidelity previews, share them for feedback, and tear everything
down with a single Ctrl+C.