Documentation

Everything you need to build amazing TypeScript applications

🚀 Quick Start

Get up and running in minutes with a single command.

Terminal
bunx @noundryfx/ndts-cli init

For a complete step-by-step guide including CRM sample application, visit the Getting Started page.

Prerequisites

  • Bun v1.3+ - JavaScript runtime (bun.com)
  • Docker (optional) - For database, Redis, and other services

🏗️ Architecture

API Architecture Patterns

Choose the pattern that fits your needs:

DAPI (Direct API) - Default

Frontend → API Routes → Database
  • ✓ Direct database access via Drizzle ORM
  • ✓ All business logic in routes
  • ✓ Perfect for new applications
  • ✓ Fast development

Use when: Building a new app from scratch

BFF (Backend for Frontend)

Frontend → BFF → Services → Backend API
  • ✓ Wraps existing backend APIs
  • ✓ Forwards bearer tokens
  • ✓ Transforms data for frontend
  • ✓ Perfect for enterprise

Use when: Integrating with C#, Java, Python, etc. backends

Project Structure

your-app/
├── packages/
│   ├── server/                # Hono API server
│   │   ├── src/
│   │   │   ├── config/        # Environment, database, cache
│   │   │   ├── middleware/    # Auth, logging, errors
│   │   │   ├── routes/        # API endpoints
│   │   │   ├── schema/        # Database schema (Drizzle)
│   │   │   └── index.ts       # Server entry point
│   │   └── package.json
│   │
│   └── client/                # HonoX with Hono JSX
│       ├── app/
│       │   ├── routes/        # File-based routing (.tsx)
│       │   │   ├── index.tsx      # Home page
│       │   │   ├── login.tsx      # Login page
│       │   │   ├── dashboard.tsx  # Dashboard
│       │   │   └── records/       # CRUD routes
│       │   ├── components/    # Reusable components
│       │   ├── server.ts      # HonoX entry point
│       │   ├── global.tsx     # Global layout (jsxRenderer)
│       │   └── style.css      # Tailwind v4 + Basecoat UI
│       ├── public/static/js/  # Client-side utilities
│       ├── vite.config.ts     # HonoX Vite config
│       └── package.json
├── scripts/                   # Service management
├── docker-compose.dev.yml     # Dev services
├── docker-compose.yml         # Production
├── .env.example
├── package.json               # Monorepo scripts
└── README.md

💻 Client Development

HonoX with Hono JSX - Server-Side Rendering without React

The client uses HonoX for file-based routing and Hono JSX for server-side rendering - lightweight, fast, and type-safe.

Technology Stack

  • HonoX - Full-stack framework with file-based routing
  • Hono JSX - Server-side JSX rendering (NO React!)
  • Vite - Build tool with customRender for Tailwind
  • Tailwind CSS v4 - Modern utility-first CSS
  • Basecoat UI - shadcn/ui-inspired components
  • Inter Font - Professional typography

File-Based Routing

HonoX automatically generates routes from .tsx files in app/routes/:

Global Layout:

app/global.tsx
import { jsxRenderer } from 'hono/jsx-renderer'

export default jsxRenderer(({ children, title }) => {
  return (
    <html>
      <head>
        <title>{title}title>
        <link href="/app/style.css" rel="stylesheet" />
      head>
      <body>{children}body>
    html>
  )
})

Route Component:

app/routes/login.tsx
export default function Login() {
  return (
    <div class="container mx-auto p-8">
      <div class="card max-w-md mx-auto">
        <form id="login-form">
          <input class="input" />
          <button class="btn">Loginbutton>
        form>
      div>
    div>
  )
}

Route Examples:

  • app/routes/index.tsx/
  • app/routes/about.tsx/about
  • app/routes/records/index.tsx/records
  • app/routes/records/[id].tsx/records/:id

Creating Components

Build reusable components with Hono JSX:

app/components/Button.tsx
type ButtonProps = {
  children: any
  variant?: 'primary' | 'secondary'
}

export function Button({ children, variant = 'primary' }: ButtonProps) {
  const buttonClass = variant === 'primary'
    ? 'btn btn-primary'
    : 'btn btn-secondary'

  return <button class={buttonClass}>{children}button>
}

Tailwind CSS v4 + Basecoat UI

Use Tailwind utilities and Basecoat components:

Tailwind Classes

Utility-first CSS with all Tailwind v4 utilities available

Basecoat Components

.card, .btn, .input, .badge and more

Inter Font

Professional typography included by default

customRender

Vite plugin for Tailwind compilation

🎨 UI Components

Pre-built TypeScript Components

Add production-ready components to your project with a single command. No React required!

Adding Components

Use the ndts CLI to add components to your project:

Terminal
# Interactive component selection
ndts add

# Add specific components
ndts add input multiselect datatable

# Add all components
ndts add --all

# Filter by category
ndts add --all --category noundry

Available Components

Input

Flexible input field with icon support

ndts add input

MultiSelect

Multi-select dropdown with API support

ndts add multiselect

DataTable

Premium table with advanced pagination, sorting & search

ndts add datatable

DatePicker

Date picker with calendar interface

ndts add datepicker

Modal & SlideOver

Overlay and panel components

ndts add modal

More...

NavigationMenu, DateRangePicker, Pacer

ndts add --all

Using Components

Components are added to your project and can be imported:

Import Component:

TypeScript
import { Input } from './components/ui/Input'

const emailInput = Input.create({
  name: 'email',
  type: 'email',
  placeholder: 'Enter email',
  icon: 'envelope',
  iconPosition: 'left'
})

document.body.appendChild(emailInput)

DataTable Example:

TypeScript
const table = DataTable.create({
  columns: [
    { key: 'id', label: 'ID', sortable: true },
    { key: 'name', label: 'Name' }
  ],
  apiEndpoint: '/api/users',
  pagination: true,
  searchable: true
})

🔗 URL State Binding

NEW FEATURE: Shareable, Bookmarkable Component States!

All form and data components now support bidirectional URL state synchronization. Enable with bindToUrl: true to make your components shareable and bookmarkable.

What You Get:

  • Shareable URLs - Copy URL to share exact component state
  • Bookmarkable - Save specific configurations
  • Browser Back/Forward - Works automatically
  • Deep Linking - Direct links to specific states
  • No Page Reloads - Uses History API

Supported Components:

Input, DatePicker, DateRangePicker

Form inputs sync values to URL

SearchSelect, MultiSelect

Selections stored in URL

DataTable

Pagination, search, sort in URL

Modal, SlideOver

Open state + data passing

Enable URL Binding:

TypeScript
const searchInput = Input.create({
  name: 'query',
  bindToUrl: true  // ← Enable URL sync
})

// URL becomes: ?query=laptop

Modal with Data Passing:

TypeScript
const modal = new FullScreenModal({
  id: 'user',
  bindToUrl: true,
  onUrlData: (data) => { /* use data */ }
})

modal.open({ userId: 123 })
// URL: ?user=open&user-data={"userId":123}

Example URLs:

  • ?search=laptop - Input value
  • ?date=2025-01-15 - Date picker
  • ?tags=["react","typescript"] - Multi-select
  • ?users-page=2&users-search=john - DataTable state

📖 Full Component Documentation

View detailed documentation, API references, and interactive examples for all components. See the DataTable live demo with premium pagination!

🔧 Server Development

Technology Stack

  • Hono - Ultra-fast web framework (60x faster than Express)
  • Drizzle ORM - Type-safe database ORM
  • Bun - JavaScript runtime (3x faster than Node.js)
  • JWT - Authentication tokens
  • bcrypt - Password hashing
  • Zod - Schema validation

Creating API Routes

packages/server/src/routes/users.ts
import { Hono } from 'hono';
import { auth } from '../middleware/auth';
import { db } from '../config/database';
import { users } from '../schema/schema';
import { eq } from 'drizzle-orm';
import { z } from 'zod';

const app = new Hono();

// Validation schema
const registerSchema = z.object({
  email: z.string().email(),
  password: z.string().min(8),
  name: z.string().min(1)
});

// Register endpoint
app.post('/register', async (c) => {
  const body = await c.req.json();
  const data = registerSchema.parse(body);

  const [user] = await db.insert(users)
    .values(data)
    .returning();

  return c.json(user, 201);
});

export default app;

Database Migrations

bun run db:generate  # Generate migration from schema
bun run db:migrate   # Run migrations
bun run db:studio    # Open Drizzle Studio (GUI)

🔌 Service Integrations

⚡ Redis Caching

In-memory caching with automatic fallback to memory cache.

Port: 6379

Connection: redis://localhost:6379

Usage Example
import { cache } from '../config/cache';

// Set cache
await cache.set('user:123', userData, 3600); // TTL: 1 hour

// Get cache
const user = await cache.get('user:123');

// Delete cache
await cache.del('user:123');

📬 BullMQ Queues

Background job processing for async tasks.

Requires: Redis

Use for: Email sending, report generation, data processing

Queue Example
import { Queue, Worker } from 'bullmq';

// Create queue
const emailQueue = new Queue('emails');

// Add job
await emailQueue.add('send', {
  to: 'user@example.com',
  subject: 'Welcome!'
});

// Process jobs
const worker = new Worker('emails', async (job) => {
  await sendEmail(job.data);
});

🗂️ S3 Blob Storage

S3-compatible storage for files and assets (works with AWS S3, MinIO, Cloudflare R2).

MinIO (dev): Port 9000 (API), Port 9001 (Console)

Credentials: minioadmin / minioadmin

File Upload Example
import { s3Client } from '../config/storage';
import { PutObjectCommand } from '@aws-sdk/client-s3';

// Upload file
await s3Client.send(new PutObjectCommand({
  Bucket: 'uploads',
  Key: 'avatar.jpg',
  Body: fileBuffer,
  ContentType: 'image/jpeg'
}));

📝 Pino Logging

Structured JSON logging for production-ready applications.

Logging Example
import { logger } from '../config/logger';

logger.info('User registered', { userId: 123 });
logger.warn('Rate limit approaching');
logger.error('Database connection failed', { error });
logger.debug('Cache hit', { key: 'user:123' });

📊 OpenTelemetry

Distributed tracing and observability with Jaeger UI.

Jaeger UI: http://localhost:16686

OTLP Endpoint: Port 4318

Automatic instrumentation for HTTP requests, database queries, and cache operations.

📧 SMTP Email

Email sending with Resend, SendGrid, or custom SMTP.

Resend

Modern, developer-friendly

SendGrid

Enterprise email service

MailHog (dev)

Port 8025 (UI), Port 1025 (SMTP)

🔐 Authentication

Multiple authentication options to fit your needs.

Custom JWT (Default)

  • • Built-in JWT + bcrypt
  • • Full control over auth flow
  • • Simple and straightforward

Better Auth

  • • Modern auth library
  • • Many OAuth providers
  • • Type-safe

Auth.js

  • • NextAuth.js compatible
  • • Popular OAuth providers
  • • Session management

Auth0

  • • Enterprise authentication
  • • Social login ready
  • • MFA support

🐳 Docker Services

Automatic Service Startup

When you run bun run dev, Docker services automatically start:

  • ✓ Checks if Docker is running
  • ✓ Starts only required services (PostgreSQL, MySQL, Redis, MinIO, Jaeger, MailHog)
  • ✓ Waits for services to be ready
  • ✓ Displays connection URLs and credentials
  • ✓ Starts your application
  • ✓ Gracefully handles Docker not being available

Service Management Commands

bun run services:start    # Start all services
bun run services:stop     # Stop all services
bun run services:restart  # Restart services
bun run services:ps       # Show service status
bun run services:logs     # View service logs

Available Services

Service When Started Ports Credentials
PostgreSQL database: postgresql 5432 postgres / postgres
MySQL database: mysql 3306 root / mysql
Redis cache or queues enabled 6379 No password
MinIO blobStorage: true 9000, 9001 minioadmin / minioadmin
Jaeger telemetry: true 16686, 4318 No auth
MailHog emailProvider: smtp 1025, 8025 No auth

🚀 Deployment

Deploy your application to any of these platforms:

Fly.io

fly launch
fly secrets set JWT_SECRET="..."
fly deploy

Railway

railway init
railway add postgresql
railway up

Vercel

vercel
vercel env add JWT_SECRET
vercel --prod

Docker Self-Hosted

docker-compose up -d

Production Checklist

  • ☐ Change JWT_SECRET to a strong random value
  • ☐ Use PostgreSQL or MySQL instead of SQLite
  • ☐ Set NODE_ENV=production
  • ☐ Configure CORS for your domain
  • ☐ Set up SSL/TLS
  • ☐ Configure rate limiting
  • ☐ Set up monitoring and logging
  • ☐ Configure database backups

⌨️ Commands Reference

CLI Commands

ndts init [options]

Initialize a new project

-y, --yes - Skip prompts, use defaults

--no-git - Skip git initialization

--no-install - Skip dependency installation

ndts --version

Display the current version of ndts CLI

Development Commands

bun run dev           # Start both server + client
bun run dev:server    # Start only API server
bun run dev:client    # Start only frontend

bun run build         # Build for production
bun run start         # Start production build

Database Commands

bun run db:generate   # Generate migration from schema
bun run db:migrate    # Run migrations
bun run db:studio     # Open Drizzle Studio (GUI)

Service Commands

bun run services:start    # Start Docker services
bun run services:stop     # Stop Docker services
bun run services:restart  # Restart services
bun run services:ps       # Show service status
bun run services:logs     # View service logs