Skip to content

Installation

Almasix is a Python web framework with expressive structure and first-class async/await for ASGI (the async server interface apps run on). Create applications with almasix new, then drive them with Smith — Almasix’s in-app CLI:

terminal
pipx install almasix
almasix new blog
cd blog
# .venv comes next — see below — then:
python smith migrate
python smith serve

Templates, routing, validation, localization, and the ORM all live behind the almasix.* package. You write application code; Almasix boots the container, compiles your routes, and serves them over ASGI.

  • Python 3.11 or higher
  • A way to install the global almasix installer — pipx (recommended) or uv (uv tool install)
  • A project virtual environment for each app (or uv, which the scaffold prefers when it finds it)
  • Node.js 18+ for the Vite stacks — the none stack needs no Node at all

Install the framework once on your machine so almasix is on your PATH. That global install only gives you the project generator — each application still gets its own .venv with Almasix as a normal dependency. Modern Python distributions block bare pip install … into the system environment (PEP 668); use a tool installer instead.

  1. Install the almasix CLI globally (pick one):

    terminal
    pipx install almasix
    # or:
    uv tool install almasix

    Developing against a local checkout of the framework? Install that tree into an isolated tool environment the same way:

    terminal
    pipx install --editable /path/to/almasix
    # or:
    uv tool install --editable /path/to/almasix
  2. Create a new application. Run it bare and it asks; pass flags and it asks only about what you left out:

    terminal
    almasix new blog
    terminal
    Which frontend stack?
    ● Tailwind CSS — Vite + Tailwind CSS 4 (recommended default)
    Bootstrap — Vite + Bootstrap 5 Sass
    Plain CSS — Vite, no CSS framework
    No frontend build — Server-rendered Prism only — no Node, no build step
    Which database will this application use?
    ● SQLite
    PostgreSQL
    MySQL
    MariaDB
    Scaffold a pytest suite (tests/)? smith test runs it
    Initialize a git repository?
    Install Python dependencies now? creates .venv, then pip/uv install -e .
    Run npm install and npm run build?
    Run the default migrations? creates users, sessions, cache, and the queue tables
  3. Create a virtual environment and install dependencies — unless you answered yes to creating a .venv and installing (which did it for you):

    terminal
    cd blog
    python -m venv .venv
    source .venv/bin/activate
    pip install -e .

    With --install (or answering Yes at the prompt), almasix new creates .venv, runs pip/uv install -e ., and installs the database extra when you picked PostgreSQL/MySQL/MariaDB.

  4. Run the migrations. Every new app is scaffolded with the default migrations (users, password_reset_tokens, sessions, plus cache and queue tables). Unless you already answered yes to running them:

    terminal
    python smith migrate
  5. Build the frontend (any stack except none):

    terminal
    npm install
    npm run dev # dev server with hot reload, while you work
    npm run build # hashed files in public/build, for a deploy
  6. Start the development server:

    terminal
    python smith serve

    Visit the URL Smith prints (typically http://127.0.0.1:3000).

Every prompt has a command-line option and a documented default, so the same almasix new is usable by a person and by a CI job. --no-interaction (or -n) asks nothing and takes the defaults below.

Question Flag Default without interaction
Frontend stack --stack tailwind|bootstrap|plain|none tailwind
Database --database sqlite|pgsql|mysql|mariadb|mongodb sqlite
pytest suite under tests/ --tests / --no-tests scaffolded
git repository --git / --no-git, --branch NAME not initialized
Python dependencies --install / --no-install, --installer auto|uv|pip not installed (creates .venv + pip install -e . when yes)
npm install && npm run build --npm / --no-npm run for Vite stacks when npm is on PATH
Default migrations --migrate / --no-migrate not run (scaffolds users/sessions/cache/jobs; runs them when yes)
Where the app is created --path DIR the working directory
Which stubs to scaffold from --stubs DIR Almasix’s own
terminal
# Scripted, start to finish: a Bootstrap app on PostgreSQL, in a git repo,
# with dependencies installed and migrations run.
almasix new shop -n --stack bootstrap --database pgsql --git --install --migrate

Two questions are skipped rather than asked when the answer could only be one thing: npm when the stack has no package.json or npm is not installed, and the migrations when the dependencies they need are not being installed.

Without a terminal — a pipeline, a Dockerfile, a subprocess — there is nobody to answer, so almasix new behaves as though -n were passed and takes the defaults in the table above. It never installs a package or touches a database that nothing asked it to: a prompt’s displayed default is Yes for the person at the keyboard who almost always wants it, and the documented default is No for the script that did not say.

almasix stacks lists the stacks and databases without creating anything.

Stack Ships Error views
tailwind Vite + Tailwind 4, rich landing/auth/layouts, branded errors Tailwind-classed
bootstrap Vite + Bootstrap 5 Sass, same UI kit Bootstrap-classed
plain Vite + hand-written CSS (Almasix brand tokens), same UI kit default bundle, kit overrides
none no Node; public/css/app.css; same UI kit default bundle, kit overrides

Every stack scaffolds two layouts (layouts/minimal, layouts/app), a branded landing page, login/register, a dashboard, and stack-styled error pages — centered on the application name with Almasix orange accents.

The three Vite stacks ship vite-plugin-almasix.js, a dozen lines that write public/hot while the dev server runs. Prism’s @vite directive reads that file: while it exists the tags point at the dev server, and once it is gone they point at the manifest npm run build wrote. See Asset Bundling.

The stack also picks which error-view bundle is published into resources/views/errors/, then the stack’s own richer error stubs overwrite those files so a 404 matches the CSS the application loads. Change your mind later with smith errors:publish --bundle.

SQLite works out of the box, and the installer creates database/database.sqlite for you. The other engines need their driver:

terminal
pip install almasix[pgsql] # PostgreSQL
pip install almasix[mysql] # MySQL
pip install almasix[mariadb] # MariaDB
pip install almasix[mongodb] # MongoDB (Articulate documents)
pip install almasix[sqlsrv] # SQL Server
pip install almasix[oracle] # Oracle (optional)
pip install almasix[db] # all SQL engines above (not Mongo)

--database writes the matching .env block. For the SQL engines it also points config/database.py’s default at that connection. Choosing mongodb configures MONGODB_* for Articulate document models and still keeps SQLite as the SQL default so the scaffolded users/sessions/cache/jobs migrations can run. Every other connection stays in the file, ready for an environment variable to select it. See Database: Getting Started and Document stores.

database/migrations/ in a new application is not empty. Three migrations create the tables the framework itself reads:

Migration Tables Read by
0001_01_01_000000_create_users_table users, password_reset_tokens, sessions auth guards, the password broker, SESSION_DRIVER=database
0001_01_01_000001_create_cache_table cache, cache_locks CACHE_STORE=database, and cache locks
0001_01_01_000002_create_jobs_table jobs, failed_jobs QUEUE_CONNECTION=database, failed-job commands

If you removed one and want it back — or you switched a driver and now need a table you did not before — each has a command:

terminal
smith cache:table # cache, cache_locks
smith queue:table # jobs
smith queue:failed-table # failed_jobs
smith session:table # sessions
smith notifications:table # notifications (the database notification channel)

Those commands and the scaffold render the same stub, so a generated migration cannot disagree with what the driver expects.

A fresh application looks like this:

blog/
blog/
app/
http/controllers/
models/user.py
providers/
bootstrap/app.py
config/
database/factories/user_factory.py
database/migrations/ # three default migrations
database/seeders/
resources/css/
resources/js/
resources/views/welcome.prism.html
routes/web.py
routes/api.py
tests/
package.json
vite.config.js
vite-plugin-almasix.js
smith

Read more in Directory Structure and Asset Bundling.

The scaffold is a stub tree, not strings inside the installer, so a team can publish it, edit it, and create every future application from its own copy:

terminal
smith stub:publish --scaffold # stubs/scaffold/{app,stacks}/…
# edit stubs/scaffold/app/routes/web.py.stub, then:
almasix new next-app --stubs stubs/scaffold

Placeholders are the same ones the make:* generators use — {{ app_name }}, {{ app_display }}, {{ db_connection }}, {{ db_env }}, {{ frontend_section }} — and an unknown one is left as written, so a Prism template’s own {{ slot }} survives being scaffolded.