Skip to content

Command Line Interface

The fullfinity-server CLI is the primary tool for managing your Fullfinity installation. It handles server startup, module management, and code generation.

Terminal window
fullfinity-server -c config.yaml [options] [command]

The -c/--config flag is required for all operations.

Terminal window
fullfinity-server -c config.yaml

This starts the server using settings from config.yaml. The API will be available at http://localhost:8000 by default.

Terminal window
fullfinity-server -c config.yaml -db mycompany

In multi-tenant setups, use -db to specify which database to connect to.

Terminal window
fullfinity-server -c config.yaml --host 127.0.0.1 --port 9000

Override the default binding address and port.

Terminal window
fullfinity-server -c config.yaml --workers 8

Override the number of worker processes (default from config file).

Terminal window
fullfinity-server -c config.yaml --rebuild

Rebuilds the React frontend from source (app/) and copies the built files to static/ before starting the server.

All module operations require the -db flag to specify the target database.

Terminal window
fullfinity-server -c config.yaml -db mycompany --update-module-list

Scans the module paths for new or updated modules and registers them in the database. Run this after adding new module folders.

Terminal window
# Install single module
fullfinity-server -c config.yaml -db mycompany -i sales
# Install multiple modules
fullfinity-server -c config.yaml -db mycompany -i sales,invoicing,crm
# Long form
fullfinity-server -c config.yaml -db mycompany --install sales,invoicing

Installs the specified modules and their dependencies. The installation process:

  1. Resolves module dependencies
  2. Runs database migrations
  3. Loads security groups and access rules
  4. Loads views, actions, and menus
  5. Loads seed data
Terminal window
# Update specific modules
fullfinity-server -c config.yaml -db mycompany -u sales,invoicing
# Update all installed modules
fullfinity-server -c config.yaml -db mycompany -u all
# Long form
fullfinity-server -c config.yaml -db mycompany --update all

Updates modules to apply changes:

  • New or modified fields (runs schema migration)
  • Updated views and actions
  • New security rules
  • Updated seed data
Terminal window
fullfinity-server -c config.yaml -db mycompany --uninstall sales

Removes a module and cleans up:

  • Deletes records owned by the module
  • Updates dependent modules to restore their original state
  • Reverts any extensions made by the uninstalled module

Warning: Uninstalling a module may delete user data associated with that module.

Terminal window
fullfinity-server -c config.yaml -db newcompany --init core,sales,invoicing

Combines --update-module-list and --install for new database setup. Use this when setting up a fresh tenant database.

Terminal window
fullfinity-server -c config.yaml -db mycompany -u all --init-only

The --init-only flag performs the module operations and exits without starting the server. Useful for:

  • CI/CD pipelines
  • Database updates in deployment scripts
  • Batch operations

upgrade is an alias for -u all — there is no separate version-based upgrade path. After pulling new code, run either:

Terminal window
git pull origin main
fullfinity-server -c config.yaml -db mycompany -u all # or: ... upgrade

This runs the additive schema sync and replays the schema-change ledger (renames, deletes, complex/data migrations) in one atomic transaction — per installed module, in change-id order. It’s safe to re-run (idempotent) and rolls back wholesale on failure. There are no pre_upgrade/post_upgrade hooks and no framework-version gating.

See Migrations & Upgrades for how schema changes are recorded (check --only schema / resolve) and replayed.

Four verbs manage the schema contract and the build-time consistency gates. All are no-database (they compose the model surface from code) except preview --db.

Runs every build-time gate and exits 1 on any failure, so it can gate CI and pre-commit:

Terminal window
fullfinity-server -c config.yaml check # all gates (report every failure)
fullfinity-server -c config.yaml check --only schema # one gate: schema|views|templates|refs|valkey|manifests
fullfinity-server -c config.yaml check --module sales # scope to a single module
fullfinity-server -c config.yaml check --strict # views/templates gates: enforce the full anchor ruleset
--onlyGate
schemathe append-only field-surface contract (no renamed/removed/retyped field or Selection choice)
viewsview inheritance stability (hooks target stable anchors, never titles/positions)
templatesreport/portal/email template inheritance: extensions target a stable #id/[data-anchor]/field:<chain> in their base (never CSS/content/position), and every base body’s structural nodes are anchor-covered so third parties can extend it
refsevery stored reference — Q-domains, filter-groups, visible_setting, field-paths, model-names, report/email Jinja — resolves against the schema
valkeyno module reaches past env.valstore into an engine-internal Valkey DB
manifestsevery module manifest has the required keys and a valid category

With no --only, all gates run and every failure is reported together.

resolve — record a sanctioned schema change

Section titled “resolve — record a sanctioned schema change”

When check --only schema fails on an intentional rename/removal/retype, record it (details in Migrations & Upgrades):

Terminal window
fullfinity-server -c config.yaml resolve # interactive prompts
fullfinity-server -c config.yaml resolve --assume-renames # auto-record obvious renames
fullfinity-server -c config.yaml resolve --rename Task.due=deadline --delete Task.legacy_note
fullfinity-server -c config.yaml resolve --snapshot --module acme # just (re)write the baseline

Before upgrading a customer install, preview what a release breaks in their custom modules, or render the release changelog (details in Upgrade Transparency):

Terminal window
fullfinity-server -c config.yaml preview --db mycompany # audit an install's custom modules (read-only)
fullfinity-server -c config.yaml preview # release reference changelog (no database)
fullfinity-server -c config.yaml preview --out FILE # write the Markdown to a file

filestore — move a filestore into object storage, and check it landed

Section titled “filestore — move a filestore into object storage, and check it landed”

Attachments live outside the database, so switching FILESTORE_BACKEND from local to s3 means the files have to be copied. The database does not change: an attachment row stores a storage key, and the same string addresses the file on disk and in a bucket.

Terminal window
fullfinity-server -c config.yaml filestore copy --db mycompany --dry-run
fullfinity-server -c config.yaml filestore copy --db mycompany
fullfinity-server -c config.yaml filestore verify --db mycompany

copy uploads every local file the configured backend does not already hold. It is idempotent and safe to run while the instance is serving: anything already there is skipped, so it can be interrupted, re-run, and run a second time after the cutover to carry whatever was uploaded in between. Node-local scratch (import_tmp/) and part-written files are deliberately left behind.

verify answers a different question — whether every attachment row has bytes the backend can actually produce. A copy can be complete and the answer still be no, because a row can outlive its file. It refuses to report success while FILESTORE_LOCAL_FALLBACK is on, since those reads may have been answered from the local disk you are trying to stop depending on.

The full cutover procedure, including where the fallback fits, is in Configuration.

filestore status / adopt / fork — after copying a database with Postgres

Section titled “filestore status / adopt / fork — after copying a database with Postgres”

A database’s files live under an id stored inside it, not under its name (see Multi-tenancy). That is what lets a pg_restore onto new hardware keep its attachments — and it means a copy made outside this application carries the original’s id:

Terminal window
pg_dump prod | psql staging # staging now points at prod's files

Two live databases, one prefix. Deleting files is blocked while that is true, because the database it was copied from is probably still serving them. Nothing can tell that apart from a disaster restore by looking inside the database, so you resolve it:

Terminal window
fullfinity-server -c config.yaml filestore status --db staging # which prefix, and who owns it
fullfinity-server -c config.yaml filestore adopt --db restored # this REPLACES the original
fullfinity-server -c config.yaml filestore fork --db staging # this stands BESIDE it

adopt keeps the files and takes ownership — the disaster-restore case, where the original is gone. fork gives this database a prefix of its own and copies the files into it — the staging case, where both are running. status exits non-zero when a decision is outstanding, so it can gate a deploy.

Databases created, cloned or restored through Fullfinity mint their own id and never need this.

These verbs replaced the earlier artifact-named flags — there are no aliases, so update any scripts or pipelines:

Old flagNew
--check-schemacheck --only schema
--check-views (--strict-views)check --only views (--strict)
--check-referencescheck --only refs
--check-valkey-accesscheck --only valkey
--check-manifestscheck --only manifests
(all gates at once)check
--resolve-schema (--rename/--delete/--complex/…)resolve (same options)
--snapshot-schemaresolve --snapshot
--report / --report-outpreview --db / preview --out
--changelog / --changelog-outpreview / preview --out
Terminal window
fullfinity-server -c config.yaml --module-path ./fullfinity/modules,./modules,/opt/modules

Override the module search paths (the MODULE_PATHS config key). Fullfinity will scan all specified directories for modules.

The new command scaffolds a module with the standard directory structure and sample files.

Terminal window
fullfinity-server -c config.yaml new my_module
# Create it in a specific directory (default: current directory)
fullfinity-server -c config.yaml new my_module --path ./modules

The module identifier must be a snake_case identifier (letters, digits, underscores; not starting with a digit). The scaffolder writes a ready-to-install module:

my_module/
├── __init__.py
├── manifest.yaml # Module metadata
├── models/ # Model definitions (.py) — includes models/__init__.py
├── views/ # UI views, actions, menus (.yaml)
├── security/ # Groups, permissions (.yaml)
├── data/ # Seed data
├── demo/ # Demo data
├── i18n/ # Translations
├── tests/ # Tests (.py)
├── templates/ # Templates
├── routes/ # Custom routes
└── static/src/{css,js}/ # Frontend assets

The generated models/, views/, security/, and tests/ folders contain working sample files (a model, list/form views, an action, a menu, a security group, and a test). After scaffolding, install it:

Terminal window
fullfinity-server -c config.yaml -db mycompany -i my_module

Note: new does not require the -db flag since no database access is needed.

OptionShortDescription
--config-cPath to configuration file (required)
--database-dbTarget database name
--help-hShow help message
OptionDescription
--hostHost to bind to (default: 0.0.0.0)
--portPort to run on (default: 8000)
--workersNumber of worker processes
--rebuildRebuild frontend before starting
--module-pathComma-separated module directories
OptionShortDescription
--install-iInstall modules (comma-separated)
--update-uUpdate modules (comma-separated or “all”)
--uninstallUninstall modules (comma-separated)
--initInitialize modules (update list + install)
--update-module-listScan for new modules
--init-onlyExit after module operations
Terminal window
fullfinity-server -c config.yaml -db mycompany upgrade

Alias for -u all: additive schema sync + atomic ledger replay. Requires -db.

Terminal window
# Scaffold a new module (no -db required)
fullfinity-server -c config.yaml new my_module [--path DIR]

new options:

OptionDescription
nameModule identifier (snake_case), e.g. my_module (positional)
--pathDirectory to create the module in (default: current directory)
Terminal window
# Run the whole suite — creates a self-cleaning ephemeral database automatically
fullfinity-server -c config.yaml test [options]

No -db is needed: the test command creates a fresh, self-cleaning database for the run and drops it afterwards. Omit --module to run every module’s tests against one install (fastest for the full suite); pass --module to filter to one.

test options:

OptionShortDescription
--module-mOnly run tests for this module (omit to run all)
--verbose-vVerbose output
-kOnly run tests whose method name matches this pattern (not class names)
--json-summaryWrite JSON test results to a file
--install-onlyInstall --module and its declared dependencies, then stop — no tests are collected or run. Succeeds if the install and view/security composition did.
Terminal window
# Run the consistency gates (no -db required)
fullfinity-server -c config.yaml check [--only AREA] [--module ID] [--strict]
OptionDescription
--onlyRun one gate: schema, views, templates, view-refs, refs, valkey, manifests, i18n, or keys (default: all)
--moduleScope the check to a single module
--strictViews gate: enforce the full anchor ruleset
Terminal window
# Record a sanctioned schema change / re-snapshot baselines (no -db required)
fullfinity-server -c config.yaml resolve [--snapshot] [--module ID] [decisions…]
OptionDescription
--snapshotJust (re)generate the committed baselines from code (record no change)
--moduleScope to a single module
--assume-renamesAuto-record obvious single-candidate field renames
--rename, --delete, --complex, --rename-choice, --complex-choice, --rename-model, --delete-modelDeclarative, repeatable decisions (non-interactive)
Terminal window
# Upgrade transparency: install audit (--db) or release changelog (no -db)
fullfinity-server -c config.yaml preview [--db DB] [--out FILE]
OptionDescription
--dbAudit an installed database’s custom modules against the current base (read-only)
--outWrite the Markdown to a file instead of stdout
Terminal window
# Create database (via psql or your preferred method)
createdb newclient
# Initialize with core modules
fullfinity-server -c config.yaml -db newclient --init core,sales,crm --init-only
# Start server for the tenant
fullfinity-server -c config.yaml -db newclient
Terminal window
# Pull new version
git pull origin main
# Upgrade after pulling new code (alias for -u all)
fullfinity-server -c config.yaml -db production upgrade
# Start server
fullfinity-server -c config.yaml -db production

upgrade is the whole upgrade: additive schema sync plus ledger replay (renames, deletes, complex/data migrations) in one atomic transaction. There is no separate step, and no version-keyed pre_upgrade/post_upgrade hooks — that mechanism has been retired.

Running Fullfinity under Docker? The image swap comes first and the migration is the same command run inside the container — see Installation → Upgrading.

Terminal window
# Pull latest code (same framework version, module changes only)
git pull origin main
# Update all modules on production database
fullfinity-server -c config.yaml -db production -u all --init-only
# Restart server (handled by process manager)
Terminal window
# Scaffold module structure
fullfinity-server -c config.yaml new custom_module
# Or create manually:
# mkdir -p modules/custom_module/{models,views,data,security,templates}
# Create manifest.yaml, models, views...
# Register the module
fullfinity-server -c config.yaml -db mycompany --update-module-list
# Install it
fullfinity-server -c config.yaml -db mycompany -i custom_module
Terminal window
# Make changes to module code
# Update the module to apply changes
fullfinity-server -c config.yaml -db dev -u mymodule --init-only
# Or update and start server in one command
fullfinity-server -c config.yaml -db dev -u mymodule
CodeMeaning
0Success
1General error
2Configuration error

The CLI reads one environment variable, FULLFINITY_CONFIG_PATH, which records the path to the config file so worker processes (Gunicorn/Uvicorn workers, the job runner) can load it. It is set automatically from the -c/--config flag — you normally don’t set it by hand:

Terminal window
export FULLFINITY_CONFIG_PATH=./config.yaml

Individual configuration keys (DB_HOST, SECRET_KEY, etc.) are not overridable via environment variables — they are read from config.yaml (and a sibling config.local.yaml overlay). See Configuration.

OptionDescription
copy | verifyCopy local files into the configured backend, or check every attachment row resolves
statusWhich filestore prefix this database uses, and whether it owns it
adopt | forkResolve a database copied in by Postgres: take over the prefix, or take a new one
--db DBDatabase to act on (required)
--dry-runReport what would be copied, upload nothing