How many times have you had an exciting idea for a side project or prototype, only to spend your entire evening configuring boilerplate?

Before writing a single line of business logic, you are already stuck wrestling with:

  • Initializing a React SPA with Vite and configuring TypeScript.
  • Creating an Express backend, configuring a separate tsconfig.json, and setting up tsx or ts-node for live reloads.
  • Linking client and server via npm workspaces so you don’t have to copy-paste DTOs and interfaces across two separate codebases.
  • Juggling scripts to run both servers concurrently without port collisions or CORS headaches.

By the time the dev environment is finally wired up, half the creative momentum has vanished.

The common alternative is reaching for heavy meta-frameworks like Next.js or Remix. While powerful, they introduce opinions, complex SSR rules, and runtime abstractions you might not actually need. Sometimes, you just want a clean, decoupled client and a standalone Express API that share TypeScript contracts.

To end this boilerplate paralysis once and for all, I built Duoo.


What is Duoo?

Duoo is a minimal, lightning-fast starter generator for building full-stack applications with Node.js, Express, React, and Vite in a unified TypeScript monorepo.

Instead of hiding configuration behind complex build magic, Duoo gives you a clean and explicit architecture:

  • Client: React + Vite (instant HMR, lightning-fast builds).
  • Server: Node.js + Express (tsx watch for sub-millisecond API restarts).
  • Shared: A zero-dependency shared package for DTOs, request/response schemas, and contracts.
  • Workspaces: Native npm workspaces orchestrated with concurrently.

End-to-End Type Safety (Zero Codegen)

The biggest headache in decoupled architectures is keeping client and server contracts in sync. Duoo solves this out of the box with native workspace referencing.

Define your payload interfaces once inside shared/src/index.ts:

// shared/src/index.ts
export interface User {
  id: string;
  name: string;
  email: string;
}

Then import them cleanly in your Express routes and React frontend components:

// server/src/routes.ts
import type { User } from "@app/shared";

// client/src/features/users/UserList.tsx
import type { User } from "@app/shared";

No code generation steps, no build watchers for types—just instant editor autocompletion and compiler safety across the entire stack.


Getting Started in 30 Seconds

Scaffolding and running a new project takes just a few quick commands:

1. Scaffold the Project

Run the generator using your package manager of choice:

npm create duoo my-app
# or
npx create-duoo my-app

2. Install Dependencies & Boot the Dev Servers

Change into the directory, install your dependencies, and fire up both environments:

cd my-app
npm i
npm run dev

3. Open Your Browser

That’s all there is to it. The root script runs both the API and client concurrently:


Clean Project Structure

Duoo creates a lean, predictable repository structure that doesn’t overwhelm you:

my-app/
├── client/          # React single-page app bundled with Vite
├── server/          # Express API server running on Node.js
├── shared/          # Shared interfaces, DTOs, and utility types
├── package.json     # Monorepo root scripts & workspace configuration
└── tsconfig.base.json

Configuration & Environment

The client communicates directly with the Express backend using VITE_API_URL.

  • Local Development (client/.env):
    VITE_API_URL=http://localhost:3001
    
  • Production (client/.env.production):
    VITE_API_URL=https://api.yourdomain.com
    

Wrapping Up

Duoo removes the gap between having an idea and writing functional code. No manual setup, no over-engineered frameworks, and no duplicated types.

Next time inspiration hits, save yourself the setup headache:

npm create duoo my-app

Happy coding!