Changelog
Flare ships as three packages that move together — @flaredev/core,
@flaredev/cli and create-flare-framework. They always share a version.
npx flare --version # what this app is onpnpm add -D @flaredev/cli@latest # upgrade itTwelve more field types.
Seven string formats — username, ip, uuid, timezone, locale,
currency, postcode — each with its own validation, input and display. A
time zone is checked against the runtime’s own list rather than a regex, and
the input offers that list; a currency code, a UUID and a postcode are
normalised on the way in.
Three number shorthands: money, percent and rating. The column stays an
ordinary float or int — the shorthand decides the input and the display. Money
gets its currency where the number is and refuses negatives unless the
descriptor allows them. A rating is a row of stars, bounded 0–5 unless you say
otherwise. A percent is left alone, because 150% is a real number.
Two aliases: website for url, alongside the existing phone for tel.
flare rm resource also works on the Next.js stack now. It removed the files
and then reached for drizzle-kit to write a drop migration, on an app that has
no drizzle-kit.
New pages: relationships, covering one-to-many, one-to-one and many-to-many with how each appears in a form, and file uploads, with an example per category.
Cursor paging failed on the Next.js stack for any date-sorted list — which is every list, by default.
A cursor travels through a URL, so a Date crosses it as a number. SQLite
stores dates as milliseconds and wants that number back; Postgres wants a
Date, and answered “Argument lt: Expected DateTime, provided Int”. The
second page of the dashboard’s default view could not load.
The cursor now carries whether its column holds a date — the store knows that from the descriptor, and neither adapter can tell on its own — and the Prisma adapter converts it back before querying.
This had a test, and the test asserted the broken behaviour: a fake delegate
accepts a number where Postgres will not, so { createdAt: { lt: 5 } } looked
right. Found by running a real query against a real database and reading the
SQL.
flare create also no longer stalls for seven seconds before printing
anything: it asked whether pnpm existed by running pnpm --version, and now
reads PATH.
flare diff was only looking at a sixth of the code Flare copies.
It tracked lib/resource and nothing else, so an app could report “up to
date” while its storage adapter, cache, API helpers and every dashboard
component were an old version. 0.7.1’s upload fix lives in lib/storage.ts —
a file flare update could not see, so the fix could never reach an app that
already existed. That is the one job these commands have.
They now cover everything under lib/ and components/ — 116 files in a
fresh app rather than 7 — minus the copies that are the app’s own: anything
rewritten from a placeholder, and lib/auth-config.ts, which is written from
the sign-in methods chosen at create time and differs from its template in
every app there will ever be.
Image uploads on the Next.js stack stored nothing, and said they worked.
Three faults in the same few lines of lib/storage.ts, found by uploading an
actual PNG rather than reading the code. The request body arrives as a stream
and S3 refuses a PUT it cannot measure — 411 MissingContentLength — so it is
buffered now, with the length set by hand, because Next patches the global
fetch and that one does not derive content-length even from a buffered body.
The adapter never checked the response, so a rejected upload returned 201 and
the field stored a key pointing at nothing. And the whole object key went
through encodeURIComponent, turning products/2026/09/a.png into a single
segment containing %2F.
Verified against a real S3 server: signed, uploaded, read back, byte-identical.
flare user:role also works on this stack now. It looked for a D1 database
and failed with “No d1_databases in wrangler.jsonc” — on an app that has no
wrangler.jsonc.
Routes say what they do.
0.6.0 moved the engine into your app, but a generated route still read as
eighteen lines of wiring — createResourceHandlers({ ... }), then four
exports. The code was yours and you still had to be told where it was.
A route now contains its own handlers. Each shows the policy check, the
cross-origin guard, the JSON read, the store call and the response it builds,
in the order they happen. Nothing is repeated between them: the guards are
named functions in lib/resource/http.ts, so the CSRF check, the
content-type check and the body drain that stops an early return breaking the
next request through wrangler’s dev proxy all still live in one place.
createResourceHandlers is still there and still works. Routes generated
before this release keep running; regenerate one with
flare gen resource <Name> --force to get the longer form, or leave them.
The Prisma engines download could fail, and took the install with it.
0.6.1 allowed @prisma/engines to run its postinstall, which downloads engine
binaries. When that download fails — a slow link, a proxy, anything —
pnpm install failed with it, after the packages were already on disk, so the
app looked installed and wasn’t.
It is refused now. A Flare app on the Next.js stack reaches Postgres through a
driver adapter and never needs what that postinstall fetches. Confirmed without
it: prisma generate, prisma validate, prisma migrate diff and
next build all work, and the install is quicker for it.
A new Next.js app couldn’t finish its first install.
pnpm install stopped with ERR_PNPM_IGNORED_BUILDS, naming four versions
of esbuild. 0.6.0 gave each stack its own list of dependency build scripts to
allow, and esbuild was left off the Next.js one — the Vercel CLI depends on
it, so every new Next.js app hit this on the very first command after
scaffolding.
The two lists are now one, the union of what either stack needs. Naming a package a stack doesn’t install costs nothing, because the entry is never consulted; leaving one out breaks the first thing somebody runs. Both stacks’ entries are pinned by tests, and the fix was confirmed by running both installs rather than re-reading the list.
The code that runs your endpoints moved into your app.
Until now a generated route was eighteen lines that called
createResourceHandlers, and the eight hundred lines that actually did the
work — query parsing, validation, hooks, pagination, constraint errors, the
database adapters — sat in node_modules. You could not read them, and you
certainly could not change them.
They now live in your repository, at lib/resource/, on both stacks. Nothing
generated imports the framework’s server entry any more. Ctrl-click
createResourceHandlers and you land in your own code.
Nothing is hidden explains the reasoning and states
both halves of the trade, because there is a cost: a fix in a later release
no longer reaches you on its own. flare diff shows what changed upstream
and flare update applies it, refusing to run without --yes.
The store takes rows now instead of a table and a database, so the adapter
is named where you can see it — drizzleRows(products, getDb) or
prismaRows(prisma.product, prisma). You can tell which database a route
talks to by reading the route.
Upgrading takes no work. An app made before the move has no
lib/resource/, and its next flare gen resource writes one, naming each
file as it goes. Routes generated by 0.5.x keep running untouched, because
the package still exports what it always did.
Also in this release: flare dev, build, start and deploy work on the
Next.js stack, delegating to Next and the Vercel CLI instead of telling you
to run something else. Every app gets a 404 page, an error page and loading
skeletons shaped like the page they wait for. File fields show a thumbnail
rather than an object key. Dependencies install with pnpm whenever it is on
the machine, because an app is around 340 packages and npm takes minutes
where pnpm takes seconds. And there is an
agent skill, an llms.txt and a prompt on every
docs page, for building with an AI.
The stack question, which 0.5.0 shipped without.
flare create --stack next worked, so every test passed and the gap stayed
invisible: the interactive flare create never asked which stack you wanted.
Anyone who answered the prompts rather than passing flags got Cloudflare and
was never offered the choice, which is the opposite of the point.
It is the first question now, because it decides the database, the ORM and
the host that everything else is built around. The docs learned to mention
--stack too — it had been documented on the stacks page and nowhere a new
person looks first.
A second stack: Next.js, Postgres and Prisma.
flare create --stack next builds an app on Next.js 16, Neon Postgres and
Prisma 7, from the same descriptors, with the same dashboard, the same
validators and the same policies. What changes is the schema, the migrations
and where it deploys. Choosing a stack compares them
properly, including what the Next.js one cannot do.
The resource store was split from its database access to make this possible: one interface, about fifty lines, with a Drizzle implementation and a Prisma one behind it. Everything a resource means stayed shared, which is why a unique-constraint error says “Sku is already taken” on both.
A catalogue on Next.js builds one against a real Postgres, with ranked full-text search and honest measurements — including the case where the index is the slower choice.
Selling a download, and the things that stopped it working.
The shop tutorial gained a till and digital delivery, the drive tutorial gained folders and multi-file upload, and building both turned up four gaps worth fixing rather than working around.
One deserves naming: every font 404’d in production. Tailwind inlines CSS
@import rules, so the fontsource imports never became real requests. Moving
them into the root layout emitted all fifty files.
flare deploy --yes arrived, and the file grammar was finally written down.
Your code, in plain sight.
Hooks, computed values and endpoints of your own, with a page explaining where each belongs and what regeneration will overwrite.
Tables grew up: a chart, chosen columns, saved views, editing in place, and pagination built for tables that got big. Every record got its own page, every account section got its own, and the sidebar got headings.
The dev server starts in about a minute now, rather than several.
One dashboard, and auth screens that say what they want.
The admin became a single coherent area rather than a set of generated pages, and every sign-in screen learned to explain itself — which method, what it needs, what happens next.
Seeding got serious: hundreds of thousands of rows, batched, with unique columns unique by construction rather than by retry.
Auth, themes, and an API that documents itself.
Every sign-in method — passwords, magic links, email codes, passkeys, two-factor by app or email, and social providers — chosen at create time and wired for you. Six themes, also chosen at create time.
Field types grew the formats that change both validation and rendering:
email, tel, url, domain, country, color, slug, plus select,
radio and multiselect.
Every app now serves an OpenAPI 3.1 document generated from its descriptors and its policies, rendered as a reference page, so the documentation cannot drift from the API.
The first one.
flare create, flare gen resource, and a resource descriptor that becomes
a table, a migration, validators, a REST API, a typed client and admin
screens.
The full history is in CHANGELOG.md and the GitHub releases.