Pareto 3.0
Pareto 3.0 is a ground-up rebuild of the framework. The bundler, the runtime, the state management, and the CLI have all been rewritten. This is the release we’ve been working toward: a lightweight React SSR framework that feels fast to use and fast to ship.
Vite 7 replaces Rspack
Section titled “Vite 7 replaces Rspack”The biggest change in 3.0 is the build system. Pareto 2.x used Rspack (a Webpack-compatible bundler) with separate client and server configurations, Babel transforms, and a complex lazy compiler. All of that is gone.
Pareto 3.0 uses Vite 7 as its build engine. This means:
- Instant dev server startup — Vite’s on-demand module transform means the dev server is ready in milliseconds, not seconds.
- Native ESM in development — No bundling during dev. Modules are served directly to the browser.
- React Fast Refresh — HMR that preserves component state, powered by
@vitejs/plugin-react. - Your Vite plugins work — Any Vite plugin you already use (PostCSS, Tailwind, MDX, etc.) works out of the box. No framework-specific wrappers needed.
- Single config surface — Customize the build by dropping a standard
vite.config.tsin your project root. Pareto loads and merges it automatically. No more juggling separate Rspack configs for client and server.
import { defineConfig } from 'vite'import myVitePlugin from 'my-vite-plugin'
export default defineConfig({ plugins: [myVitePlugin()],})React 19
Section titled “React 19”Pareto 3.0 requires React 19. This gives you access to the latest React features:
use()hook — Read promises and context directly in render.- Actions — Async functions that integrate with transitions.
useOptimistic()— Optimistic UI updates built into React.- Improved Suspense — Better streaming and hydration behavior.
No server components — Pareto continues to use the loader pattern for server-side data fetching. Your components are standard React components that work on both server and client.
Simplified routing conventions
Section titled “Simplified routing conventions”The file-based routing system has been refined. Convention files in 3.0:
| File | Purpose |
|---|---|
page.tsx | Route component |
layout.tsx | Wrapping layout (nests from root to page) |
loader.ts | Separate loader file for server-side data |
head.tsx | Per-route <title> and meta tags |
not-found.tsx | 404 page (root level only) |
error.tsx | Error page — catches loader and render errors |
document.tsx | Document customization — getDocumentProps() for <html> attributes |
route.ts | Resource route (JSON API, no HTML) |
New: loader.ts — You can now define loaders in a separate file instead of exporting from page.tsx. This keeps data fetching logic separate from your components:
import type { LoaderContext } from '@paretojs/core'
export function loader(ctx: LoaderContext) { return { stats: getDashboardStats() }}New: error.tsx — Create an error.tsx at the app root to customize the error page shown when a loader throws or a render error is not caught by a ParetoErrorBoundary. For component-level error isolation, use ParetoErrorBoundary anywhere in the component tree:
import { ParetoErrorBoundary } from '@paretojs/core'
<ParetoErrorBoundary fallback={({ error }) => <p>{error.message}</p>}> <RiskyComponent /></ParetoErrorBoundary>State management improvements
Section titled “State management improvements”defineStore() and defineContextStore() now use Immer for immutable state updates. Write mutations as if you’re mutating directly — Immer produces the immutable result:
import { defineStore } from '@paretojs/core/store'
const { useStore, getState, setState } = defineStore((set) => ({ count: 0, increment: () => set((draft) => { draft.count += 1 // Immer makes this immutable }),}))The store API supports direct destructuring, automatic SSR serialization, and context-scoped stores for per-request isolation.
Security headers
Section titled “Security headers”Pareto automatically applies OWASP-recommended security headers in development. For production, securityHeaders() is exported from @paretojs/core/node for use in custom server setups:
import { securityHeaders } from '@paretojs/core/node'import express from 'express'
const app = express()app.use(securityHeaders())This sets X-Content-Type-Options, X-Frame-Options, Referrer-Policy, Permissions-Policy, Strict-Transport-Security, and Cross-Origin-Opener-Policy headers automatically.
CLI changes
Section titled “CLI changes”The CLI commands remain the same but are now built on cac instead of a custom parser:
pareto dev # Development server with HMRpareto build # Production build (client + server + static)pareto start # Start production serverMigration from 2.x
Section titled “Migration from 2.x”- Update dependencies — Install
@paretojs/core@3and update to React 19. - Remove Rspack config — Delete any custom Rspack configuration files. Create a standard
vite.config.tsin your project root instead — Pareto loads and merges it automatically. - Update error handling —
error.tsxis now optional and provides app-level error pages. UseParetoErrorBoundaryin your layouts/pages for component-level error isolation. - Update imports — The
@paretojs/coreAPI surface is largely the same, but check that your imports match the API reference. - Test your loaders — Loader behavior is unchanged, but verify that your data fetching works with Vite’s dev server.
Try it now:
npx create-pareto@latest my-app