Skip to main content
Remix 3 is built on a fundamentally different architectural philosophy than traditional web frameworks. Rather than a monolithic framework, Remix is a collection of single-purpose, composable packages that work together seamlessly while remaining independently useful.

Design Principles

Remix follows six core principles that guide every architectural decision:
AI fundamentally shifts the human-computer interaction model. Remix optimizes source code, documentation, tooling, and abstractions for LLMs while providing abstractions for applications to use models in the product itself.
Sharing abstractions across the stack reduces context switching for both humans and machines. Remix builds on Web APIs and JavaScript as the only true full-stack ecosystem.
All packages are designed with no expectation of static analysis. Remix avoids the API pollution that comes from designing for bundlers, compilers, and typegen. All tests run without bundling.
Dependencies lock you into someone else’s roadmap. Remix chooses dependencies wisely, wraps them completely, and expects to replace most with its own packages. The goal is zero external dependencies.
Every abstraction is single-purpose and replaceable. Composable abstractions are easy to add and remove from existing programs. Every package is documented and useful independent of any other context.
While extremely composable ecosystems can be difficult to learn, Remix is distributed as a single remix package for ease of use. However, all individual packages can also be used standalone.

Package Architecture

Remix is organized as a pnpm monorepo with packages in the packages/ directory. Each package has a single responsibility and prioritizes web standards for maximum interoperability.

Core Package Categories

Routing & Server

  • fetch-router - Composable router for the Fetch API
  • node-fetch-server - Node.js server with Fetch API
  • route-pattern - URL pattern matching with strong typing

Data Handling

  • multipart-parser - Streaming multipart parsing
  • form-data-parser - FormData parsing with file uploads
  • data-schema - Standards-aligned schema validation
  • data-table - Typed, relational query toolkit

Storage & Files

  • file-storage - Key/value storage for File objects
  • lazy-file - Lazy, streaming file implementation
  • fs - Filesystem utilities using Web File API

HTTP Utilities

  • headers - HTTP headers toolkit
  • cookie - Cookie management
  • response - Response helpers
  • session - Session management

Module Boundaries

Remix maintains strict boundaries between packages:
// ✅ Good: Import from the owning package directly
import { parseHeaders } from 'remix/headers'
import { createRouter } from 'remix/fetch-router'

// ❌ Avoid: Re-exporting APIs from other packages
// Each package should be imported independently
Package Export Structure:
  • All exports in package.json map to dedicated files in src/
  • Files in src/lib/ are implementation files (not public API)
  • Top-level src/ files define public API by re-exporting from src/lib/
  • No barrel-style re-exports between src/lib files

Composability in Practice

Remix packages are designed to be composed incrementally. You can start with a single package and add more as needed.

Example: Building a Server

Start with just the router:
import { createRouter } from 'remix/fetch-router'
import { route } from 'remix/fetch-router/routes'

let routes = route({
  home: '/',
  about: '/about',
})

let router = createRouter()

router.map(routes, {
  actions: {
    home: () => new Response('Home'),
    about: () => new Response('About'),
  },
})
Add middleware as needed:
import { logger } from 'remix/logger-middleware'
import { staticFiles } from 'remix/static-middleware'
import { formData } from 'remix/form-data-middleware'

let router = createRouter({
  middleware: [
    logger(),
    staticFiles('./public'),
    formData(),
  ],
})
Connect to Node.js:
import * as http from 'node:http'
import { createRequestListener } from 'remix/node-fetch-server'

let server = http.createServer(createRequestListener(router.fetch))
server.listen(3000)

Example: Standalone Package Usage

Every package works independently:
// Use multipart-parser without any other Remix packages
import { parseMultipartRequest } from 'remix/multipart-parser'

async function handleUpload(request: Request) {
  for await (let part of parseMultipartRequest(request)) {
    if (part.isFile) {
      console.log(`File: ${part.filename} (${part.size} bytes)`)
      await saveFile(part.filename, part.bytes)
    }
  }
}
// Use lazy-file without any other Remix packages
import { LazyFile } from 'remix/lazy-file'

let lazyFile = new LazyFile(lazyContent, 'video.mp4', {
  type: 'video/mp4',
})

// Stream directly to a Response
return new Response(lazyFile.stream(), {
  headers: {
    'Content-Type': lazyFile.type,
    'Content-Length': String(lazyFile.size),
  },
})

Distribution Strategy

Remix provides two ways to install and use packages:
The unified remix package re-exports all individual @remix-run/* packages through TypeScript’s subpath exports. This provides a cohesive experience while maintaining strict internal boundaries.

Testing Philosophy

All Remix tests run from source with no build step required:
# Run tests directly on TypeScript source
node --test './packages/*/src/**/*.test.ts'
This enforces the “Religiously Runtime” principle - if code requires bundling or compilation to work, it violates Remix’s architectural principles.
Every package must be testable without static analysis, bundling, or compilation beyond TypeScript and JSX transforms.

Benefits of This Architecture

Start with a single package and add more as needed. No need to commit to an entire framework upfront.
Each package has a well-defined responsibility, making it easier to understand and maintain.
Built on web standards means your code works everywhere and doesn’t depend on framework-specific APIs.
Don’t like a package? Replace it with your own or a third-party alternative. Composition makes it easy.
Every package works across Node.js, Bun, Deno, and Cloudflare Workers without modification.

Next Steps

Web Standards

Learn how Remix leverages web standards for maximum portability

Composability

Explore patterns for composing Remix packages

Runtime Agnostic

See how Remix runs everywhere without modification

API Reference

Browse the complete API documentation

Build docs developers (and LLMs) love