-
Notifications
You must be signed in to change notification settings - Fork 0
Bare VM
A fresh Ubuntu box with bun and git runs a scaffolded app's whole gate. No Docker daemon, no
Postgres, no Redis, no NATS, no object store, no .env editing. Bun runs all four commands below;
git is what commits the scaffold, and --no-git is the form that skips it.
bunx create-ultimate demo --no-git
cd demo
bin/setup
bin/check| Command | What it needs from the box |
|---|---|
bunx create-ultimate demo --no-git |
bun, and a network the npm registry answers on. --no-git skips git init, which is the form an automated provisioner uses; without it the scaffold is committed, and that is git's only job here |
cd demo |
— |
bin/setup |
bun. Six steps: bun install, an .env.development.local touch, x db gen "initial" when packages/db/migrations holds no .sql, x db migrate, x db seed, x manifest
|
bin/check |
bun. x build --target static, then x verify — the build first, because budgets weighs .x/build-stats.json and the build is that file's only writer |
x new installs nothing, so bin/setup is not optional and cd demo && bin/check stops on
X_BUILD_FAILED naming bun install (Installation).
The scaffold's .env.development ships committed non-secret defaults, and it leaves DATABASE_URL
empty. An empty DATABASE_URL is not a hole to fill — it is the switch that selects the embedded
database, in resolveServices
(packages/cli/src/runtime-bindings.ts),
which is the one place the three service bindings are decided:
| Binding | Unset env | Resolves to | Set it to |
|---|---|---|---|
| db | DATABASE_URL |
pglite://<app>/.x/pgdata — Postgres compiled to WASM, running inside this process
|
a postgres: URL |
| events | NATS_URL |
inproc://events — in-process fanout |
a NATS URL |
| storage | S3_ENDPOINT |
file://<app>/.x/storage |
an S3 endpoint |
The database is
packages/db/src/pglite.ts:
a real Postgres, WASM-compiled, opened on a directory under .x/, so x db migrate and x db seed
write to the same engine the app then reads — no container to wait for, no port to publish, and a
restart keeps the data. The module is an optional peer resolved at first query, never at import,
so an image that only ever talks to a managed Postgres does not carry the WASM it will never load.
@electric-sql/pglite is a devDependencies entry of the generated app, which is what puts it on
the box during step 1 of bin/setup.
Its absence is a coded refusal, never a silent skip: X_DB_UNAVAILABLE, whose fix: is
bun add @electric-sql/pglite, or set DATABASE_URL to a Postgres server and re-run — a command the
reader runs, on a box that has just told them what is wrong.
x doctor says it earlier than the first query does. Its external-database probe answers nothing
where DATABASE_URL is unset, and that silence is exactly this box, so it asks the embedded
question too: does the peer resolve from the app root — a resolve, never an import, since
loading it boots the WASM and takes the single-writer lock the next command needs. Red only where
DATABASE_URL is unset and the peer is unresolvable (CLI reference).
bin/check's live, job and e2e steps need no service of their own in a generated app: the
queue is Postgres (SELECT … FOR UPDATE SKIP LOCKED), the fanout is in-process, and both resolve
through the table above.
No logical replication. PGlite has no walsender, so there is no write-ahead log to decode and no
slot to take. A --live query still works: x dev installs the in-process bridge instead — the
same row observer the framework's own live tests run on — and the boot line says which feed you
got, live=in-process under the embedded database and live=replication under a real one
(packages/cli/src/runtime-live-feed.ts). Its honest bound is that a write made by another process
is invisible to it, which holds by construction under x dev, where every role is this one process
(Realtime).
Reach for the dev compose file only when you want parity against a real Postgres, NATS and S3 (Deployment). Nothing on this page uses it.
On a WSL2 developer box — not a bare VM, and not a CI runner — on a Bun the CLI's own floor
accepts (x doctor), against real x new scaffolds, first pass, nothing waived and no fix-follow,
warm Bun cache, As of 2026-09-11:
| Measure | Default scaffold | --no-example |
|---|---|---|
| files written | 161 | 133 |
bin/setup |
6,802ms | 5,135ms |
bin/check |
5,389ms | 3,909ms |
the first bin/check's verdict |
green, 20 of 20 steps, budgets included |
green, 20 of 20 steps, budgets included |
The cache is the variable to watch, not the box: a cold first install takes the bun install
inside bin/setup to 12.0s on the same machine.
And on a free ubuntu-latest runner, which is the measurement that speaks for a provisioned
box — ci.yml's scaffold-smoke job, running these same two scripts on a scaffold written outside
the checkout, As of 2026-09-12:
| Measure | Default scaffold | --no-example |
|---|---|---|
| files written | 161 | 133 |
bin/setup |
6,665ms | 5,994ms |
bin/check |
7,279ms | 4,886ms |
the first bin/check's verdict |
green, 20 of 20 steps pass | green, 20 of 20 steps pass |
budgets is green on that first pass on every one of those runs, because bin/check builds before
it verifies — nothing is waived to get there, and no printed fix: is followed before the verdict
is taken. The job prints the table itself, one row per command and one per gate step, so the run is
its own measurement rather than a number this page asserts: read it from the job's log when you want
today's.
Ultimate — v23.0.0 As of 2026-09. Stable API, semver from here. MIT licensed. What npm serves is npm view @ultimat3/core version, never this line.
This footer is the only page that stamps a version. It renders under every wiki page, so one release bumps one line; a stamp on a second page is 46 hand-copies of one fact, and every one of them goes stale on the next tag.
Repository · Issues · Changelog · llms.txt
Edits to these pages are synced from wiki/ in the repository — change the file there, not the wiki, or the next sync overwrites it.
Start
Tutorials
- 1 · First app
- 2 · First feature
- 3 · Auth and admin
- 4 · Jobs and realtime
- 5 · Deploy free
- 6 · Growing up
Primitives
- The eight primitives
- Building your own base
- Actions
- Entities and migrations
- Policies and authz
- Queries and live queries
- Client data
- Jobs and workflows
- Scheduled tasks
- Routes and render modes
Capabilities
- Realtime
- Caching and invalidation
- Batching and preloading
- N+1 detection
- PWA and offline
- Client navigation
- MCP and AI
- Agents
- Admin dashboard
- Scraping
- Auth
- Notify
- Storage and uploads
- Feature flags
- SEO
- Static assets
Cross-cutting
- I18n
- Theming
- UI components
- Interface rules
- Timezones and dates
- Money
- Resource management
- Migrations and backfills
- Testing
- CI: the gate across parallel jobs
Reference