Start an Inertia application from sillohq/starter-inertia. The two development processes, and every task the project ships with.
Creating a Project
Section titled “Creating a Project”sillohq/starter-inertia is a
working application: session authentication, a persistent layout, server-side
validation whose errors render on the form, Record, a queue, and a production
asset pipeline. You copy it and make it yours.
sillo-start create-app sillohq/starter-inertia myappcd myappInstall it once if you have not already, uv tool install sillo-start, or pip install sillo-start. See Creating a
Project.
Then install dependencies and set the database up:
uv syncnpm installuv run sillo db:migratepython -m venv .venvsource .venv/bin/activate # Windows: .venv\Scripts\activatepip install -e ".[dev]"npm install
sillo db:migratesillo-start takes the repository as an argument. There is no --inertia
flag, because it fetches a real starter rather than rendering a template. It
renames the project to yours and writes a .env with fresh secrets.
Node is required here as well as Python, because the front end is compiled.
npm install is the one step the standard starter does not have.
Everything on Creating a Project applies here too. The
requirements, what sillo-start does to the files, using your own starter.
This page covers what is different.
Two processes in development
Section titled “Two processes in development”This is the part that catches everyone once.
uvicorn app:app --reload # the application, on :8000npm run dev # the Vite dev server, on :5173 — second terminalThen open http://127.0.0.1:8000.
Both are required. The page is served by Sillo, but it loads its JavaScript
from Vite, so with only uvicorn app:app running you get a blank page and a
console full of failed module requests. With only npm run dev you get nothing
at all. Vite serves modules, not your application.
They are kept as two commands rather than one wrapper on purpose: running both under a single process hides which one printed an error, and the HMR output is worth having where you can see it.
Everything the project does is either the sillo command or an npm script.
sillo on its own lists what this project can do.
uvicorn app:app --reload | The application, with reload. Needs npm run dev alongside |
npm run dev | The Vite dev server |
sillo db:migrate | Apply every pending migration |
sillo db:make add_posts --apply | Write a migration and apply it |
sillo db:plan | Show which migrations would run |
sillo db:rollback 0001_initial | Roll back to a migration |
sillo user:admin ada@example.com ada | Create an administrator |
sillo user:list | List users |
sillo queue:work | Run the queue worker |
npm run build | Compile the front end into static/build |
npm run typecheck | Type-check the front end |
uvicorn app:app | Run as production would. Needs npm run build and VITE_DEV=false |
pytest | The Python suite |
ruff check . / ruff format . | Lint, checking or fixing |
See The Console for what the sillo commands do and
how to add your own.
Testing
Section titled “Testing”pytest runs the Python suite. The tests drive real requests through the
application and assert on the page object, so they cover the handler, the
props, and the adapter together.
What CI runs, in this order:
ruff check . && ruff format --check .npm run typechecknpm run buildpytestThe build before pytest is not incidental. The production-asset tests skip
themselves when there is nothing built, and a check that silently skips its
most fragile assertions is not a check.
Things that will bite you
Section titled “Things that will bite you”A blank page with failed module requests. npm run dev is not running, or
VITE_DEV=false is set with nothing built.
Every module blocked by CORS. The browser is on the Sillo origin and pulls
modules from Vite’s, which is cross-origin. server.cors in vite.config.ts
is set for this reason. Removing it renders the page blank with only a console
error to say so.
A full page refresh on every save instead of HMR. Vite guesses the HMR
host from the page, which is the Sillo origin rather than its own.
server.hmr.host states it.
- Project Structure: what is in the box and where it lives
- Pages and Props: adding a page of your own