Pre-release Changes
-
BREAKING CHANGE: Legacy package-aligned
remix/*aliases have been removed in favor of canonical entrypoints that group related APIs together. Update imports when moving from beta.5 to beta.6:- import { requireAuth } from 'remix/auth-middleware' - import { createPostgresDatabase } from 'remix/data-table-postgres' - import { createRouter } from 'remix/fetch-router' + import { requireAuth } from 'remix/middleware/auth' + import { createPostgresDatabase } from 'remix/data-table/postgres' + import { createRouter } from 'remix/router'
The same canonical structure applies to the other entrypoints: middleware lives under
remix/middleware/*, database dialects underremix/data-table/*, storage adapters underremix/file-storage/*andremix/session-storage/*, and route definitions move fromremix/fetch-router/routestoremix/routes. -
BREAKING CHANGE:
createAssetServer()fromremix/assetsnow usesallowFilesanddenyFilesinstead ofallowanddenyfor file path access rules:import { createAssetServer } from 'remix/assets' export const assetServer = createAssetServer({ - allow: ['app/routes.ts', 'app/**/public/**'], - deny: ['app/**/*.test.*'], + allowFiles: ['app/routes.ts', 'app/**/public/**'], + denyFiles: ['app/**/*.test.*'], }) -
BREAKING CHANGE:
remix/cookienow treats customencodeanddecodefunctions as the complete cookie value codec. Custom encoded values are signed and serialized as-is instead of being wrapped in Remix's default base64 encoding. The default codec keeps the existing base64-safe representation. -
BREAKING CHANGE: Route patterns now use delimiter-bounded params. Params stop at raw
/and., but not-, so a pattern such as/:year-:monthmust become one inseparable param such as/:date, or place the captures in separate path segments. Ambiguous adjacent captures are now rejected, and matching work is bounded to prevent pathological patterns (see #11651). -
BREAKING CHANGE: Href helpers from
remix/route-pattern/hrefandremix/routesnow take search parameters in asearchParamsoptions property:- const href = userRoute.href({ id: '123' }, { tab: 'settings' }) + const href = userRoute.href( + { id: '123' }, + { searchParams: { tab: 'settings' } }, + )
The options object also accepts a
baseURLfor generating path-relative same-origin hrefs. Route matching accepts the same option for relative URL strings, andsearchParamsaccepts both typed objects andURLSearchParams. -
BREAKING CHANGE:
remix/middleware/sessionnow makes session cookies HTTP-only whenhttpOnlyis omitted. SethttpOnly: falseexplicitly if client-side JavaScript must read the cookie.Cookie.httpOnlyfromremix/cookienow returnsboolean | undefinedso omitted and explicitly disabled settings can be distinguished. -
BREAKING CHANGE: Run tests with
remix testinstead of the removedremix-testexecutable, and move settings fromremix-test.config.tsor.jsinto thetestproperty ofremix.json:- remix-test --type server --concurrency 1 + remix test --type server --concurrency 1
The programmatic
runRemixTest()API fromremix/test/clinow accepts typed runner options instead of raw command-line arguments. The test runner also adds--onlyfor matching suite or test names,--quietfor omitting skipped tests, and defaultsNODE_ENVtotestwhen it is not already set (see #11623, #11628). -
BREAKING CHANGE: Browser frame resolvers now receive one options object instead of positional
signalandtargetarguments:- async function resolveFrame(src, signal, target) { + async function resolveFrame(src, options) { + const { signal, target } = options ?? {} // ... }
-
Add an
allowPackagesoption tocreateAssetServer()fromremix/assets. This allows a package and its dependencies to be served without listing every file the package may load:import { createAssetServer } from 'remix/assets' export const assetServer = createAssetServer({ allowFiles: ['app/routes.ts', 'app/**/public/**'], allowPackages: ['remix'], })
-
Added a new
remix dbworkflow for inspecting migration status, migrating, seeding, wiping, and resetting the current app database. Configure a built-in SQLite, PostgreSQL, or MySQL database inremix.json; for example:{ "$schema": "https://remix.run/schemas/remix.json", "db": { "adapter": { "type": "sqlite", "filename": "./db/app.sqlite", }, "migrations": { "directory": "./db/migrations", }, "seed": "./db/seed.sql", }, }The same configuration then powers the complete local database lifecycle:
remix db status remix db migrate remix db seed remix db reset --force
Command flags override configured values, database commands work from project subdirectories by finding the nearest
remix.json, and destructivewipeandresetcommands require--force(see #11608, #11639). -
Added an optional JSONC
remix.jsonfile for sharedremix db,remix test, andremix doctorsettings. Relative paths and globs resolve from the configuration file, command-line options take precedence, and the globalremix --config <path>option selects a different file (see #11628, #11638, #11639). -
Added complete
createPostgresDatabase(),createMysqlDatabase(), andcreateSqliteDatabase()factories throughremix/data-table/postgres,remix/data-table/mysql, andremix/data-table/sqlite. These return theDatabaseused for queries and lifecycle operations such asmigrate(),migrationStatus(),reset(),wipe(), andclose()(see #11608, #11639).BREAKING CHANGE: Replace the removed adapter and migration-runner APIs with a concrete database and its lifecycle methods:
- import { createDatabase } from 'remix/data-table' - import { createPostgresDatabaseAdapter } from 'remix/data-table/postgres' + import { createPostgresDatabase } from 'remix/data-table/postgres' - const db = createDatabase( - createPostgresDatabaseAdapter({ connectionString: process.env.DATABASE_URL }), - ) + const db = createPostgresDatabase({ + connectionString: process.env.DATABASE_URL, + }) - await migrationRunner.migrate() + await db.migrate(migrations)
Applications should use a dialect factory; database integration packages can extend
Databasewith a composedDatabaseDriverfromremix/data-table. -
Beta.6 adds an integrated full-stack hot module replacement workflow. Run
npm run hmrin a newly generated project to reload server modules and update compatible UI components in place while preserving their state.New projects include the script and a complete
hmr.tsrunner. The core setup looks like this:{ "scripts": { "hmr": "NODE_ENV=development node hmr.ts" } }// hmr.ts (excerpt) import { run } from 'remix/node-hmr' const hmrRunner = run('server.ts', { nodeArgs: ['--import', 'remix/node-tsx', '--import', 'remix/ui-hmr/node'], browserHmrChannel: { port: 44101 }, })
remix/node-hmr,remix/ui-hmr, andremix/assetscoordinate server and browser updates through the standardimport.meta.hotAPI. Browser-reachable source is scaffolded in colocatedpublic/directories so the server/browser boundary remains explicit. -
Remix UI navigation now progressively enhances same-origin forms into frame navigations. Forms support
rmx-target,rmx-document, andrmx-history="push|replace"; resolvers receive native submission data and may return aResponse, including redirected responses whose final URL becomes the top frame's canonical location. The newrmx-preserve-domattribute protects client-owned subtrees such as custom elements during reloads, andrun()exposesapp.framesfor inspecting the current frame collection. -
This beta also improves runtime reliability across the stack. UI hydration, document navigation, and frame reloads no longer stall, lose newly rendered siblings, retain stale server-rendered content, or reload the wrong top-frame URL in the fixed edge cases. Styled components adapt to dark color schemes, and server-rendered CSS safely escapes values that could close a
<style>element. Node handlers now receive nativeRequestinstances, response compression varies caches correctly byAccept-Encoding, proxied responses discard stale encoding and framing headers, and multipart parsing rejects overlong boundaries without stalling non-Node runtimes. -
Bumped
@remix-run/*dependencies:assets@0.5.0async-context-middleware@0.3.5auth@0.2.7auth-middleware@0.2.5cli@0.4.0compression-middleware@0.1.13cookie@0.6.0cop-middleware@0.1.8cors-middleware@0.1.8csrf-middleware@0.1.8data-table@0.4.0data-table-mysql@0.5.0data-table-postgres@0.5.0data-table-sqlite@0.6.0fetch-proxy@0.8.5fetch-router@0.21.0form-data-middleware@0.3.5form-data-parser@0.17.5logger-middleware@0.3.5method-override-middleware@0.1.13multipart-parser@0.16.4node-fetch-server@0.14.1node-hmr@0.1.0render-middleware@0.1.5response@0.3.8route-pattern@0.24.0session-middleware@0.4.0static-middleware@0.4.13test@0.6.0ui@0.5.0ui-hmr@0.1.0
{ "$schema": "https://remix.run/schemas/remix.json", "test": { "type": ["server"], "concurrency": 1, "quiet": true, }, }