Starter kits are ready-made Suprnova applications you fork and ship. Each one wires the controllers, routes, migrations, frontend pages, and tests for a complete product surface - so you start from a running app, not an empty scaffold.
Three kits ship, modelled on Laravel's lineage. Pick the one closest to what you're building and customise from there.
Nebula - authentication (Breeze-tier)
Repo: github.com/eas4ai/Nebula
The minimal full-auth kit - Suprnova's Breeze equivalent. Everything you need for accounts and nothing you don't:
- Registration with email verification
- Login with remember-me
- Password reset with anti-enumeration responses
- Profile management - update email and password, delete account
- A branded Inertia 3 + Svelte 5 frontend (dark by default), with the logged-in user menu wired
Nebula ships two test suites: facade-level auth logic, and a wire-level HTTP suite that drives real routes, sessions, CSRF round-trips, and the guest / auth / verified gates over a loopback socket.
Reach for Nebula when you want a clean account-management foundation to build your own product on top of.
Pulsar - product site & community
Repo: github.com/eas4ai/Pulsar
A complete developer-tool / SaaS company site on Vue 3.5 + Vuetify. Everything in Nebula's auth story, plus the surfaces a real product site needs:
- Marketing landing page and a user dashboard
- A Markdown documentation pipeline (
docs:build) with search and a generated table of contents - A blog / articles system with an RSS feed
- Public member profiles
- Taxonomy - topics, tags, and categories
- Role-based access control: roles, permissions, and gates
- Admin and moderation surfaces for content and members
Pulsar is the source kit for downstream products such as suprnova.app. Reach
for it when you're shipping a product site with docs, a blog, and a member
community - not just authentication.
Directory starter - listings, moderation, and paid publication
Repo: github.com/eas4ai/suprnova-directory-starter
A free, MIT-licensed directory on Vue 3.5: owners submit listings, moderators review them, visitors search them, and publication is free or paid through Stripe and Paddle. Everything in Nebula's auth story, plus:
- Directory discovery - searchable listings, category filters, pagination, and public detail pages
- Owner submissions and moderation - drafts, revision history, approval, rejection, resubmission, and suspension
- Free and paid publication - Stripe and Paddle, configurable plans, separate test and live settings, authenticated webhooks, and payment recovery
- Editorial publishing - article drafts, previews, categories, tags, and RSS
- Administration - permission-based roles, account suspension, audit history, and an admin overview
- SEO - site defaults and per-content overrides, server-rendered metadata, sitemaps, redirects, a 404 report, and Markdown versions of public pages
- Media and notifications, colour presets with a remembered light or dark preference, demo content, and documented backup and restore workflows
Reach for the directory starter when the product is a directory or a marketplace of listings, with or without paid placement.
Which kit?
| You want… | Start with |
|---|---|
| Accounts and a place to build | Nebula |
| A full product site - landing, docs, blog, community, RBAC | Pulsar |
| A directory or marketplace of listings, free or paid | Directory starter |
| Server-rendered pages with no Node toolchain | suprnova new my-app --frontend live |
| An API-only backend (token auth, no frontend) | suprnova new my-api --api |
All three kits track the framework as a git dependency and run on the same stack you already know - see each repo's README for setup. More kits are planned; watch the releases or open an issue if there's one you want.
What the default scaffold gives you
If neither kit fits, suprnova new my-app --frontend svelte (or react, or
vue) already ships a working authentication flow - login, register, logout,
email verification, password reset, session authentication with the
authenticate middleware, CSRF protection, and a protected /dashboard
route - on any of the three frontends (Svelte 5,
React 19, Vue 3.5) with Tailwind v4 and Inertia v3, or on the
Live starter kit, which needs no Node toolchain. See
Installation for the scaffold output and
Quickstart for the first-five-minutes walkthrough.
Behind the authentication group, the scaffold ships the server side of the kit pages, all of it over the signed-in user's own data:
- A
notestable and aNotemodel (src/models/note.rs) that belongs to a user, withNote::owned_by(user_id)as the one way the handlers read notes. GET /dashboard, which sendsstatsdeferred (the user's note count and the notes written today) andrecent_notesoptional (the user's five newest notes).GET /notes, which lists the user's notes 10 at a time withcursor_paginatethroughInertia::paginate, filtered by thesearchquery parameter in title or body without regard to case, and sendssearchback to the page.GET /notes/{id}, which shows one of the user's notes and answers404for a note of another user or an id that doesn't exist.POST /notes, which validatestitle(1 to 255 characters) andbody(at most 10000 characters), writes the note, flashes a toast, and returns to the page the form was posted from, preserving its search query, with/notesas the fallback.POST /profile/name, a JSON handler for the dashboard's name form that answers200with{"user": {...}}or422with the framework's validation body.
Every page receives the signed-in user, or null for a guest, under the
shared auth prop: bootstrap.rs shares it with App::inertia_share_lazy,
which reads the request's session for each response that sends it, and
SharedData in src/props/shared.rs, marked #[inertia_props(shared)],
adds auth to the generated SharedProps. A layout reads
usePage().props.auth.user.
Sign-in, registration, a reset-link request, a password reset, email
verification, a verification resend, sign-out, and a saved note each flash a
Toast (src/props/flash.rs) under the key toast. The Flash struct
beside it holds that toast and is marked #[inertia_props(flash)], so
suprnova generate-types names it as Inertia's flashDataType and
page.flash.toast is typed in every page.
The routes carry the names Laravel's kits give them: dashboard,
notes.index, notes.show, notes.store, profile.name, login,
register, password.request, password.email, password.reset,
password.update, verification.notice, verification.send,
verification.verify, and logout.
The dashboard handler shows how each prop travels:
pub async
The Svelte kit's pages show Inertia 3.8's client components at work:
layouts/AppLayout.svelteandlayouts/GuestLayout.svelteframe every page throughcreateInertiaApp'slayoutoption and stay mounted across visits. They carry theLinknavigation, the signed-in user's name and a sign-outLink(or sign-in and register links for a visitor), and the toast a handler flashes, whichcomponents/FlashToast.sveltereads frompage.flash.Dashboardloads the note counts withDeferredand polls them withusePoll, loads the recent notes withWhenVisibleonce they scroll into view, and sets the layout's heading withsetLayoutProps. Its display-name form posts JSON throughuseHttpand shows the new name before the server answers.Notes/Indexcreates a note with theFormcomponent, keeps its search box withuseRemember, loads more notes withInfiniteScroll, and opens a note with a prefetched, instantLinktoNotes/Show.- The pages under
auth/submit through theFormcomponent, and every page titles its tab with the kit'scomponents/Head.svelte.
For the code, see Page Components.
The React starter (--frontend react) runs on Inertia 3.8 through the
@inertiajs/vite plugin and shows the client side of each feature on a
page you can copy. Dashboard renders stats with Deferred, polls it
with usePoll, loads recent_notes with WhenVisible, and changes your
display name through useHttp with an optimistic update. Notes/Index
creates a note with Form, remembers its search with useRemember,
scrolls your notes with InfiniteScroll, and opens one with an instant,
prefetched Link; Notes/Show renders it. Login, Register,
ForgotPassword, ResetPassword, and VerifyEmail submit through Form.
Every page sets its title with Head, and the pages render inside a
guest layout (the auth/ pages) or an application layout (the rest). Both
show the flash toast and, from the shared auth prop, the signed-in
user's name and a sign-out link or the sign-in and register links. See Page Components for the
code.
The Vue kit (--frontend vue) runs on Inertia 3.8 and its Vite plugin, and
each page shows part of the client at work:
Dashboard.vueloads the note counts as a deferred prop withDeferred, polls them withusePoll, loads the recent notes withWhenVisible, and saves the display name throughuseHttpwith an optimistic update.Notes/Index.vuecreates a note withForm, remembers its search withuseRemember, scrolls the signed-in user's notes withInfiniteScroll, and opens a note as an instant visit from a prefetchingLink.Notes/Show.vueshows one of the signed-in user's notes.- The five pages under
auth/submit throughForm. layouts/AppLayout.vueandlayouts/GuestLayout.vue, applied through thelayoutoption, carry the navigation, the flash toast fromcomponents/FlashToast.vue, and the account links fromcomponents/AccountLinks.vue: the signed-in user's name and a sign-out button, or the sign-in and register links for a guest. Every page titles its tab withHead.
For API-only services, suprnova new my-api --api initializes Magnetar,
installs bearer-session middleware, and scaffolds password registration and
login against the canonical app_users table without a frontend.
Why Suprnova diverges
Laravel's starter kits ship a dashboard with placeholder content and no list page. Suprnova's scaffold lists the signed-in user's own notes, so deferred and optional props, cursor scrolling, a JSON form, and flashed toasts each have a working server to talk to. No handler lists accounts: a directory of users would show every member the name and email of every other member.
The Live starter kit
suprnova new my-app --frontend live scaffolds the same application as the
Inertia kits without a frontend build: no frontend/ directory, no
package.json, and no Node toolchain. Every page is a server-rendered
Live document. The application serves the Live browser runtime
under /__live/assets/ and the library components' stylesheets and scripts
under /suprnova-ui/, so the backend is the only process you run.
The kit keeps the backend the Inertia kits share: the users and notes
tables and models, Note::owned_by(user_id) as the one way to read notes,
the account flows through Auth, PasswordReset, and
EmailVerification, and the route names. Pages render and act through Live
instead of Inertia:
| Page | Route | Layout | Live components |
|---|---|---|---|
| Welcome | / |
application | none |
| Sign in | /login |
guest | LoginForm |
| Register | /register |
guest | RegisterForm |
| Forgot password | /forgot-password |
guest | ForgotPasswordForm |
| Reset password | /reset-password |
guest | ResetPasswordForm |
| Verify email | /verify-email |
guest | VerifyEmail |
| Dashboard | /dashboard |
application | NoteStats, ProfileName |
| Notes | /notes |
application | NoteForm, NoteList |
| A note | /notes/{id} |
application | none |
| Error | any failed request | application | none |
The forms on the guest pages are public seeds, which any visitor can use.
Every other island is identity-bound: it belongs to the signed-in user, and
its route sits behind the auth middleware.
Files
The kit adds these files to the shared backend:
src/controllers/- one controller per page. Each opens the request'sLiveDocument, mounts the page's islands fromlive::mounts(), and renders the page's view.src/views/mod.rs- the view structs andFrame, the part both layouts read: the title, the Live bootstrap tags, the signed-in user, the CSRF token of the sign-out form, and the toast.templates/live/layouts/-guest.htmlfor the account pages andapp.htmlfor the rest, with the header bar, the account menu, and the toast region.head.htmlholds the bootstrap tags and the stylesheet links both layouts include.templates/live/pages/- one template per page. Each starts with{% extends "live/layouts/app.html" %}or the guest layout.src/live/andtemplates/live/*.html- the Live components and their views, registered insrc/live/mod.rs.templates/suprnova-ui/- the library components the views import, installed the waysuprnova live:addinstalls them and recorded insuprnova.toml, so a laterlive:addkeeps them current.src/flash.rs- theToasta finished flow shows on the next page.src/controllers/errors.rs- theErrorPagemiddleware, which renders every framework error response as the error page in the application layout, keeping the response's status, its other headers and its error report. A client that expects JSON keeps the JSON body, and in debug mode a5xxkeeps the development error page.src/controllers/profile.rs-POST /profile/name, the JSON endpoint the Inertia kits ship for the display name; the dashboard's island saves it through Live.public/css/app.css- the page layout, written with the same--sn-tokens the library uses.
What each component does
LoginForm,RegisterForm,ForgotPasswordForm, andResetPasswordFormcheck their fields with the same rules as the Inertia kits' form requests and show each message under its field. An action that succeeds signs the user in, mails a link, or rotates the password, then sends the browser to the next page with a toast.VerifyEmailnames the address the link went to and mails a new link on request.NoteStatsshows the user's note count, the notes written today, and the five newest notes. It subscribes to the streamnotes/:principal, which Live fills with the user's own id. Saving a note publishes a refresh on that topic, so every dashboard the user has open renders again without a page load, over server-sent events or a WebSocket, and through polling when neither connects. Its Refresh button renders it again on request.ProfileNamechanges the display name and reloads the dashboard, so the navigation shows the new name.NoteFormchecks the title (1 to 255 characters) and the text (at most 10000 characters), saves the note, and reloads the list with a toast.NoteListfilters the notes by title and text. The applied search is bound to the?search=query: each search puts it in the address bar without a history entry, and the page mounts the list from it, so a reloaded or shared URL shows the same list. Load more adds 10 notes at a time.
A finished flow keeps its Toast in the session, and the next document
takes it with Toast::take(), which removes it. The toast is an ordinary
session value rather than a session flash, because a flash ages on every
request of the session, the Live requests included. Saving a note makes
your open dashboards refresh, and that refresh would age a flashed toast
away before the redirect lands. The kit also turns session blocking on
(SESSION_BLOCK=true in .env), so the requests of one session run one
at a time and a refresh cannot write over the toast a save just kept.
Add a page
To add a page, give it a route, a view, and a controller:
- Add the route to
src/routes.rs, in the authenticated group if the page needs a user. - Add the view struct to
src/views/mod.rs, and its template totemplates/live/pages/, starting with the layout it extends. - Write the controller. Open the request's
LiveDocument, mount the page's islands, then build theFrame, which emits the bootstrap tags after the last mount, and render the view. - Declare the page in
live::routes()insrc/live/mod.rs: with.try_live_document("/path")?when it mounts no island, or with aLiveMountinMountsand.try_live_mount(&mounts.name)?for each island.
An /about page with no island looks like this:
// src/views/mod.rs
// src/controllers/about.rs
use LiveDocument;
use ;
use crate;
pub async
async
{% extends "live/layouts/app.html" %}
{% block content %}
About
{% endblock %}
Add a component
- Run
suprnova live:make Invoices. It writessrc/live/invoices.rsandtemplates/live/invoices.htmland registers the component. - Add a
LiveMountfor it toMountsinsrc/live/mod.rs:LiveMount::identity_boundwhen it belongs to the signed-in user, orLiveMount::public_seedwhen any visitor may use it. Seal it inlive::routes()with.try_live_mount(&mounts.invoices)?, and mount it from the page's controller. - To use another library component in its view, run
suprnova live:add <name>and link the component's stylesheet intemplates/live/layouts/head.html. - Run
suprnova live:checkto prove every view against its component.
Why Suprnova diverges
Laravel's Livewire starter kit renders Blade views with Livewire components, and still builds its assets with Vite. The Live kit has no build step: the framework serves the Live runtime, and the component library ships as files the scaffold installs into your project, which you own and edit like any other view.
Contributing a starter kit
Built something reusable on top of Suprnova and want to upstream it as a canonical kit? See Contributions. We're happy to take a real implementation and round it into a generic kit.
Every kit is held to the browser suite in suprnova-cli/tests/kit_browser/.
Run cargo test -p suprnova-cli --test kit_browser -- --ignored --test-threads=1
from the repository root. The harness scaffolds all three kits, builds one
backend against the in-tree framework, builds each frontend, and runs the
same Chromium assertions over each served application. It uses the existing
Playwright browser cache; it does not install browsers. Failed runs print
the kit name, the browser output, the server log, and the retained artifact
directory.
The Live kit is held to suprnova-cli/tests/kit_live.rs and to
live_kit_compiles_and_renders in suprnova-cli/tests/scaffold_snapshot.rs,
which builds a fresh Live scaffold against the in-tree framework, starts it,
and requests its pages:
cargo test -p suprnova-cli --test scaffold_snapshot -- --ignored live_.
