@nestjs-dash/nestjs
v2.2.0
Published
NestJS host module (AdminModule), controllers, guards, and React SSR admin shell for NestJS Dash
Readme
@nestjs-dash/nestjs
The NestJS host module for NestJS Dash: AdminModule, the controllers/guards that serve the admin panel, and the React SSR admin shell (built on @nestjs-dash/design-system). This is the package most apps install directly — it wires @nestjs-dash/core Resources together with an ORM adapter and serves a working panel.
An ORM adapter package (@nestjs-dash/typeorm / @nestjs-dash/mikroorm / @nestjs-dash/prisma / @nestjs-dash/in-memory) supplies the adapter. @nestjs-dash/storage is a required companion for serving a panel (upload endpoint). @nestjs-dash/media, @nestjs-dash/audit-log, and @nestjs-dash/bullmq are optional plugins; @nestjs-dash/translation adds translatable JSON columns via its own TranslatableModule; @nestjs/swagger enables Admin API OpenAPI UI.
Install
pnpm add @nestjs-dash/nestjs @nestjs-dash/storage@nestjs/common / @nestjs/core / @nestjs/platform-express ^12.0.0 and rxjs are required peer dependencies. @nestjs-dash/typeorm, @nestjs-dash/media, @nestjs-dash/audit-log, @nestjs/swagger, @nestjs/typeorm, and typeorm are optional peers, loaded via dynamic import() only when their corresponding feature is enabled.
@nestjs-dash/storage is technically a peer, but in practice required once you serve a panel, because the built-in /admin/upload endpoint always depends on it (@nestjs-dash/media stays genuinely optional, gated behind media.enabled).
Quick start
import { AdminModule } from '@nestjs-dash/nestjs';
import { TypeOrmAdapter } from '@nestjs-dash/typeorm';
AdminModule.forRootAsync({
// ...
useFactory: (dataSource) => ({
dataSource,
autoBindTypeOrm: true,
storage: {
defaultDisk: 'local',
disks: { local: { driver: 'local', root: './storage' } },
},
panel: {
id: 'admin',
path: '/admin',
brandName: 'My App',
plugins: [TypeOrmAdapter.forRoot()],
},
}),
});storage, media, audit, and swagger are top-level AdminModuleOptions (siblings of panel). Only true AdminPlugin objects (ORM adapters, BullMQ, custom plugins) go in panel.plugins.
Swagger / OpenAPI
pnpm add @nestjs/swagger// app.module — enable the flag
AdminModule.forRoot({
swagger: true, // or { path, title, version }
panel: {/* ... */},
});// main.ts — mount after NestFactory.create
import { AdminModule } from '@nestjs-dash/nestjs';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module.js';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await AdminModule.setupSwagger(app);
await app.listen(process.env.PORT ?? 3000);
}
await bootstrap();Default UI: /api/docs. NestJS Dash builds the OpenAPI document from the panel — no DocumentBuilder. See Swagger / OpenAPI.
Auth
The admin UI is unprotected by default. When no working auth resolver is configured — either auth is omitted, or a configured resolver is explicitly disabled via auth.enabled: false — AdminAuthGuard logs a one-time startup warning and the panel itself renders a persistent "this admin panel is not secure" banner, so the exposure is visible in the UI, not just the server log. Pass auth (with enabled left unset or true) to lock it down:
import { AdminModule, credentialsAuthResolver } from '@nestjs-dash/nestjs';
AdminModule.forRootAsync({
useFactory: () => ({
// ...
auth: credentialsAuthResolver({
secret: process.env.ADMIN_SESSION_SECRET!, // long random value
validate: async (email, password) => {
const admin = await findAdminByEmail(email);
if (!admin || !(await bcrypt.compare(password, admin.password))) return null;
return { id: admin.id, email: admin.email };
},
}),
}),
});credentialsAuthResolver renders a real login form at {panelPath}/login and stores the result in a signed, httpOnly session cookie — no session store needed. Unauthenticated browser requests are redirected there automatically.
Other built-in resolvers:
jwtAuthResolver({ verify, loginUrl? })— bring your own JWT library.passportAuthResolver({ guard, loginUrl? })— delegate to an existing@nestjs/passportAuthGuard(...).customAuthResolver(authenticate, options?)— anything else.
All four return an AdminAuthResolver; implement that interface yourself for full control. Every built-in resolver accepts an enabled?: boolean option (default true) so you can toggle auth from an env var without removing the resolver — auth: credentialsAuthResolver({ ..., enabled: process.env.ADMIN_AUTH_ENABLED !== 'false' }). Setting it to false (or omitting auth entirely) puts the panel back into unprotected mode, with the warning banner described above. AdminApiController (the generic /api/{resource} surface) is deliberately not gated by this — guard/replace it yourself if you expose it.
Decorators
@AdminResource() and @AdminPage() register a class with the admin panel; @AdminAction() marks a standard action method; @AdminWidget() registers a dashboard widget class. See AdminResourceRegistry/AdminPageRegistry for the underlying explorer/registry providers if you need to inspect what's registered at runtime.
License
MIT
