Getting Started

Build your first full-stack TypeScript application in minutes

Quick Install

No global installation needed - use bunx to run directly

Terminal
bunx @noundryfx/ndts-cli init

Prerequisites

  • โ€ข Bun v1.3+ - JavaScript runtime (bun.com)
  • โ€ข Docker (optional, but recommended for great DX) - For database, Redis, and other services

๐Ÿ’ก Note: Node.js is NOT required. Bun is a drop-in replacement that handles all runtime needs including CLI execution.

Your First Project

Follow these steps to create and run your first application

1

Create Your Project

Run the CLI and follow the interactive wizard

bunx @noundryfx/ndts-cli init

You'll be asked to configure:

  • โ€ข Project name: my-app
  • โ€ข Database: SQLite / PostgreSQL / MySQL
  • โ€ข Authentication: Custom JWT / Better Auth / Auth.js / Auth0
  • โ€ข Email provider: Resend / SendGrid / SMTP / None
  • โ€ข Optional features: Caching, Blob Storage, Queues, Logging, Telemetry
2

Navigate to Your Project

Change into your newly created project directory

cd my-app
3

Set Up Environment

Copy the environment template and configure your secrets

cp .env.example packages/server/.env

Edit packages/server/.env:

# Server
PORT=3001
NODE_ENV=development

# Database (SQLite)
DB_URL=file:local.db

# Auth
JWT_SECRET=your-super-secret-key-change-in-production
JWT_EXPIRES_IN=7d

# CORS
CORS_ORIGIN=http://localhost:3000
4

Start Development Servers

Launch both the API server and frontend with automatic Docker service startup

bun run dev

๐Ÿณ Automatic Docker Service Startup

When you run bun run dev, Docker containers automatically start for your selected services:

  • โœ“ 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

๐Ÿ”Œ Server Running:

http://localhost:3001

API endpoints available

๐Ÿ’ป Frontend Running:

http://localhost:3000

Open in browser

5

Test Your Application

Open your browser and interact with your new app

โœ“ What you'll see:

  • โ€ข Homepage with navigation
  • โ€ข User registration page
  • โ€ข Login page with authentication
  • โ€ข Protected dashboard (requires login)

๐Ÿงช Try it out:

  1. Click "Register" and create an account
  2. Login with your new credentials
  3. Explore the dashboard
Sample Application

Build a CRM System

Follow this guide to build a complete Customer Relationship Management system with contacts, products, and invoices using HonoX

What You'll Build

๐Ÿ‘ฅ

Contacts

Manage customer records with email, phone, company, and notes

๐Ÿ“ฆ

Products

Product catalog with pricing, SKU, and stock tracking

๐Ÿ’ฐ

Invoices

Full invoicing system with line items and status tracking

1

Generate CRM Project

Create a new project with database support

bunx @noundryfx/ndts-cli init
# Project name: crm-system
# Database: SQLite (or PostgreSQL for production)
# Auth: Custom JWT
# Email: None (for simplicity)
# Caching: Yes
# Other features: As needed
2

Define Database Schema

Add CRM tables to your schema

Edit packages/server/src/schema/schema.ts:

packages/server/src/schema/schema.ts
import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core';

// Contacts table
export const contacts = sqliteTable('contacts', {
  id: integer('id').primaryKey({ autoIncrement: true }),
  userId: integer('user_id')
    .notNull()
    .references(() => users.id, { onDelete: 'cascade' }),
  name: text('name').notNull(),
  email: text('email'),
  phone: text('phone'),
  company: text('company'),
  address: text('address'),
  notes: text('notes'),
  createdAt: integer('created_at', { mode: 'timestamp' })
    .$defaultFn(() => new Date())
});

// Products table
export const products = sqliteTable('products', {
  id: integer('id').primaryKey({ autoIncrement: true }),
  userId: integer('user_id').notNull().references(() => users.id),
  name: text('name').notNull(),
  description: text('description'),
  price: integer('price').notNull(), // in cents
  sku: text('sku'),
  stock: integer('stock').default(0)
});

// Invoices table
export const invoices = sqliteTable('invoices', {
  id: integer('id').primaryKey({ autoIncrement: true }),
  userId: integer('user_id').notNull().references(() => users.id),
  contactId: integer('contact_id').references(() => contacts.id),
  invoiceNumber: text('invoice_number').notNull(),
  status: text('status').notNull().default('draft'), // draft, sent, paid, overdue
  subtotal: integer('subtotal').notNull(),
  tax: integer('tax').default(0),
  total: integer('total').notNull(),
  issueDate: integer('issue_date', { mode: 'timestamp' }),
  dueDate: integer('due_date', { mode: 'timestamp' })
});
3

Generate and Run Migrations

Create database tables from your schema

cd crm-system
bun run db:generate  # Generate migration files
bun run db:migrate   # Apply migrations to database
4

Create API Routes

Add CRUD endpoints for contacts, products, and invoices

Create packages/server/src/routes/contacts.ts:

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

const app = new Hono();

// Protect all routes
app.use('*', auth);

// Get all contacts
app.get('/', async (c) => {
  const userId = c.get('userId');
  const results = await db.select()
    .from(contacts)
    .where(eq(contacts.userId, userId));
  return c.json(results);
});

// Create contact
app.post('/', async (c) => {
  const userId = c.get('userId');
  const data = await c.req.json();
  const [contact] = await db.insert(contacts)
    .values({ ...data, userId })
    .returning();
  return c.json(contact, 201);
});

export default app;

๐Ÿ’ก Tip: Create similar routes for products.ts and invoices.ts

5

Create Frontend Routes

Build JSX routes with HonoX file-based routing

Create packages/client/app/routes/contacts/index.tsx:

packages/client/app/routes/contacts/index.tsx
export default function Contacts() {
  return (
    <div class="container mx-auto p-4">
      <h1 class="text-3xl font-bold mb-4">Contactsh1>
      <div id="contacts-list" class="card">div>
    div>
  )
}

๐Ÿ’ก Tip: HonoX automatically creates the /contacts route from this file structure!

6

Start Building!

Run your CRM system and start customizing

bun run dev

โœ“ Features Included:

  • โ€ข User authentication
  • โ€ข Contact management
  • โ€ข Product catalog
  • โ€ข Invoice creation
  • โ€ข Type-safe API & database

๐ŸŽฏ Next Steps:

  • โ€ข Customize page layouts
  • โ€ข Add validation logic
  • โ€ข Implement search/filters
  • โ€ข Add export features
  • โ€ข Deploy to production
File-Based Routing

HonoX Routes with JSX

Create .tsx files and HonoX automatically generates routes

Automatic Route Generation

app/routes/index.tsx

โ†’ /

app/routes/about.tsx

โ†’ /about

app/routes/records/index.tsx

โ†’ /records

app/routes/records/[id].tsx

โ†’ /records/:id

Example Route Component

app/routes/products.tsx
export default function Products() {
  return (
    <div class="container mx-auto p-8">
      <h1 class="text-3xl font-bold">Productsh1>
      <div class="grid grid-cols-3 gap-4">
        {/* Product cards */}
      div>
    div>
  )
}

Ready to Build?