Repository navigation
Loco 1.2.0
Ships a Loco skill so coding agents write idiomatic Loco without guessing,
adds presigned storage URLs, row-level multi-tenancy, Tera components and
Postgres-only builds, and fixes a long list of defects in the app loco new
generates β including a server-side app that returned 404 at /.
Upgrading: nothing to do for most apps. Two behaviour changes are listed
below; neither needs an edit unless you were relying on the old behaviour.
Breaking
-
perform_later_with_prioritynow returns an error when no queue provider
is configured. It previously logged and handed back a fabricated job id,
so an app with a misconfigured queue was told every enqueue had succeeded.
It now returnsError::QueueProviderMissing. (#1821, @mccormickt) -
ExprTraitis no longer re-exported from the prelude. It is
impl<T> ExprTrait for T where T: Into<Expr>, and primitives are
Into<Expr>, so it reached every value in every file that globs the
prelude:n.max(1)stopped compiling, andn.eq(&3)kept compiling while
returning anExprinstead of abool. Import it explicitly if you need
it.
Added
-
Presigned storage URLs.
ctx.storage.presign_get(path, ttl)and
presign_put(path, ttl, PresignPutOptions)hand a client a time-limited URL
that talks to S3, Azure Blob or GCS directly, so large uploads and downloads
skip the app. Drivers that cannot presign return an error; on
ReplicatedStrategypresigning is primary-only. (#1827, @robertazzopardi) -
Row-level multi-tenancy, behind the opt-in
multi-tenancyfeature.
TenantEntitynames an entity's tenant column,.in_tenant(id)scopes
selects and bulk updates/deletes, andset_tenantassigns the key on new
records and refuses to overwrite a different one. Scoping is explicit at the
call site; a query without.in_tenantis unscoped. (#1824, @shuvroroy) -
TeraView::render_componentrenders a single Tera 2 component by name,
autoescaped likerender. Plus a guide to converting Tera 1 templates to
Tera 2 with an AI assistant, covering the places it gets subtly wrong.
(#1822, @schungx) -
Postgres-only builds. SQLite support is now its own
db-sqlitefeature,
on by default. Apps that setdefault-features = falseand leave it out
skiplibsqlite3-sysand its C toolchain entirely. (#1828, @robertazzopardi) -
A Loco skill for coding agents.
skills/loco/carries the framework's
doctrine, a generated API index coveringloco-rsand Sea-ORM, and ten
task recipes.loco newwrites it into every generated app under
.claude/skills/loco/, matched to that app's crate version, and it is
served at https://loco.rs/skills/loco/.cargo xtask agent-skill --check
keeps the derived outputs from drifting out of step with the source. -
Batch job enqueueing.
perform_all_later(&ctx, args_list)and
perform_all_later_with_priorityenqueue many jobs in a single round trip,
atomically, on all three backends. Fanning out with a loop of
perform_latercost N round trips and could leave the queue half-populated
when one of them failed. (#1821, @mccormickt) -
cargo loco task user:deletein generated apps, besideuser:create.
Takes a pid, prints the user it matched, and confirms before deleting;
force:trueskips the prompt for scripted use. (#1708, @floscodes)
Fixed
-
A Redis worker could stop draining its queue while the process stayed
up.redis1.x changed its default connect timeout from none to one
second and its response timeout to 500ms, so on a small instance booting
against a managed Redis the worker failed to connect and exited; a dropped
connection mid-run also ended it. Workers now use explicit timeouts, retry
with backoff, and reconnect on a dead socket. (#1831, @mikosco4real) -
A server-side app returned 404 at
/.assets/views/home/hello.html
shipped with a test that rendered it and no route that served it, so the
first URL anyone opened was a 404. Generated apps now ship
controllers/page.rsand a request test that exercises the route rather
than the template. -
Nine defects in the generated SPA. No sign-up page β the SaaS starter
ships JWT auth as its headline feature and told users to
curl POST /api/auth/register. A Vite dev proxy hardcoded to port 5150
while the backend readsPORTfrom config, so overriding the port sent
every/apicall somewhere else. A dead-endHome.tsx. Booleans rendering
as blank cells in both list and detail views. List and detail disagreeing
on which column holds the title, producing links with no text. And
vite buildnever typechecking, because esbuild strips types without
checking them β it is nowtsc -b && vite build. -
Scaffolded controller actions were all routed as
GET.createwas
reachable byGET,deletebyGET. Actions are now wired to the verb
their name implies, and the generated tests call them that way. -
TypeScript bindings were written for apps with no frontend.
#[ts(export)]is a side effect ofcargo test, not an annotation, so
running the suite in an--assets noneapp conjured a
frontend/src/bindings/tree out of nothing. -
The generated model test asserted nothing. It booted the app, seeded,
and returned. It now queries the entity, which fails when the migration and
the entity disagree β a renamed column, a type that does not round-trip, a
migration that never ran. -
The generated Dockerfile pinned a Rust older than the crate's MSRV, so
cargo loco generate deployment docker && docker buildfailed on a freshly
generated app. -
The prelude withheld Sea-ORM query traits every app needs. It carried
QueryFilterbut notQueryOrder, so.filter()compiled and
.order_by_desc()on the next line did not β reported as a missing method
rather than a missing trait. Loco had been working around this in its own
generated scaffold. -
The prelude's
Pagerre-export was not gated behindwith-db, so
every DB-less app failed to compileloco-rsitself.
Docs
- "The Tour" rewritten against what the generator actually emits today.
(#1829, @Data5tream) - Indonesian README. (#1823)
- A copy-paste agent prompt for upgrading 1.0 β 1.1.
- The Japanese README could not reach the English or Spanish translations.
Internal
- CI pinned its toolchain instead of floating on
stable, which meant new
pedantic and nursery lints turned master red on a calendar rather than on a
change.stylealso gated seven other jobs, so a lint error in an
unrelated file reported build, test, msrv and examples as SKIPPED β two
contributors spent two weeks looking at a red X that was ours. A weekly
lint:futurejob now runs the same lints onstableandbetaso the
next set arrives as a scheduled failure instead of on someone's PR.