· frameworks  · 6 min read

10 Hidden Features of Nuxt.js You Didn't Know About

Discover 10 lesser-known Nuxt.js capabilities - from server/api Nitro handlers and per-route rules to runtime config tricks and built-in image optimization - that can speed development and boost performance.

Discover 10 lesser-known Nuxt.js capabilities - from server/api Nitro handlers and per-route rules to runtime config tricks and built-in image optimization - that can speed development and boost performance.

Outcome: By the end of this post you’ll know 10 lesser-known Nuxt features and how to use each to ship faster, reduce bundle weight, improve render behavior, or simplify server logic.

Nuxt is full of productive conventions. You probably already know about pages, components auto-import, and server-side rendering. But beneath those headline features are small, high-leverage capabilities that often go unused - until you need them.

This post walks through 10 of them with practical examples, benefits, and tips so you can start applying them today.

1) Server API with Nitro - server/api routes (no server framework required)

What it is: Drop a file in server/api/ and it becomes a server endpoint powered by Nitro. No Express/Koa wiring.

Why it matters: Build backend logic and server endpoints inside the same repo with a tiny API surface and deploy to serverless or edge platforms seamlessly.

Example (server/api/hello.get.ts):

import { defineEventHandler, getQuery } from 'h3';

export default defineEventHandler(event => {
  const q = getQuery(event);
  return {
    message: `Hello ${q.name ?? 'world'}`,
  };
});

Client call:

const data = await $fetch('/api/hello?name=Dev');

Tip: Use useCookie, readBody, and setCookie inside handlers. See Nitro docs for advanced features like route caching and prerendering.

Docs: https://nitro.unjs.io/

2) Per-route behavior with defineNuxtRouteRules

What it is: Fine-grained rules per route - control SSR, caching, CORS, headers, ISR and more - from a single config place.

Why it matters: You can render most routes statically but keep a few as SSR or enable ISR for specific pages.

Example (nuxt.config.ts):

export default defineNuxtConfig({
  routeRules: {
    '/admin/**': { ssr: true },
    '/blog/**': { isr: 60 }, // cache for 60s and regenerate
    '/api/**': { cors: true },
  },
});

Tip: Use ISR for expensive pages that update occasionally (like a blog index) to get static performance and near-real-time updates.

Docs: https://nuxt.com/docs/getting-started/routes#route-rules

3) Auto-imported composables & useState for app-wide reactive state

What it is: Create a composable in composables/ like useCart.ts and Nuxt auto-imports it anywhere. useState provides reactive, SSR-friendly global state.

Why it matters: No repetitive imports and a simple, consistent way to share state without Vuex/Pinia for smaller needs.

Example composable (composables/useCounter.ts):

export const useCounter = () => {
  const count = useState('count', () => 0);
  const inc = () => count.value++;
  return { count, inc };
};

Then in any component you can call const { count, inc } = useCounter() with no import.

Tip: useState persists per session on the server render, preventing hydration mismatch when correctly initialized.

Docs: https://nuxt.com/docs/getting-started/composables

4) Revalidation, caching and incremental static regeneration (ISR)

What it is: Use defineNuxtRouteRules for ISR and use built-in server caching strategies. Also use useAsyncData with server/lazy options to control fetch timing.

Why it matters: You can combine static generation and on-demand regeneration so pages load fast and stay reasonably fresh.

Example: Enable ISR for a news listing in nuxt.config.ts:

export default defineNuxtConfig({
  routeRules: {
    '/news/**': { isr: 120 }, // regenerate in background every 120s
  },
});

Client-side fetch with useAsyncData:

const { data } = await useAsyncData('posts', () => $fetch('/api/posts'), {
  server: true, // fetch on server during SSR
  lazy: false,
});

Tip: Combine ISR with cache headers in server handlers to get predictable CDN caching behavior.

Docs: https://nuxt.com/docs/getting-started/routes#isr

5) Runtime config separates server-only secrets from public keys

What it is: runtimeConfig holds environment-specific values. You can mark keys as public or keep them server-only.

Why it matters: Safely reference private API keys on the server while exposing only what the client needs.

Example (nuxt.config.ts):

export default defineNuxtConfig({
  runtimeConfig: {
    // server-only
    mySecret: process.env.MY_SECRET,
    public: {
      apiBase: process.env.PUBLIC_API_BASE || '/api',
    },
  },
});

Usage in code:

const config = useRuntimeConfig();
const base = config.public.apiBase;
// on server you can access config.mySecret

Tip: Use useRuntimeConfig() in server routes so secrets never leak to the client.

Docs: https://nuxt.com/docs/getting-started/runtime-config

6) Small server helpers: useCookie, useStorage, useRequestEvent

What it is: Nuxt provides composables that work both client/server: useCookie, useRequestEvent in server handlers, useStorage (localStorage abstraction) and more.

Why it matters: These unify code across environments and reduce boilerplate for things like persisted preferences or SSR-safe cookies.

Example cookie:

// server or client
const theme = useCookie('theme', { default: 'light' });

// set in server handler
export default defineEventHandler(({ event }) => {
  setCookie(event, 'token', 'abc', { httpOnly: true });
});

Docs: https://nuxt.com/docs/getting-started/composables#cookies

7) Built-in image optimization (Nuxt Image module)

What it is: The Nuxt Image module optimizes images on-the-fly (format, size, lazy-loading, placeholders). It supports local/static images and remote providers.

Why it matters: Automatically reduce payloads, serve WebP/AVIF when supported, and improve Largest Contentful Paint without manual tooling.

Example (component):

<template>
  <NuxtImg src="/hero.jpg" width="1200" placeholder="blur" />
</template>

Tip: Combine the module with a CDN for best results. You can set default formats and device sizes in module config.

Docs: https://image.nuxtjs.org/

8) defineNuxtRouteMiddleware & named middleware (simple, per-route logic)

What it is: Create route middleware files and reference them per-page or globally using defineNuxtRouteMiddleware or page middleware metadata.

Why it matters: Run authentication checks, analytics, or prefetch logic with minimal ceremony.

Example (middleware/auth.ts):

export default defineNuxtRouteMiddleware(to => {
  const user = useSupabaseUser?.() || useState('user');
  if (!user?.value) return navigateTo('/login');
});

Then on a page:

definePageMeta({ middleware: 'auth' });

Tip: Use middleware only for short synchronous checks. For heavy async loading prefer server middleware or fetch inside the page.

Docs: https://nuxt.com/docs/getting-started/runtime#middleware

9) Component auto-importing with smart prefixes and level control

What it is: Nuxt auto-imports components placed in components/. You can organize components into nested folders and control global registration via file naming conventions or config.

Why it matters: Reduces imports and supports scalable component directories. You can also use <ClientOnly> automatically.

Example: A component at components/ui/Button.vue can be used as <UiButton /> or <button /> depending on your naming rules.

Control options in nuxt.config.ts:

export default defineNuxtConfig({
  components: [{ path: '~/components', global: true }],
});

Tip: Prefix large UI libraries’ components (e.g., Ui) to avoid name collisions.

Docs: https://nuxt.com/docs/getting-started/components

10) Devtools and nitro debugging helpers - inspect server handlers & routes

What it is: Nuxt DevTools (and Nitro) provide UI to inspect composables, server routes, middleware, and runtime config during development.

Why it matters: Quickly discover which composables are used where, see route generation, and debug server handlers without console logging.

How to open: In dev mode visit /__nuxt_devtools or run Nuxt with the devtools enabled in config.

Tip: Use DevTools to inspect auto-import maps and find unused components or server routes before deployment.

Docs: https://nuxt.com/docs/getting-started/commands#dev


Closing notes - how to pick which features to adopt now

  • If you have small backend needs, start with server/api and Nitro handlers (1). They dramatically simplify fullstack code.
  • If you want to squeeze performance from a static site, combine route rules + ISR (2 & 4) and the image module (7).
  • For faster iteration and cleaner app architecture, lean into auto-imported composables, useState and runtime config (3 & 5).

Each of these features was built to reduce friction and make common tasks trivial. Try one or two in your next sprint and you’ll likely find they remove a surprising amount of boilerplate.

Further reading

Back to Blog

Related Posts

View All Posts »
The Hidden Powerful Features of Nuxt.js You Didn't Know About

The Hidden Powerful Features of Nuxt.js You Didn't Know About

Discover Nuxt.js features you may have missed - from advanced meta tag control with useHead to Nitro-powered server routes, automatic image optimization, route rules, and SEO modules - and learn practical patterns to boost performance and search visibility.

Unlocking the Power of Dependency Injection in NestJS

Unlocking the Power of Dependency Injection in NestJS

A deep dive into NestJS's dependency injection system: how it works, advanced techniques (custom providers, scopes, ModuleRef), common pitfalls and fixes, and practical patterns to produce cleaner, more testable code.