The web-dev template ships Node 20, npm, yarn, pnpm, plus the
Next.js, Vite, Prisma, Drizzle, Tailwind, ESLint, and Prettier CLIs
pre-installed globally. Pick it when you want an agent to bootstrap,
edit, and build a React / Next frontend without a multi-minute cold
npm install on every run.
What you’ll learn
- Picking
template="web-dev" to skip Node + tooling installs
- Creating a new Next.js app with
npx create-next-app offline-cached
- Writing a page and running
next build against it
Prerequisites
export DECLAW_API_KEY="your-api-key"
export DECLAW_DOMAIN="your-declaw-instance.example.com:8080"
Code
import textwrap
from declaw import Sandbox
PAGE = textwrap.dedent("""
export default function Home() {
const stats = { orders: 42, revenue: 1337.5, uptime: "99.9%" };
return (
<main className="min-h-screen bg-slate-900 text-slate-50 p-8">
<h1 className="text-3xl font-bold">Declaw demo</h1>
<ul className="mt-4 space-y-2">
{Object.entries(stats).map(([k, v]) => (
<li key={k}>
<span className="text-slate-400">{k}: </span>
<span className="font-mono">{String(v)}</span>
</li>
))}
</ul>
</main>
);
}
""")
def main() -> None:
sbx = Sandbox.create(template="web-dev", timeout=240)
try:
for tool in ("node --version", "next --version", "tailwindcss --help | head -1"):
r = sbx.commands.run(tool, timeout=15)
print(f"{tool:<35} => {(r.stdout or r.stderr).splitlines()[0]}")
# Scaffold a Next.js app. Flags make it non-interactive.
r = sbx.commands.run(
"cd /tmp && npx --yes create-next-app@latest app "
"--ts --tailwind --eslint --app --no-src-dir "
"--import-alias '@/*' --use-npm --skip-install",
timeout=120,
)
if r.exit_code != 0:
print("scaffold failed:", r.stderr[:800])
return
# Overwrite the default home page with our own content.
sbx.files.write("/tmp/app/app/page.tsx", PAGE)
# Install deps + build.
r = sbx.commands.run(
"cd /tmp/app && npm install --silent && npx next build",
timeout=300,
)
if r.exit_code != 0:
print("build failed:", r.stderr[-1200:])
return
print("build succeeded — last 12 lines:")
print("\n".join(r.stdout.strip().splitlines()[-12:]))
# Inspect the output directory structure.
r = sbx.commands.run("ls -1 /tmp/app/.next/server/app 2>/dev/null | head")
print("\nrendered routes:")
print(r.stdout)
finally:
sbx.kill()
if __name__ == "__main__":
main()
import "dotenv/config";
import { Sandbox } from "@declaw/sdk";
const PAGE = `
export default function Home() {
const stats = { orders: 42, revenue: 1337.5, uptime: "99.9%" };
return (
<main className="min-h-screen bg-slate-900 text-slate-50 p-8">
<h1 className="text-3xl font-bold">Declaw demo</h1>
<ul className="mt-4 space-y-2">
{Object.entries(stats).map(([k, v]) => (
<li key={k}>
<span className="text-slate-400">{k}: </span>
<span className="font-mono">{String(v)}</span>
</li>
))}
</ul>
</main>
);
}
`;
async function main(): Promise<void> {
const sbx = await Sandbox.create({ template: "web-dev", timeout: 240 });
try {
for (const cmd of ["node --version", "next --version", "tailwindcss --help | head -1"]) {
const r = await sbx.commands.run(cmd, { timeout: 15 });
const line = (r.stdout || r.stderr).split("\n")[0];
console.log(`${cmd.padEnd(35)} => ${line}`);
}
let r = await sbx.commands.run(
"cd /tmp && npx --yes create-next-app@latest app " +
"--ts --tailwind --eslint --app --no-src-dir " +
"--import-alias '@/*' --use-npm --skip-install",
{ timeout: 120 },
);
if (r.exitCode !== 0) {
console.log("scaffold failed:", r.stderr.slice(0, 800));
return;
}
await sbx.files.write("/tmp/app/app/page.tsx", PAGE);
r = await sbx.commands.run(
"cd /tmp/app && npm install --silent && npx next build",
{ timeout: 300 },
);
if (r.exitCode !== 0) {
console.log("build failed:", r.stderr.slice(-1200));
return;
}
const tail = r.stdout.trim().split("\n").slice(-12).join("\n");
console.log("build succeeded — last 12 lines:");
console.log(tail);
r = await sbx.commands.run("ls -1 /tmp/app/.next/server/app 2>/dev/null | head");
console.log("\nrendered routes:");
console.log(r.stdout);
} finally {
await sbx.kill();
}
}
main().catch(console.error);
Expected output
node --version => v20.x
next --version => 14.x
tailwindcss --help | head -1 => tailwindcss v3.x
build succeeded — last 12 lines:
▲ Next.js 14.x
- Environments: .env.local
...
Route (app) Size First Load JS
┌ ○ / ... ...
...
rendered routes:
page.js
create-next-app pulls packages from the npm registry — add a
SecurityPolicy with domains registry.npmjs.org and
registry.yarnpkg.com if you have a domain allowlist configured.