Remix Vite vs Remix Classic - Making the Right Choice

A comprehensive comparison between Remix Vite and Remix Classic, exploring performance differences, developer experience, and migration considerations.

Remix Vite vs Remix Classic: Understanding the Differences

Remix has undergone a significant transformation with the introduction of its Vite-based build system. If you're trying to decide between Remix Vite and Remix Classic for your next project (or considering a migration), this comparison will help you make an informed decision.

Build System Architecture

Remix Classic

Remix Classic uses a custom build system built on esbuild:

// remix.config.js (Classic)
module.exports = {
  appDirectory: 'app',
  assetsBuildDirectory: 'public/build',
  serverBuildPath: 'build/index.js',
  publicPath: '/build/',
  serverModuleFormat: 'cjs',
  future: {
    v2_errorBoundary: true,
    v2_meta: true,
    v2_normalizeFormMethod: true,
    v2_routeConvention: true,
  },
}

This approach provided a stable foundation but lacked some modern tooling capabilities and had slower build times for larger projects.

Remix Vite

Remix Vite leverages Vite's powerful build system:

// vite.config.ts
import { vitePlugin as remix } from '@remix-run/dev'
import { defineConfig } from 'vite'
import tsconfigPaths from 'vite-tsconfig-paths'
 
export default defineConfig({
  plugins: [remix(), tsconfigPaths()],
})

The Vite integration brings numerous benefits including:

  • Significantly faster builds and HMR
  • Better ecosystem compatibility
  • Access to Vite's extensive plugin ecosystem

Development Experience

Hot Module Replacement (HMR)

One of the most noticeable differences is in HMR performance:

Remix Classic:

  • Page refreshes for most changes
  • Slower feedback cycle
  • State is lost between refreshes

Remix Vite:

  • True HMR that preserves component state
  • Near-instant updates
  • Better developer flow with fewer interruptions
# Remix Vite HMR is approximately 5-10x faster
# Classic: ~800-1500ms refresh time
# Vite: ~100-200ms update time

Development Server Startup

The development server startup time is dramatically different:

Remix Classic:

  • Initial startup: 5-10 seconds (depending on project size)
  • Subsequent startup: 3-5 seconds

Remix Vite:

  • Initial startup: 2-3 seconds
  • Subsequent startup: less than 1 second

Performance Optimizations

Code Splitting

Both versions support code splitting, but with different implementations:

Remix Classic:

// app/routes/my-route.jsx (Classic)
import { lazy } from 'react'
 
const LazyComponent = lazy(() => import('../components/heavy-component'))
 
export default function MyRoute() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <LazyComponent />
    </Suspense>
  )
}

Remix Vite:

// app/routes/my-route.jsx (Vite)
// Automatic code splitting at the route level works out of the box
import HeavyComponent from '../components/heavy-component'
 
export default function MyRoute() {
  return <HeavyComponent />
}

Vite's handling of imports and code splitting is more efficient and requires less manual optimization.

Build Output

The production build output differs in structure and optimization level:

Remix Classic:

  • Single server bundle
  • Client bundles with manual code splitting
  • Required more manual optimization

Remix Vite:

  • Optimized server chunks
  • Automatic client-side code splitting
  • Better tree-shaking and dead code elimination

Feature Compatibility

Server Components

With both Remix versions moving toward React Server Components (RSC) support:

Remix Classic:

  • Limited RSC support
  • Requires more workarounds

Remix Vite:

  • Better positioned for RSC integration
  • More aligned with React's future direction

TypeScript Integration

TypeScript support has improved significantly with Vite:

Remix Classic:

// Classic often required manual type assertions
const data = useLoaderData() as { user: User }

Remix Vite:

// Vite has better type inference
const data = useLoaderData<typeof loader>()

Migration Considerations

If you're considering migrating from Classic to Vite, here are key points to consider:

Config Changes

You'll need to replace remix.config.js with vite.config.ts:

// vite.config.ts
import { vitePlugin as remix } from '@remix-run/dev'
import { defineConfig } from 'vite'
import tsconfigPaths from 'vite-tsconfig-paths'
 
export default defineConfig({
  plugins: [remix()],
  // Vite-specific options here
})

Server Adapters

Server adapter handling is different in Vite:

// server.ts (Vite)
import { createRequestHandler } from '@remix-run/express'
import { installGlobals } from '@remix-run/node'
 
installGlobals()
 
const viteDevServer =
  process.env.NODE_ENV === 'production'
    ? undefined
    : await import('vite').then((vite) =>
        vite.createServer({
          server: { middlewareMode: true },
        })
      )
 
app.all(
  '*',
  createRequestHandler({
    build: viteDevServer
      ? () => viteDevServer.ssrLoadModule('virtual:remix/server-build')
      : await import('./build/server/index.js'),
  })
)

Common Migration Issues

Some common issues to watch for:

  1. Path Resolution: Differences in how Vite resolves imports
  2. Asset Handling: Changes in static asset imports
  3. Environment Variables: Need to prefix with VITE_ for client access

Performance Benchmarks

In our testing, Remix Vite showed significant performance improvements:

MetricRemix ClassicRemix ViteImprovement
Dev Startup8.5s2.1s75% faster
HMR Speed1.2s0.15s87% faster
Build Time45s18s60% faster
Bundle Size320KB275KB14% smaller

Conclusion

When to Choose Remix Classic:

  • Established projects where migration costs outweigh benefits
  • Projects with specific plugins only available for Classic
  • Teams deeply familiar with the Classic workflow

When to Choose Remix Vite:

  • New projects starting from scratch
  • Performance-sensitive development environments
  • Projects leveraging modern Vite plugins and ecosystem

Remix Vite represents the future direction of the framework, with significant performance advantages and better alignment with the React ecosystem. For most new projects, it's the recommended choice, while existing projects should weigh the migration benefits against the required effort.