Skip to content

CLI

The juice CLI wraps Vite with Juice-specific commands. It is intentionally thin: most commands delegate to Vite with the Juice plugin pre-configured.

juice create <name>

Scaffold a new Juice app. Creates the project directory, installs dependencies, and sets up the file structure.

juice create my-app
juice create my-app --target bun
juice create my-app --target node
juice create my-app --target cloudflare
juice create my-app --target deno

Valid targets: bun (default), node, cloudflare, deno. The target affects only server.ts (the runtime entry point). Everything else is identical across targets.

Coming from Next.js: equivalent to npx create-next-app. The difference is that Juice asks you where you want to deploy instead of assuming Node.js.

You can also use npx without installing globally:

npx @cmj/juice create my-app

juice dev

Start the Vite dev server with the Juice plugin. Supports all Vite dev flags.

juice dev
juice dev --port 4000
juice dev --host 0.0.0.0

The dev server logs each request with method, path, status, and response time:

  VITE v6.x.x  ready in 150 ms

  Routes:
    /              home.tsx
    /product/:id   product/[id].tsx
    /api/health    api/health.ts

  GET  /              200  12.3ms
  GET  /product/42    200  8.1ms
  POST /api/contact   303  45.2ms
  GET  /not-found     404  2.1ms

The route table is printed on startup so you can verify which routes were discovered. If a route is missing, check that the file is in app/routes/ and has a default export (for pages) or named HTTP method exports (for API routes).

Server components that throw a Response (redirects, 404s) are logged with the thrown status code, not 200.

juice build

Run the dual Vite build: client build first (produces browser chunks, CSS, and the flight manifest), then SSR build (produces dist/server.js). Supports all Vite build flags.

juice build

Output structure:

dist/
  client/           # Static assets (JS chunks, CSS, images)
    assets/
      home-a1b2c3.js
      global-d4e5f6.css
  server.js         # Server bundle
flight-manifest.json  # Updated manifest

When to run: before every deployment. If you see stale routes or missing styles in production, run juice build to regenerate everything.

juice preview

Run the production build locally using Vite preview. Serves the built assets and runs the server bundle. Use this to catch production-only issues before deploying.

juice preview
juice preview --port 4000

Coming from Next.js: equivalent to next start. The difference is that juice preview uses the same fetch handler as your production deployment.

juice routes

List all discovered routes in the project. Shows URL patterns, file paths, associated layouts, middleware, and HTTP method handlers.

$ juice routes

  Route                File                     Layouts    Middleware    Methods
  /                    home.tsx                 layout     middleware    GET
  /about               about.tsx                layout     middleware    GET
  /product/:id         product/[id].tsx         layout     middleware    GET
  /blog                blog/index.tsx           layout     middleware    GET
  /blog/:slug          blog/[slug].tsx          layout     middleware    GET
  /admin/dashboard     admin/dashboard.tsx      layout+1   middleware+1  GET
  /api/health          api/health.ts            --         middleware+1  GET
  /api/users           api/users.ts             --         middleware+1  GET, POST

When to use: debugging. If a URL returns 404 but you expected it to match a route, run juice routes to see what the compiler discovered.

juice add route <name>

Add a new route file to the project. Creates the file with a default export and response export.

juice add route about           # creates app/routes/about.tsx
juice add route blog/[slug]     # creates app/routes/blog/[slug].tsx
juice add route api/users       # creates app/routes/api/users.ts (no React)

Files in api/ directories are created as .ts with HTTP method exports. All others are created as .tsx with a React component.

juice --version

juice --version
juice -v

Prints the installed Juice version. Include this in bug reports.

When NOT to Use the CLI

The CLI is a convenience wrapper around Vite. If you have a custom Vite setup (monorepo with shared config, custom plugins), you can use Vite directly with the Juice plugin:

// vite.config.ts
import { defineConfig } from 'vite';
import juice from '@cmj/juice/vite';

export default defineConfig({
  plugins: [juice()],
});

Then use vite dev, vite build, and vite previewdirectly. The CLI commands are just aliases for these with the Juice plugin pre-loaded.