Reference

Upgrading to 0.3.5

0.3.5 makes devora start do less work per request (about a fifth to a third more requests per second on pages and API routes, measured on one machine), gives a missing session store or secret one clear message, and adds guides for live updates (WebSockets) and background jobs. Nothing in a typical app needs a change. If you are on 0.3.3 or older: 0.3.3 was prepared but never published, so its changes are in 0.3.4, and the 0.3.4 and 0.3.2 changes are listed below too.

Steps

  1. Upgrade @devorajs/core and @devorajs/cli together, in the root package.json and every app's: "^0.3.5". API routes run on the CLI's bundled copy of core and pages on the app's installed one, so mixing versions gives one project two behaviors.
  2. If you import an adapter directly, use @devorajs/adapter-node 0.2.1, @devorajs/adapter-vercel 0.2.3 or @devorajs/adapter-netlify 0.2.4 (devora bundles the adapters, so most projects don't depend on them at all). Earlier adapter-node 0.2.0 and the 0.2.2 adapters were published without their build output and are deprecated.
  3. Install, then run npm run typecheck, npm run dev and npm run build.
  4. Go through the tables below and change what applies to your app.

TypeScript: ctx.params keeps its type (Record<string, string>), so existing code compiles unchanged. A catch-all's segments are joined with / there, and ctx.catchAll.slug (or req.catchAll.slug in an API route) is the string[].

From 0.3.4 to 0.3.5

What changedWhat to do
A missing session store, or (in production) a missing DEVORA_SESSION_SECRET, stops devora start with one clear line and exit status 1 instead of a stack trace. It refused to start before and still does.Nothing to do. Add sessions: { store: "memory" } under shared in devora.config.ts (one long-running server) or a store backed by your database, and set the secret.
ctx.url and ctx.headers are built the first time a handler reads them. Reading them is unchanged (the same URL and Headers objects every time). They are now getters, so assigning to them throws in strict mode.Nothing to do unless your code assigns ctx.url or ctx.headers; the types never marked them read-only and nothing in the framework assigns them.
A rebuilt island or client-route manifest is picked up within a second, instead of on the next request.Nothing to do, as built static files already work this way.
The header's brand link has the accessible name devora.js home (it was Home, which did not contain its visible text).A test that selects it by aria-label="Home" needs the new name.

From 0.3.2 to 0.3.4

What changedWhat to do
A file named [...name].tsx or [[...name]].tsx is now a catch-all route. Before, it was a single [param] whose name started with dots.If you have such a file, rename it, or expect it to match more URLs (/docs/a/b/c, not only /docs/a). Nothing else needs to change: ctx.params values are still strings.
A URL path containing a dot no longer ends at the static-file lookup. If no public file exists at that path, it goes on to route matching (so /docs/v1.2/intro can reach a catch-all).Nothing to do. A real file under the public folder still wins.
getStaticParams() values are percent-encoded in the output path: a value with a space or non-ASCII characters is written under its encoded path, which is what url.pathname holds.Nothing to do unless you read dist/static by hand.
sitemap.xml now lists the URLs of dynamic routes that export getStaticParams().Nothing to do; check the file if you post-process it. A dynamic route without getStaticParams() is still left out.
devora start answers any method other than GET and HEAD to a public file, a built asset or a pre-rendered (ssg) page with 405 and Allow: GET, HEAD. It used to return the file.A form that posts to a pre-rendered page never ran an action there; post to an ssr route instead.
Pre-rendered pages are sent with Cache-Control: public, max-age=0, must-revalidate and an ETag (a repeat visit gets a 304). Pages and files are held in memory — 64 MB in total, 2 MB per file, larger ones streamed — and re-checked against the disk once a second.Nothing to do. A rebuild into a running server shows up within a second; changed route code still needs a restart. See Deployment.
With sitemap off, a hand-written public/sitemap.xml is served. It used to 404 in production.Nothing to do. Turn sitemap on if you want the generated one (it takes precedence).

From 0.3.1 to 0.3.2

0.3.2 was a large release for a patch number: request access in loaders, actions that return data, error pages, a <head> API, uploads, cookie and proxy settings, CORS, .env loading and a fixed Vercel runtime. Most of it is new options; this is what can change how an existing app behaves.

What changedWhat to do
Redirects after a POST are 303 See Other (were 302); loader redirects stay 302.Browsers behave the same. Tests or clients that assert 302 after a form post: update them, or pass redirect(to, 302).
Page errors keep their status: a thrown HttpError (or anything with a 4xx/5xx status) is that status, not a 500 — requireAuth() is 401, verifyCsrf() 403. Errors and unmatched URLs render error.tsx or a built-in page, in dev too.Anything that treated every page failure as a 500 should check the status. Add an error.tsx for your own error page.
The framework stylesheet and favicon are only added to pages that render PageShell or AppHeader (and CSR shells).A page that relied on the theme without the shell needs head: { theme: true } in app.config.ts or its meta().head.
PageShell wraps its content in <div class="devora-shell">; the theme no longer sets body { display: flex }.Adjust custom CSS that depended on body being the flex container, or on main being a direct child of #root. Props are unchanged.
The theme no longer defines --devora-bg-elevated (it has --devora-surface and more tokens). Not in the CHANGELOG; found upgrading this site.If your CSS uses it, replace it with var(--devora-surface) or define it yourself: :root { --devora-bg-elevated: var(--devora-surface); }. A manual light/dark switch that overrides tokens should override the new ones too.
A backend-only app answers GET / with 200 (JSON for API clients, a small HTML page for browsers). It was a 404.Monitors that expected 404 there are fine to keep using /api/health.
Request bodies are limited to 10 MB by default (maxBodyBytes, forms and API routes); larger ones get a 413. Malformed multipart is a 400.Apps that accept larger uploads set maxBodyBytes in app.config.ts.
.env files in the project root are loaded by dev, build, start and deploy; variables already in the environment win.Check the project root for stale .env files, and drop node --env-file wrappers.
devora start reads PORT and HOST (--port/--host still win).A PORT left in the environment now moves the server; unset it or pass --port.
devora build --adapter= anything other than vercel/netlify fails, instead of building without the requested output.Scripts using --adapter=node drop the flag: devora build, then devora start.
The Vercel runtime is no longer nodejs20.x (Vercel rejects it): vercel.runtime, else the running Node major, else engines.node, else nodejs24.x.Nothing, unless you need a specific runtime. An engines.node no supported runtime satisfies fails the build.
adapter-vercel empties .vercel/output before writing it.Don't keep files of your own in that directory.
The generated Vercel and Netlify functions trust the platform's proxy headers (trustProxy: true unless the app sets false).Nothing, unless the function can be reached without going through the platform's edge.
devora build only imports ssg/isr routes (and routes whose render mode isn't a string literal).Nothing, unless a build relied on a request-time route running at build time.
Unsupported island() calls (island(loader), a computed path, a path that doesn't resolve) fail the build and dev server with the file and line.Fix the reported call to island(() => import("./path")).
Session config that used to be ignored is an error: session settings on an auth: "none" app, a cookie.domain that doesn't cover the app, per-app lifetimes on a shared app.Fix or remove the setting the error names.
devora dev's boot output has a new layout: every app's URLs first, then routes per app; more than 10 API routes per app are counted.Anything that parsed the old output should use --routes and match the new lines.

Before deploying to Vercel, check the preflight output of devora build --adapter=vercel (runtime, a top-level api/ folder, session secret and store), and see Deployment.

Worth adopting while you're here

Move API routes out of a top-level api/ folder if you deploy to Vercel (apiDir: "endpoints"), set trustProxy behind nginx/Caddy, and replace hand-rolled query-string parsing with ctx.url. See Pages, forms and errors and Backend.

The complete list per package is in the CHANGELOG.