A React 19 RSC framework with 2 dependencies.
Your app is one function: (Request) => Response.
npx @cmj/juice create my-app
cd my-app && bun install && bun run devGet StartedJuice is for teams that want React Server Components without the abstraction tax. If you have used Next.js and wished you could just return a Response from your route handler, or used Remix and wished you had RSC streaming, Juice gives you both.
Use Juice when: you are building a server-rendered app with forms, data fetching, and progressive enhancement. You want to deploy to Cloudflare Workers, Bun, or Deno without runtime-specific adapters. You want the framework to stay out of your way.
Do NOT use Juice when: you are building a single-page app with heavy client-side state (drag-and-drop builders, real-time collaboration, canvas editors). Use Vite with React directly. Juice adds server-side complexity you will not benefit from. Also skip Juice if you need a mature ecosystem with hundreds of plugins and community packages. Next.js has that. Juice does not.
| Concept | Next.js | Juice |
|---|---|---|
| Route handler | Proprietary NextRequest/NextResponse | Standard Request/Response |
| Middleware | Single middleware.ts at root, runs on edge only | Per-directory, onion model, runs everywhere |
| Data fetching | fetch() with magic caching + revalidation | cache(fn) with explicit identity-based dedup |
| Runtime target | Node.js (edge runtime is opt-in, limited) | WinterCG-first: Workers, Bun, Deno, Node |
| Bundle size | ~2MB+ node_modules runtime | 10.7KB gzipped on Cloudflare Workers |
| Streaming | Always on, limited control | Three modes: wait, shell, full stream. You choose. |
Your filesystem is the router config. Layouts, dynamic params, middleware are co-located with the routes they serve.
Server components are async. Fetch data directly in the component. Deduplicate with cache(), not magic.
Forms that work without JavaScript. Progressive enhancement with useActionState. Real POST-Redirect-GET.
Three modes, one decision: do you need correct status codes, fast TTFB, or both? Pick the tradeoff explicitly.
Onion-model middleware with typed context. Pass the authenticated user from middleware to component without prop drilling.
Global CSS, modules, Sass. Vite handles the build. The manifest tracks which CSS belongs to which route.
CSRF protection is on, not opt-in. Client boundary enforcement catches server-only imports at build time.
One fetch handler. Cloudflare Workers, Bun, Deno, Node.js. No runtime-specific code in your app.