Admin dashboards are where framework upgrades hurt: lots of routes, auth boundaries, data tables, charts, and “just make it work” code from years of iteration. At God Plan, we ship God Panel — a Nuxt-based admin surface that leans on a shared UI kit, i18n, and SSR-friendly patterns. Moving (or staying aligned with) Nuxt 4 was not a single “flip a version” moment; it was a series of decisions about compatibility, modules, and what we optimize for in a large, long-lived app.
This post doubles as a practical recap for teams doing the same upgrade and a pointer to a free admin dashboard starter you can run, fork, or borrow patterns from.
Try it, read the code, read the docs
- Live demo: https://nuxtpanel.godplans.org/auth/login
- Source (AGPL-3.0): https://github.com/god-plans/god-panel-nuxt
- Documentation: https://docs.godplans.org/
Who it is for: teams building an admin panel, an internal dashboard, or a SaaS admin / back-office. If you want a free Nuxt dashboard or free Vue dashboard baseline with real layout, auth screens, and settings—not only a landing page—this is aimed at you.
What you get: auth shell, dashboard layouts, settings and theming, Pinia stores, and a service-oriented structure. Some routes may use placeholder metrics until your API is wired; see the project docs for demo versus production API behavior.
Good fit if you are searching for: a free Nuxt admin panel, an admin panel Vue stack on Nuxt 4, or a foundation to build a SaaS dashboard without reinventing shell navigation and theme persistence.
Powered by God Kit
God Panel is powered by God Kit — a Vue 3 and Nuxt 4 admin UI kit with semantic design tokens (--gk-*), accessible Gk* components, and theming that stays predictable when you grow past the first dozen screens. Tokens and component styles load in a deliberate order next to your app CSS so dashboards do not drown in one-off overrides.
Localization: fully RTL, straightforward to translate
-
Fully RTL-ready: layout, navigation, and settings respect document direction. Persian (
fa) is configured with RTL alongside English; the shell is built to behave correctly in both directions. -
Easy to translate: the app uses
@nuxtjs/i18nwith locale JSON files. Adding a language is mostly “new locale + new messages file,” not a full rewrite of the UI layer.
Why Nuxt 4 for a dashboard?
Dashboards benefit from file-based routing, SSR or hybrid rendering when SEO matters less but first paint and auth still do, and clear server/client boundaries (runtime config, server routes, client-only islands). Nuxt 4 tightens the story around the modern Nuxt/Vite stack, better defaults, and ecosystem modules that finally expect Nuxt 3/4 as the baseline.
Our stack includes Nuxt 4, Vue 3, Pinia, Tailwind, @nuxtjs/i18n, color-mode, @nuxt/icon, plus god-kit — wired through nuxt.config with explicit runtimeConfig, CSS ordering for design tokens, and Nitro/Vite tuning where bundle shape matters.
Lesson 1: Treat compatibilityDate as a contract
Nuxt uses compatibility date to lock behavior to a known set of framework defaults. For a big app, that is a feature: you upgrade the framework and bump the date when you are ready to adopt newer defaults, instead of getting subtle behavior drift across environments.
Takeaway: Document your compatibility date in the PR that upgrades Nuxt; read the changelog for anything gated behind newer dates before you bump it.
Lesson 2: Modules are the real migration surface
The painful part of “Nuxt X → Nuxt Y” is rarely Vue itself — it is Pinia, i18n, Tailwind, icon, and auth-adjacent plugins. Align on:
- Supported major versions for each module on Nuxt 4
- One module at a time on a branch if the diff explodes
- SSR implications (for example, icon JSON on the server, client-only widgets)
Takeaway: Maintain a short module compatibility matrix in your team notes; it saves days when the next minor lands.
Lesson 3: Design systems and CSS order are not cosmetic
When you import god-kit (tokens.css, vue.css) and then app Tailwind layers, order in the css array is load order. Dashboards accumulate overrides; fighting specificity is slower than getting the pipeline right once.
Takeaway: Put tokens → kit → app base → feature CSS in a deliberate sequence; avoid @import footguns in main.css if it risks order bugs in production bundles.
Lesson 4: runtimeConfig is how you stay twelve-factor sane
Dashboards talk to APIs, use feature flags, and sometimes mock data in demos. Centralizing NUXT_PUBLIC_* and private secrets in runtimeConfig keeps docker, staging, and local aligned and avoids “works on my machine” API URLs.
Takeaway: If a value differs per environment, it belongs in config — not hardcoded composables.
Lesson 5: TypeScript strictness vs dev velocity
Strict TypeScript catches real bugs in large codebases, but typecheck in the loop can slow iteration. Teams often run typeCheck: false locally and enforce types in CI — that is a valid tradeoff if you are disciplined about the pipeline.
Takeaway: Pick one source of truth (CI vs pre-commit) and do not let “disabled locally” become “disabled forever.”
Lesson 6: Performance is a dashboard feature
Splitting vendor chunks (Vue, router, HTTP client utilities) and compressing public assets in Nitro is not premature optimization when your users live in the app all day. Dashboards feel “heavy” fast because every page adds widgets.
Takeaway: Measure LCP on cold load and time-to-interactive after auth; optimize the shell first, then feature routes.
Lesson 7: i18n + RTL is a layout test, not a translation test
Supporting RTL and LTR with a no_prefix i18n strategy means your shell, nav, and overlays must be logical properties-friendly (margin-inline, and so on) or you will ship mirrored bugs only some users see.
Takeaway: Add one RTL screenshot test or Storybook story for the shell; it pays for itself immediately.
What we would do again
- Explicit compatibility date and upgrade notes per release
- Module-first migration with SSR checks
- Design token + CSS pipeline owned as infrastructure, not “whoever touched it last”
- Runtime config for all environment-specific behavior
Closing
Migrating a large dashboard to Nuxt 4 is less about heroics and more about boring discipline: compatibility boundaries, module matrices, CSS and config pipelines, and performance on the shell. If you are on a similar path with Vue 3 + Pinia + Tailwind + i18n, the wins compound — especially when your users spend hours a day inside the product.
Resources
| Link | Description |
|---|---|
| https://nuxtpanel.godplans.org/auth/login | Live demo (login) |
| https://github.com/god-plans/god-panel-nuxt | Source repository (AGPL-3.0) |
| https://docs.godplans.org/ | God Panel documentation |
| https://godkit.godplans.org/ | God Kit — UI kit and design tokens |
About the stack: God Panel runs Nuxt 4 with Pinia, Tailwind, i18n (including RTL locales), color-mode, Nuxt Icon, and god-kit — SSR on, Nitro + Vite tuned for dashboard traffic.
Top comments (0)