Folder structure
A njin project is a regular Bun project. The framework itself is an npm package, @njinlabs/njin, installed in node_modules, so the project contains only your own code and content.
my-web/
├── config.ts Site settings and the list of everything you register
├── src/
│ ├── models/ Data models: posts, pages, products...
│ ├── vars/ Singleton settings: site name, SEO defaults...
│ ├── helpers/ Functions you can call from templates
│ ├── events/ Event definitions and their listeners
│ ├── routes/ Custom server routes
│ ├── plugins/ Plugins that live inside the project
│ ├── views/
│ │ ├── pages/ Page templates (file-based routing)
│ │ ├── layouts/ Layouts shared by pages
│ │ ├── components/ Reusable template components
│ │ └── errors/ Optional custom error pages (404.edge, 500.edge...)
│ └── client/
│ ├── main.ts Browser JavaScript entry point
│ └── app.css Tailwind CSS
├── static/ Images and files served as they are
├── _admin/ The admin panel
├── CLAUDE.md, AGENTS.md Guides for AI coding agents
├── package.json
├── tsconfig.json
└── vite.config.tsFolders such as src/vars/ and src/events/ are where the matching files go. Create them when you need them.
config.ts
The single place where you register what your site is made of: models, vars, helpers, events, routes and plugins. It also holds the port, the database, the file storage adapter, the allowed image hosts, logging, the languages of the site, and which pages are cached as static HTML.
njin reads config.ts once at startup, so restart the dev server after you change it. See Configuration.
src/models
One file per model, each exporting the result of makeModel(). A model must be registered in config.ts before it exists in the API and the admin panel. See Defining a model.
src/vars
One file per settings group, each exporting the result of makeVars(). Where a model holds many records, a vars group holds exactly one object, which is a good fit for things like the site name. See Defining vars.
src/helpers, src/events, src/routes, src/plugins
- helpers are plain functions exposed as globals in every template. See Helpers.
- events are typed events and the listeners for them. See Events.
- routes are custom server routes, for things like webhooks. See Custom routes.
- plugins are bundles of models, vars, hooks, events and routes.
bunx njin plugin:create <name>creates one insrc/plugins/<name>. See Plugins.
src/views
Templates are written in EdgeJS.
- pages/ maps files to URLs:
pages/about.edgeis/about,pages/blog/[slug].edgeis/blog/:slug, andindex.edgeis the root of its folder. See File-based routing. - layouts/ holds the HTML shell shared by pages.
- components/ holds reusable pieces, used with
@componentand@include. - errors/ can hold a template per status code, such as
404.edge.
src/client
main.ts is the browser entry point (Alpine.js is started here) and app.css is the Tailwind CSS entry. Both are built by Vite and added to a page with vite.asset(). See Tailwind and Alpine.js.
static
Files that are served as they are, such as logo.svg and favicon.svg. Reference them in templates with vite.static('logo.svg'). See Static assets.
_admin
The admin panel, served at /_admin. It is downloaded when the project is created and refreshed with bunx njin update (or bunx njin update --admin for the panel only). You do not edit it.
Generated folders
These appear while you work and are listed in the starter .gitignore:
| Folder | What it is |
|---|---|
data/ |
The embedded database, with the default settings |
uploads/ |
Uploaded files, with the default filesystem adapter |
public/ |
Assets built by Vite |
out/ |
The output of njin build |
.cache/ |
Cached static pages |
Keep data/ and uploads/ out of version control, but back them up. They hold your content.