Skip to main content
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()

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.