Build your first Nounjs application in minutes
Understanding the .noun file compile process
Nounjs uses single-file components (.noun files) that combine your template and logic.
The CLI compiles these into standard JavaScript classes that the browser can run.
| Step | Source | Output |
|---|---|---|
| Write | src/pages/*.noun |
- |
| Compile | src/pages/*.noun |
src/compiled/*.js |
| Import | - | from './src/compiled/*.js' |
Always import from ./src/compiled/*.js, not from ./src/pages/*.noun.
The browser runs the compiled JavaScript, not the source .noun files.
Browsers can't natively understand .noun files. The compile step transforms the single-file component format into a standard ES6 class that extends Component. This keeps your source clean while producing optimized output.
Everything you need before getting started
Nounjs is optimized for Bun - a fast JavaScript runtime that serves as a drop-in replacement for Node.js.
curl -fsSL https://bun.sh/install | bashCreate a new project with a single command
# With Bun (recommended)
bunx @noundryfx/nounjs create my-app
# Or with npm
npx @noundryfx/nounjs create my-app
Custom Tailwind-based component classes with noun- prefix.
bunx @noundryfx/nounjs create my-app
# or: bunx @noundryfx/nounjs create my-app --tailwind
Basecoat UI - shadcn/ui-inspired component library.
bunx @noundryfx/nounjs create my-app --basecoat
Already have an API? Generate a complete admin UI in seconds.
The scaffold command parses your OpenAPI/Swagger spec and generates a complete dashboard with list, detail, and form pages for every resource. Includes login page and auth guards auto-detected from securitySchemes. Perfect for rapid prototyping or building internal tools.
# Generate from any OpenAPI endpoint
noun scaffold https://api.example.com/openapi.json
# Or from a local swagger file
noun scaffold ./swagger.json --name "Admin Dashboard"
# Try it with the Pet Store demo API
noun scaffold https://petstore.swagger.io/v2/swagger.json --name "Pet Store"
Full client with all endpoints
Login, OAuth, JWT, API keys
Search, sort, pagination
Single item displays
Create/edit with validation
/openapi/v1.json
/openapi.json
/api-docs
/v3/api-docs
/swagger_doc.json
From zero to running application
Run the CLI to scaffold a new Nounjs project.
bunx @noundryfx/nounjs create my-app
cd my-app
Install the project dependencies.
bun install
# or: npm install
Build CSS/JS and start the development server with hot reload.
bun run dev
_ _ _ ____ | \ | | ___ _ _ _ __ | / ___| | \| |/ _ \| | | | '_ \ _ | \___ \ | |\ | (_) | |_| | | | | |_| |___) | |_| \_|\___/ \__,_|_| |_|\___/|____/ v0.9.31 info Starting development server... done Compiled 10 components in 28ms done dist/styles.css (57.7kb) in 1067ms done Initial build complete in 1217ms
Open your browser to http://localhost:3000
Your Nounjs app is now running with:
Understanding your new Nounjs project
my-app/
├── index.html # Entry HTML file
├── app.js # Main application code
├── noun.config.json # Nounjs configuration
├── tailwind.config.js # Tailwind CSS configuration
├── package.json # Dependencies and scripts
├── src/
│ ├── pages/ # Place your .noun files here
│ ├── compiled/ # Generated JS from .noun files
│ └── styles/
│ └── globals.css # Your Tailwind + custom CSS
└── dist/
├── noun.esm.js # Nounjs runtime (included)
├── router.esm.js # Router module
├── styles.css # Built CSS output
└── app.js # Bundled JavaScript output
app.js - Your main application entry pointsrc/pages/ - Single-file .noun componentssrc/styles/globals.css - Your custom CSS and Tailwind importsnoun.config.json - Project configurationComplete reference for development and production
| Command | Description |
|---|---|
bun run dev |
Build CSS + JS, start server with watch |
bun run compile |
Compile .noun files to .js |
bun run build |
Full production build (CSS + JS) |
bun run build:css |
Build Tailwind CSS only |
bun run bundle |
Bundle app.js for production |
bun run watch:css |
Watch and rebuild CSS on changes |
bun run serve |
Start static file server |
noun scaffold <url> |
Generate complete UI from OpenAPI spec |
noun publish |
Deploy to nounjs.app hosting |
Two ways to create components in Nounjs
Edit app.js directly:
import { Component, mount } from './build/noun.esm.js'
class HelloWorld extends Component {
template = `
<div class="p-8 max-w-md mx-auto">
<h1 class="text-2xl font-bold mb-4">
Hello { name }!
</h1>
<input
type="text"
class="input mb-4"
placeholder="Enter your name"
:model="name"
/>
<button @click="greet" class="btn">
Greet
</button>
</div>
`
name = 'World'
greet() {
alert(\`Hello, \${this.name}!\`)
}
}
mount('#app', HelloWorld)
Create src/pages/hello.noun:
<template>
<div class="p-8 max-w-md mx-auto">
<h1 class="text-2xl font-bold mb-4">
Hello { name }!
</h1>
<input
type="text"
class="input mb-4"
placeholder="Enter your name"
:model="name"
/>
<button @click="greet" class="btn">
Greet
</button>
</div>
</template>
<script>
export default {
name: 'World',
greet() {
alert(\`Hello, \${this.name}!\`)
}
}
</script>
After creating a .noun file, compile and import it:
# Compile .noun files
bun run compile
// In app.js
import { Hello } from './src/compiled/hello.js'
import { mount } from './build/noun.esm.js'
mount('#app', Hello)
Register once, use everywhere
Nounjs uses a global component registry. Register child components once in app.js, then use them anywhere in your templates without imports.
import { mount, registerComponent } from './build/noun.esm.js'
// Import and register child components
import { UserCard } from './src/compiled/components/UserCard.js'
import { StatusBadge } from './src/compiled/components/StatusBadge.js'
registerComponent('user-card', UserCard)
registerComponent('status-badge', StatusBadge)
// Mount your app - child components auto-discovered
mount('#app', App)
<template>
<div>
<user-card :user="selectedUser" @delete="handleDelete"></user-card>
<status-badge :status="item.status"></status-badge>
</div>
</template>
UserCard → <user-card>
:prop="expr" for dynamic values
@event="handler" to listen
Set up client-side navigation
import { createRouter } from './build/router.esm.js'
import { mount } from './build/noun.esm.js'
import { Home } from './src/compiled/home.js'
import { About } from './src/compiled/about.js'
import { User } from './src/compiled/user.js'
const router = createRouter({ mode: 'hash' })
router
.route('/', () => mount('#app', Home))
.route('/about', () => mount('#app', About))
.route('/users/:id', (to) => mount('#app', User, { id: to.params.id }))
.start()
URLs like #/users/123
Clean URLs like /users/123
mode: 'history'Use the CLI to scaffold components quickly
# Generate a basic component
noun g component Button
# Generate different page types
noun g page Dashboard # Basic page
noun g page Users list # List/grid page with search
noun g page Products grid # NounTable data grid
noun g page UserEdit form # Create/edit form page
noun g page UserDetail detail # Detail view page
noun g page Login login # Login page
Prepare your app for deployment
# Full production build
bun run build
# or: noun prod
Deploy your app with a single command:
noun publish my-app
Your app will be live at https://my-app.nounjs.app
Built-in visual debugging panel for component inspection
import { enableDevTools } from './build/noun.esm.js'
// Enable DevTools (development only)
if (location.hostname === 'localhost') {
enableDevTools()
}
AI-powered development with real-time diagnostics and instant deployment
# Install from VSIX
code --install-extension nounjs-0.9.12.vsix
# Or search "Nounjs" in VS Code Extensions
Catches errors as you type, detects React patterns and suggests Nounjs equivalents
Autocomplete for 36+ built-in components with prop suggestions
AI-optimized templates including full CRUD pages, dashboards, auth flows
Publish to nounjs.app without leaving the editor
First-class TypeScript in .noun files
<template>
<div :for="user of users">
{ user.name } - { user.role }
</div>
</template>
<script lang="ts">
interface User {
id: number
name: string
role: 'admin' | 'user'
}
export default {
users: [] as User[],
async mounted(): Promise<void> {
this.users = await api.getUsers()
}
}
</script>
Add lang="ts" to your script tag. Nounjs uses Bun's native transpiler for fast compilation.
In environments without Bun, it falls back to regex-based type stripping.
A complete reference application demonstrating all core features
# Clone the starter app
git clone https://github.com/noundry/nounjs-starter.git
cd nounjs-starter
# Install and run
bun install
bun run dev
# Open http://localhost:3000
The starter demonstrates passing services to all pages via a shared props object. This keeps components loosely coupled and testable.
const sharedProps = {
auth: authService, authStore, themeStore, api: apiService,
router, utils, validators, toast: toastService,
transitions: { transitionEnter, transitionLeave },
createVirtualList
}
mount('#app', Dashboard, sharedProps) // All pages get these