Quickstart
To try PyWeb without installing anything, open the playground: it runs the compiler, server rendering and your @server functions in the browser.
#Install
The package is published as pyweb-stack; you import it as pyweb and the command is pyweb.
pip install pyweb-stack # Python 3.10+; no other dependencies
pip install "pyweb-stack[all]" # optional: Postgres, MySQL, Redis, cryptography, uvicorn#Create and run an app
pyweb new hello
cd hello
pyweb dev app.pyweb # http://localhost:8000, reloads on savepyweb new writes app.pyweb, a starter test (test_app.py) and AGENTS.md/CLAUDE.md (instructions for AI coding agents). Add --template todo (or blog, auth, chat, blank) to start from a bigger example. The default counter app is:
from pyweb import App
app = App(title="Hello")
@app.page("/")
def Home():
count = 0
def increment():
count += 1
<main>
<h1>Counter</h1>
<button onclick={increment}>
Count: {count}
</button>
</main>What this compiles to
// Home.js
function Home($s) {
const count = $signal("count" in $s ? $s["count"] : 0);
function increment() {
count($py.add(count(), 1));
}
return [$h("main", null, () => [
$h("h1", null, () => [$t("Counter")]),
$h("button", {"onclick": increment}, () => [
$t("Count: "),
$dyn(() => count())
])
])];
}
$mount("Home", Home);page Home route=/
browser count reactive state: assigned in increment(); literal initial value
browser increment event handler (compiled to JavaScript)<main>
<h1>Counter</h1>
<button>Count: 0</button>
</main>What happened:
countis read by the markup and changed byincrement, so it became a signal. Clicking the button updates only that button's text.incrementwas compiled to a JavaScript function. Nothing is sent to the server when you click.- The first response was complete HTML (
Count: 0), rendered on the server.
Edit the file and save: the dev server recompiles and the browser reloads. If you introduce an error, the page shows it with the line.
#See what the compiler decided
pyweb inspect app.pywebpage Home("/") signals ['count'] rpc []
place count: browser # reactive state: assigned in increment(); literal initial value
place increment: browser # event handler (compiled to JavaScript)#Check, build and serve
pyweb check app.pyweb # compile + security checks (CI-friendly)
pyweb build app.pyweb --out dist --production # hashed, minified, deployable dist/
pyweb serve dist # production server with /healthzdist/ contains your app source, static assets and a Dockerfile; see Deployment.
#Next
The tutorial builds a notes app with a database, server functions and login. Then, depending on what you're building:
- several pages with a shared header: Layouts & navigation;
- pages that update when data changes: Live data;
- chat or other AI features: Building AI apps, or start from
pyweb new myapp --template ai-chat; - charts, maps or editors from npm: npm packages;
- working with an AI assistant: AI assistants & MCP.