Skip to main content

Quick Start

This guide takes a new user from zero setup to custom UI in production.

Prerequisites

  • Python 3.12+ (python --version)
  • uv package manager (install)

The fastest way to get started is using a pre-configured cloud development environment. This handles all dependencies, database setup, and the studio environment for you.

Open in GitHub Codespaces Open in DevPod


Project Setup (from scratch)

mkdir my-project && cd my-project
uv init

# Core runtime
uv add framework-m

# Developer tooling
uv add --dev framework-m-studio

1) Base App

Create your first app package:

uv run m new app crm
cd crm
uv sync

Create your first DocType:

uv run m new doctype Contact

Example Contact DocType (src/crm/doctypes/contact/doctype.py):

from __future__ import annotations

from typing import ClassVar

from framework_m import DocType, Field


class Contact(DocType):
__doctype_name__: ClassVar[str] = "Contact"

first_name: str = Field(description="First name")
last_name: str = Field(description="Last name")
email: str = Field(default="", description="Email address")

class Meta:
requires_auth: ClassVar[bool] = False # Allow access without login (dev)
apply_rls: ClassVar[bool] = False # All users can access all records (dev)
naming_rule: ClassVar[str] = "autoincrement"
api_resource: ClassVar[bool] = True
show_in_desk: ClassVar[bool] = True
permissions: ClassVar[dict[str, list[str]]] = {
"create": ["All"],
"read": ["All"],
"write": ["All"],
"delete": ["All"],
}

Note: if your project has not implemented authentication and a custom permission model yet, keep these Meta defaults so Desk create/read/update/delete works during development.

If you want to implement authentication and role-based access control (RBAC), refer to:

Install database drivers (important):

# Development (SQLite)
uv add --dev aiosqlite

# Production (PostgreSQL)
uv add asyncpg

Set database URL in your app .env (important):

Create crm/.env (the same directory where you run uv run m ...):

# Development (SQLite)
DATABASE_URL=sqlite+aiosqlite:///./dev.db

# Production example (PostgreSQL)
# DATABASE_URL=postgresql+asyncpg://user:password@localhost:5432/crm

If DATABASE_URL is missing at runtime, API create/list routes can respond but won’t persist records.

Run migrations:

For rapid development, use sync to automatically update your database schema based on your DocType definitions:

uv run m migrate sync

Alternatively, use all to run both versioned patches and schema synchronization:

uv run m migrate all

Or follow the traditional Alembic workflow:

uv run m migrate init
uv run m migrate create "Add Contact doctype" --autogenerate
uv run m migrate run

2) Base Desk UI

Start with bundled Desk UI:

uv run m prod

Open http://127.0.0.1:8888/desk/.

Use this when you want ready UI with no custom frontend build.


3) Frontend

Initialize your frontend scaffold:

# Execute from crm root
uv run m new frontend

This creates ./frontend under your crm app and installs dependencies.

Build custom UI when ready:

cd ./frontend
pnpm build
# Switch back to crm root
cd ..

4) Extended UI Apps

Install additional app packages (example):

uv add business-m wms-app

Discovery model:

  • framework_m.apps entry points → backend DocTypes/routes
  • framework_m.frontend entry points → frontend plugin discovery in dev/build flows

5) Extended UI Plugins

Add local/custom plugin entries in your app frontend modules for composition.

Typical flow:

  • add plugin entry files
  • run uv run m dev for live composition
  • run frontend build for production artifacts

Reference docs:


6) m dev

Use this for day-to-day development:

uv run m dev

Current behavior:

  • Backend API server on 127.0.0.1:8888
  • Frontend Vite dev server on 127.0.0.1:5173
  • Hot reload for frontend + backend workflows

7) m prod

Use this for production-style runtime:

# Bundled Desk via backend
uv run m prod

# Custom UI deployment mode (prebuilt dist served by backend)
uv run m prod --with-frontend

Important for --with-frontend:

  • Backend serves prebuilt static from frontend/dist (via FRAMEWORK_M_FRONTEND_DIST)
  • m prod --with-frontend does not run frontend build

For high-scale production, nginx/CDN static serving is optional. Use this reusable nginx template:

It includes placeholders:

  • ${APP_NAME}
  • ${STATIC_ROOT}
  • ${BACKEND_UPSTREAM}

Quick API Check

curl http://127.0.0.1:8888/health
curl http://127.0.0.1:8888/api/meta/doctypes

Next Steps