Create production-ready Hono & EJSX applications with zero configuration. Comes with built-in authentication, dashboard, and database setup.
npx create-ejsx-app my-app
cd my-app
npm run dev
bunx create-ejsx-app my-app
cd my-app
bun run dev
Visit http://localhost:3000
to see your app.
- ⚡️ Hono - Ultra-fast web framework
- 🎨 EJSX - EJS with component & layout support
- 🔒 Built-in authentication with JWT
- 💾 SQLite database setup
- 📊 Basic dashboard template
- 🎯 Production-ready middleware
- 🔥 Hot reload in development
my-app/
├── src/
│ ├── routes/
│ │ ├── api.js # API routes (auth, user)
│ │ └── pages.js # Page routes with EJSX templates
│ ├── middleware/
│ │ ├── auth.js # JWT authentication
│ │ └── error.js # Error handling
│ ├── db/
│ │ └── setup.js # Database initialization
│ └── index.js # App entry point
├── data/ # SQLite database file
├── .env # Environment variables
├── .gitignore
└── package.json
- User registration and login
- JWT-based session management
- Secure password hashing with bcrypt
- Protected routes and API endpoints
- SQLite setup with migrations
- User and session tables
- Easy-to-extend schema
- Responsive layout system
- Navigation component
- Login/Register forms
- Dashboard template
- TailwindCSS for styling
- CSRF protection
- Secure headers
- SQL injection prevention
- Password hashing
- JWT token management
- Hot reload with nodemon
- Environment variable management
- Error handling middleware
- Logging system
# Start development server with hot reload
npm run dev
# Start production server
npm start
# Run tests
npm test
# Run linter
npm run lint
Create a .env
file in your project root:
NODE_ENV=development
PORT=3000
JWT_SECRET=your-secret-key
DATABASE_URL=./data/app.db
# Register new user
POST /api/auth/register
{
"email": "user@example.com",
"password": "password123",
"name": "John Doe"
}
# Login
POST /api/auth/login
{
"email": "user@example.com",
"password": "password123"
}
# Get user profile
GET /api/user
Authorization: Bearer <token>
-
/
- Home page -
/login
- Login page -
/dashboard
- Protected dashboard
// src/routes/pages.js
ejsx.components.set('Button', ({ text, onClick, type = 'primary' }) => `
<button
class="bg-${type}-500 px-4 py-2 rounded"
onclick="${onClick}"
>
${text}
</button>
`);
// src/routes/api.js
api.get('/custom-route', async (c) => {
const userId = c.get('jwtPayload').sub;
// Your logic here
return c.json({ data: 'your data' });
});
// src/routes/pages.js
pages.get('/custom-page', async (c) => {
const html = await ejsx.render(`
<% slots.title = 'Custom Page' %>
<% slots.content = \`
<div>
<h1>Custom Page</h1>
<!-- Your content here -->
</div>
\` %>
<%- renderLayout('main', slots) %>
`, {});
return c.html(html);
});
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.