MUST use when creating raw apps.
Raw apps let you build custom frontends with React, Svelte, or Vue that connect to Windmill backend runnables and datatables.
wmill app new
This interactive command creates a complete app structure with your choice of frontend framework (React, Svelte, or Vue).
my_app__raw_app/
├── AGENTS.md # AI agent instructions (auto-generated)
├── DATATABLES.md # Database schemas (run 'wmill app generate-agents' to refresh)
├── raw_app.yaml # App configuration (summary, path, data settings)
├── index.tsx # Frontend entry point
├── App.tsx # Main React/Svelte/Vue component
├── index.css # Styles
├── package.json # Frontend dependencies
├── wmill.ts # Auto-generated backend type definitions (DO NOT EDIT)
├── backend/ # Backend runnables (server-side scripts)
│ ├── <id>.<ext> # Code file (e.g., get_user.ts)
│ ├── <id>.yaml # Optional: config for fields, or to reference existing scripts
│ └── <id>.lock # Lock file (run 'wmill generate-metadata' to create/update)
└── sql_to_apply/ # SQL migrations (dev only, not synced)
└── *.sql # SQL files to apply via dev server
Backend runnables are server-side scripts that your frontend can call. They live in the backend/ folder.
Add a code file to the backend/ folder:
backend/<id>.<ext>
The runnable ID is the filename without extension. For example, get_user.ts creates a runnable with ID get_user.
| Language | Extension | Example |
|---|---|---|
| TypeScript | .ts | myFunc.ts |
| TypeScript (Bun) | .bun.ts | myFunc.bun.ts |
| TypeScript (Deno) | .deno.ts | myFunc.deno.ts |
| Python | .py | myFunc.py |
| Go | .go | myFunc.go |
| Bash | .sh | myFunc.sh |
| PowerShell | .ps1 | myFunc.ps1 |
| PostgreSQL | .pg.sql | myFunc.pg.sql |
| MySQL | .my.sql | myFunc.my.sql |
| BigQuery | .bq.sql | myFunc.bq.sql |
| Snowflake | .sf.sql | myFunc.sf.sql |
| MS SQL | .ms.sql | myFunc.ms.sql |
| GraphQL | .gql | myFunc.gql |
| PHP | .php | myFunc.php |
| Rust | .rs | myFunc.rs |
| C# | .cs | myFunc.cs |
| Java | .java | myFunc.java |
backend/get_user.ts:
import * as wmill from 'windmill-client';
export async function main(user_id: string) {
const sql = wmill.datatable();
const user = await sql`SELECT * FROM users WHERE id = ${user_id}`.fetchOne();
return user;
}
After creating, tell the user they can generate lock files by running:
wmill generate-metadata
Add a <id>.yaml file to configure fields or static values:
backend/get_user.yaml: