In the box

Pyxle Studio and the .pyxl debugger.

StudioDebugger

Pyxle — an open-source, full-stack Python framework

Python & React.
One file.

A feature's Python and its React in one .pyxl file — server-rendered, hydrated, and no API layer to keep in sync.

$pip install pyxle-framework

MIT · v0.9.3 · Python 3.10+ · any ASGI host · ~2.2× faster SSR than Next.js →

likes.pyxlone file
# likes.pyxl

@server
async def load(req):
    return {"likes": await db.count()}

@action
async def like(req):
    return {"likes": await db.bump()}


export default function Likes({ data }) {
  const like = useAction('like')
  return <button onClick={() => like()}> {data.likes}</button>
}
The whole feature — it loads, mutates, and renders, with no API in between.

01The file

Eight files was never the point.

The usual React-plus-API stack scatters one feature across eight files, stitched together by convention and hope. In Pyxle it's one file — one read tells you everything it does.

The usual way

  • app/api/likes/route.ts (replaced)
  • lib/validators.ts (replaced)
  • types/likes.d.ts (replaced)
  • hooks/use-likes.ts (replaced)
  • lib/api-client.ts (replaced)
  • components/LikeButton.tsx (replaced)
  • components/LikeButtonSkeleton.tsx (replaced)
  • app/posts/[id]/page.tsx (replaced)
likes.pyxl— the same feature
likes.pyxl24 lines
# likes.pyxl

@server
async def load(request):
    pid = request.path_params["id"]
    return {"id": pid, "likes": await db.likes(pid)}

@action
async def toggle_like(request):
    body = await request.json()
    return {"likes": await db.toggle(body["id"])}


import React from 'react';
import { useAction } from 'pyxle/client';

export default function Likes({ data }) {
    const toggle = useAction('toggle_like');
    return (
        <button onClick={() => toggle({ id: data.id })}>
             {data.likes} likes
        </button>
    );
}
Fig. 1 — likes.pyxl, complete. This is not an excerpt.
02 — Interactive

Change the Python. Watch the page.

The @server loader and @action handlers below execute in genuine, sandboxed CPython; the component renders live in the preview pane. Edit anything — nothing here is a video.

counter.pyxl edit me
Previewsandboxed preview · no install
state lives in Python
0

Edit the code → real Python boots.

Fig. 2 — the playground. Loader and actions run in sandboxed CPython; nothing leaves your browser. Full version at /playground.

03In the box

Everything you'd assemble, already assembled.

No meta-framework archaeology. Pyxle ships the parts a product actually needs, and stays out of the way for the rest.

File-based routingdrop a file in pages/ — it's a route
SSR + hydrationHTML first, interactive after
Hot reloadVite HMR, Python changes included
Server actions@action replaces the API layer
Studioa dashboard for routes, loaders & actions
The debuggerbreakpoints in .pyxl — Python and React
Pluginsauth, database, and your own
ASGI underneathuvicorn today, any host tomorrow

04Studio & the debugger

Two breakpoints, one file.

Set one in the @server loader and one in the React component below it — both bind, in the same .pyxl. The VS Code extension contributes each half as its own F5 launch: Backend runs your dev server under the Python debugger, Frontend attaches the browser to it.

The same run serves Studio at /__pyxle/studio — every route with its loaders and actions, a tester that runs them against the live server, and the request feed as it happens. Dev-only by construction: a production pyxle serve doesn't contain it.

$pyxle studio

routes · tester · request feed · latency · resolved config · pyxle check

$code --install-extension pyxle.pyxle-language-tools

F5 needs the extension · already on Pyxle? pip install --upgrade pyxle-framework

Debug a .pyxl file →Studio, panel by panel →Get the VS Code extension ↗

post.pyxltwo breakpoints
# post.pyxl

@server
async def load(request):
    pid = request.path_params["id"]
    post = await db.post(pid)
    return {"post": post}


export default function Post({ data }) {
  const words = data.post.body.split(' ').length
  return <h1>{data.post.title} · {words} words</h1>
}
Fig. 3 — the loader breakpoint pauses the request in Python; the component breakpoint pauses the render in the browser. Same file, no compiled output to chase.

05The numbers

Measured, not marketed.

Same hardware, same load generator, both frameworks tuned in good faith. When a setup is unfair to a competitor, we fix the setup — not the chart.

faster server-side rendering than Next.js, per core
~2.2×
smaller HTML than Next.js for the same page
2–3×
FastAPI's throughput on database-heavy pages, at 8 workers
1.3×
errors under sustained load

Measured July 2026 on Pyxle 0.7.1, and not re-measured for the 0.9 line. Reproduce them yourself — full methodology, hardware, and harness at /benchmarks →

Beyond raw speed — the full picture against Django, FastAPI, and Next.js is in the comparison →

terminal
$ pyxle check
ℹ️  Checked 2 .pyxl file(s) in my-app/
  error: [python] line 2: expected ':'
    --> pages/feed.pyxl
  error: [jsx] line 6: JSX syntax error: Adjacent JSX elements must be wrapped in an enclosing tag. Did you want a JSX fragment <>...</>? (6:8)
    --> pages/likes.pyxl
❌ Check failed with 2 error(s)
$ echo $?
1
Fig. 4 — pyxle check, verbatim. Structured diagnostics, an exit code an agent can branch on.
pyxle — one file
typical stack — 8 files
Fig. 5 — context per feature read.

06For the agents

One file is also how an agent reads.

Context windows are budgets. A Pyxle feature is one read — loader, mutations, and UI in a single pass, not a scavenger hunt across eight files before the first edit.

And it's all Python — the language models write best.

Read the full case →

07Markdown, built in

Every page is also Markdown.

Your readers increasingly arrive with an AI in the loop — and it wants text, not your HTML. Flip one flag and every page serves a clean Markdown twin: append .md to any URL, or send Accept: text/markdown. This page included.

How it works →

terminal
$ curl pyxle.dev/docs/core-concepts/routing.md
> Markdown rendition of that page,
> served for agents. Index: /llms.txt

# Routing

Pyxle uses **file-based routing**. The
structure of your `pages/` directory is
your URL routes — no router config,
no tag soup, just the words.
Fig. 6 — any URL, plus .md. Turned on with one line: "llms": true.

09Start

Four commands. The fourth is a running app.

  1. pip install pyxle-framework

    installs the compiler, server, and CLI

  2. pyxle init my-app && cd my-app

    scaffolds pages/, config, and a first route

  3. pyxle install

    installs the pinned JS toolchain

  4. pyxle dev

    SSR dev server with HMR at localhost:8000

Then open pages/, add a file, and you've shipped a route. The docs take it from there.

This form is the demo.

The input below posts to an @action defined in index.pyxl — the file that rendered this page. Release notes, occasionally. No noise.

def subscribe_newsletter(request) · validated, rate-limited, and stored by an @action on this server.