Runtime

How to preview a Next.js app an AI agent built

Run next dev in the agent's sandbox with spawn, allow *.runtimehost.com in allowedDevOrigins, and share port 3000 as a preview.

On Runtime each agent's app gets its own microVM and a private HTTPS address in one call. The app never runs on your servers, the address needs a token unless you make it public, and hot reload works because previews carry WebSockets. The sandbox has Node.js 24.21.0; Next.js 16.3.6, current on 25 September 2026, needs 20.9 or later.

Run the agent's app

Upload what the agent wrote, or scaffold a fresh project, then start the dev server and share it:

TypeScriptimport { Sandbox } from "withruntime";const nextConfig = `import type { NextConfig } from "next";const nextConfig: NextConfig = { allowedDevOrigins: ["*.runtimehost.com"] };export default nextConfig;`;const sbx = await Sandbox.create({ timeoutSeconds: 3600 }); // keeps running after this script endsawait sbx.exec("npx create-next-app@16.3.6 site --yes --use-npm --disable-git", {  check: true,  timeoutMs: 600_000,  env: { NEXT_TELEMETRY_DISABLED: "1" },});await sbx.files.write("/workspace/site/next.config.ts", nextConfig);await sbx.spawn("npx next dev -p 3000", {  cwd: "/workspace/site",  env: { NEXT_TELEMETRY_DISABLED: "1" },});await sbx.exec("npx wait-on@9.1.0 http://127.0.0.1:3000", { check: true, timeoutMs: 180_000 });const preview = await sbx.previews.create(3000);console.log(preview.urlWithToken); // a one-time link for your browser
Pythonfrom withruntime import SandboxNEXT_CONFIG = """import type { NextConfig } from "next";const nextConfig: NextConfig = { allowedDevOrigins: ["*.runtimehost.com"] };export default nextConfig;"""sbx = Sandbox.create(timeout_seconds=3600)sbx.exec("npx create-next-app@16.3.6 site --yes --use-npm --disable-git",         check=True, timeout_ms=600_000, env={"NEXT_TELEMETRY_DISABLED": "1"})sbx.files.write("/workspace/site/next.config.ts", NEXT_CONFIG)sbx.spawn("npx next dev -p 3000", cwd="/workspace/site", env={"NEXT_TELEMETRY_DISABLED": "1"})sbx.exec("npx wait-on@9.1.0 http://127.0.0.1:3000", check=True, timeout_ms=180_000)print(sbx.previews.create(3000)["urlWithToken"])

For a project the agent already wrote, replace the scaffold with sbx.files.upload("./site", "/workspace/site") and npm ci. Upload the source without its node_modules: packages installed on a Mac carry native binaries for the wrong system.

Why allowedDevOrigins matters

In development, Next.js blocks requests for dev-only assets and endpoints that come from an origin other than localhost, its subdomains or the hostname the server started with. A preview's hostname is a name under runtimehost.com, so without an entry the page loads but the dev assets it asks for are refused with 403, and the dev server logs "Blocked cross-origin request to Next.js dev resource". Hot reload then never connects.

Setting Effect
No entry Next.js blocks the preview's requests for dev assets
allowedDevOrigins: ["*.runtimehost.com"] Every preview address works; * covers one label, which is all a preview uses
next start (production) No dev endpoints, so the setting does not apply

Next.js matches only the hostname of the request's Origin, so write the entry without https:// and without a port.

Dev server or production build

Question next dev next build then next start
Does an edit show at once? Yes, over hot reload No; rebuild first
Does it match what users would get? Close, but compiled on request Yes
Who should open it? The person watching the agent work A reviewer, a client, a demo
Preview visibility Private, with the one-time link Public, or private for a reviewer

To share the finished app:

TypeScriptimport { Sandbox } from "withruntime";const sbx = await Sandbox.connect(process.env.SANDBOX_ID ?? "");const build = await sbx.exec("cd site && npx next build", {  timeoutMs: 900_000,  onStdout: (text) => process.stdout.write(text),});if (build.exitCode !== 0) throw new Error(build.stdout + build.stderr);await sbx.spawn("npx next start -p 3001", { cwd: "/workspace/site" });await sbx.exec("npx wait-on@9.1.0 http://127.0.0.1:3001", { check: true, timeoutMs: 120_000 });const demo = await sbx.previews.create(3001, { visibility: "public" });console.log(demo.url);

A failed build is useful to the agent too: next build checks types, so send its output back as the next message and the agent sees each error with its file and line.

How much disk a Next.js app takes

A fresh create-next-app@16.3.6 project, measured on a Linux x86-64 machine on 25 September 2026:

Part Size
node_modules 476 MB
.next after next build 39 MB
npm's download cache, ~/.npm 769 MB

That fits the default 4 GiB disk, which has about 2.5 GiB free, with room to spare. An agent that adds many packages, or a monorepo, needs more: ask for diskMiB: 8192 when you create the sandbox. The trial allows up to 10 GiB.

Start from an image with the dependencies installed

Build the project's dependencies into a custom image with a Dockerfile. The lockfile comes first, so a rebuild after a code change reuses the installed packages:

dockerfileFROM runtimeENV NEXT_TELEMETRY_DISABLED=1WORKDIR /workspace/siteCOPY package.json package-lock.json ./RUN npm ci --no-fund --no-auditCOPY . .RUN chown -R 1000:1000 /workspace/site
Pythonfrom withruntime import Runtimeruntime = Runtime()with open("site/Dockerfile") as handle:    runtime.images.build(name="site", dockerfile=handle.read(), context_dir="site",                         on_log=lambda line: print(line["text"]))sbx = runtime.sandboxes.create(image="site")sbx.spawn("npx next dev -p 3000", cwd="/workspace/site")print(sbx.previews.create(3000)["urlWithToken"])

Keep node_modules and .next in .dockerignore, so the build context holds only the source.

Sources

Checked 25 September 2026.

Facts on this page were checked on 25 September 2026.