Project Structure
pyxle init is interactive — the exact files depend on your answers. A default
project (no Tailwind) looks like this:
my-app/
pages/
api/
pulse.py # Example API route
components/
Badge.jsx # Example component using a CSS Module
Badge.module.css # Locally-scoped, hashed class names
styles/
app.css # Global CSS (imported from index.pyxl)
index.pyxl # Home page (Python + React)
layout.pyxl # Root layout wrapper (React only)
public/
branding/ # SVG logos and assets
favicon.ico
AGENTS.md # Conventions guide for AI coding agents
jsconfig.json # Import alias (@/*) + editor hints
vite.config.js # Re-exports Pyxle's generated Vite config
package.json # Node.js dependencies and scripts
pyxle.config.json # Framework configuration
requirements.txt # Python dependencies
.env.local # Generated dev secret (PYXLE_SECRET_KEY) — gitignored
.gitignoreOpting into Tailwind replaces pages/styles/app.css with an
@import "tailwindcss"; entry (and drops the CSS-Module example) — there are no
tailwind.config or postcss.config files. Opting into shadcn/ui adds
components.json and lib/utils.js. See Styling.
Key directories
pages/
The pages directory is the heart of your app. Every .pyxl file here becomes a route, and every .py file under pages/api/ becomes an API endpoint.
pages/
index.pyxl --> /
about.pyxl --> /about
blog/
index.pyxl --> /blog
[slug].pyxl --> /blog/:slug
api/
pulse.py --> /api/pulse
users.py --> /api/usersSee Routing for the full rules.
public/
Static files served directly. Anything in public/ is available at the root URL:
public/favicon.ico-->http://localhost:8000/favicon.icopublic/branding/logo.svg-->http://localhost:8000/branding/logo.svg
.pyxle-build/ (generated at runtime)
Created automatically when you run pyxle dev or pyxle build. Contains compiled Python modules, transpiled JSX, and Vite configuration. This directory is gitignored -- do not edit files here.
.pyxle-build/
server/ # Compiled Python modules from @server blocks
client/ # Transpiled JSX components + composed page/layout wrappers
metadata/ # Per-page metadata (route, loader, head, scripts)
vite.config.js # Auto-generated Vite configurationKey files
pages/index.pyxl
A .pyxl file combines Python server logic with a React component. The scaffold's index page demonstrates:
@serverdecorator for data loading- React JSX for the UI
- The
<Head>component frompyxle/clientfor document<head>elements
# Python section
from datetime import datetime, timezone
from pyxle import __version__
@server
async def load_home(request):
now = datetime.now(tz=timezone.utc)
return {
"version": __version__,
"time": now.strftime("%H:%M:%S UTC"),
"message": "You're ready to build with Pyxle.",
}// JSX section -- receives loader data as props
import React from 'react';
import { Head } from 'pyxle/client';
export default function HomePage({ data }) {
return (
<main>
<Head>
<title>Pyxle App</title>
</Head>
<h1>{data.message}</h1>
<p>Pyxle v{data.version} · {data.time}</p>
</main>
);
}pages/layout.pyxl
The root layout wraps every page. It is JSX-only (no Python section needed):
import React from 'react';
export default function AppLayout({ children }) {
return <>{children}</>;
}pages/api/pulse.py
A plain Python file that serves as an API endpoint. It exports an endpoint callable and returns JSON:
from starlette.requests import Request
from starlette.responses import JSONResponse
from pyxle import __version__
async def endpoint(request: Request) -> JSONResponse:
return JSONResponse({"status": "ok", "pyxle": __version__})pyxle.config.json
Framework configuration. The scaffold ships with a minimal config:
{
"middleware": []
}See Configuration Reference for all available options.
package.json
Defines Node.js dependencies and npm scripts:
| Script | Purpose |
|---|---|
npm run dev |
Alias for pyxle dev |
npm run build |
Alias for pyxle build |
It also declares "engines": { "node": ">=20.19" } (Vite 7's floor). Vite
compiles CSS on both pyxle dev and pyxle build — including Tailwind v4 via
the @tailwindcss/vite plugin when you opt into it — so there's no separate CSS
script. See Styling.
.env.local
Every scaffold generates a .env.local with a unique PYXLE_SECRET_KEY for
development (it signs the CSRF tokens). The file is gitignored — never commit
it; set a real secret in your production environment instead. See
Environment Variables.
jsconfig.json and vite.config.js
jsconfig.json declares the import alias (default @/*) so @/lib/utils
resolves from anywhere; Pyxle wires the same alias into both the Vite build and
the SSR runtime. vite.config.js re-exports Pyxle's generated config so the
wider Vite ecosystem (shadcn/ui, editor plugins) finds a config at the project
root — you normally never edit it.
Next steps
- Learn how
.pyxlfiles work:.pyxlFiles - Understand routing: Routing