Nitro Server Engine

repository·main·Indexed 11 days ago

https://github.com/unjs/nitro

A production-ready server engine for building and deploying universal JavaScript servers. Nitro extends Vite applications with file-based routing, auto-imports, and support for various server entries including Hono, Elysia, Express, and Fastify. Version 3.0.260610-beta features include cached handlers via defineCachedHandler, global error handling with defineErrorHandler, and a built-in database layer using useDatabase().

Tokens
117.5K
Snippets
449
Records
499
Agent score
93%

What's inside Nitro

  1. What is Nitro?

    main

    Nitro is a full-stack, runtime-agnostic server framework designed for high performance and deployment flexibility. It provides a production-ready server environment with the following core features:

    • Filesystem Routing: Create server and API routes by placing files inside a routes/ directory. Each file maps directly to a URL path.
    • Optimized Builds: Nitro compiles routes at build time, enabling code-splitting so that only the code required for a specific request is loaded. This results in near-0ms boot times, making it ideal for serverless environments.
    • Runtime Agnostic: Nitro can be deployed to Node.js, Bun, Deno, and various hosting platforms (Cloudflare Workers, Netlify, Vercel, etc.) without configuration changes.
    • Extensible Server Entry: While filesystem routing is the default, you can take full control by creating a server.ts file and using any HTTP library like h3, Elysia, or Hono.
    • Built-in Capabilities: Includes native support for key-value storage, caching, and SQL databases.
  2. What is Nitro?

    main
    Nitro is a production-ready server engine designed to extend Vite applications. It allows you to add server routes and deploy your application across multiple platforms with a zero-config experience. It is designed to be portable and run anywhere.
  3. Overview of Nitro Core Features

    main

    Nitro is a production-ready server engine that extends Vite applications. Key capabilities include:

    • File-system Routing: Automatically register server routes by placing them in the routes/ folder.
    • Universal Deployment: Deploy the same codebase to Node.js, Cloudflare Workers, Deno, Bun, AWS Lambda, Vercel, Netlify, and more without vendor lock-in.
    • Universal Storage: A key-value storage abstraction (powered by unstorage) that works with filesystem, Redis, Cloudflare KV, etc.
    • Built-in Caching: Cache route handlers and functions using various storage backends and stale-while-revalidate patterns.
    • Custom Server Entry: Use web standards or your preferred framework (H3, Hono, Elysia, Express) via a server.ts entry point.
    • Server Plugins: Extend runtime behavior by hooking into lifecycle events via files in the plugins/ directory.
    • Built-in Database: A lightweight SQL layer (powered by db0) with SQLite support out of the box and compatibility with PostgreSQL, MySQL, and Cloudflare D1.
    • Assets Management: Serve static public assets or bundle server assets for programmatic access across all deployment targets.
  4. What is the Nitro Renderer and how does it work?

    main

    The Nitro Renderer is a special catch-all handler that intercepts all routes that do not match any specific API or route handler. It is primarily used for:

    • Server-Side Rendering (SSR)
    • Serving Single-Page Applications (SPAs)
    • Creating custom HTML responses

    Priority and Routing

    The renderer acts as a catch-all route (/**) and has the lowest priority in the routing hierarchy:

    1. Specific API routes (e.g., /api/users) are matched first.
    2. Specific server routes (e.g., /about) are matched second.
    3. The Renderer catches everything else.
    WARNING

    If you define a catch-all route (e.g., [...].ts) in your routes, Nitro will warn you that the renderer will override it. Use more specific routes or different HTTP methods to avoid conflicts.

  5. What is a Nitro Server Entry?

    main

    A server entry is a special handler in Nitro that acts as a global middleware, running for every incoming request before routes are matched. It is ideal for cross-cutting concerns such as authentication, logging, request preprocessing, or custom routing logic.

    Key Behaviors

    • Termination: If the server entry returns a Response, the request lifecycle stops there.
    • Continuation: If the server entry returns undefined (or nothing), the request continues to the next stage in the lifecycle (either a specific route handler or the renderer).
    • Priority: Specific routes (in routes/) take priority. The server entry runs for unmatched routes before they reach the renderer.
    export default {
      async fetch(req: Request) {
        // If you return a Response, the request stops here
        // If you return nothing, it continues to routes/ or the renderer
      }
    }
  6. Understand the Nitro request lifecycle with server entry

    main

    The server entry is part of the request lifecycle, specifically acting as a catch-all handler for unmatched routes. The order of execution is:

    1. Server hook: request
    2. Route rules: Headers, redirects, etc.
    3. Global middleware: Files in the middleware/ directory.
    4. Route matching:
      • Specific routes: Handlers in routes/ (if matched, they handle the request).
      • Server entry: Runs for unmatched routes.
      • Renderer: renderer.ts or index.html (if no response was returned by the server entry).
  7. Migrate to H3 v2 (Web Standards)

    main

    Nitro v3 uses H3 v2, which is built on Web Standard primitives (Request, Response, Headers, URL).

    Request and Response

    • event.web is renamed to event.req (an instance of Request).
    • Access to event.node.{req,res} is only available in the Node.js runtime.
    • Use standard Headers API: event.req.headers.get('name') and event.res.headers.set('name', 'value').
    • event.res.status replaces getResponseStatus(event).

    Response Handling

    You must now explicitly return the response body or throw an error instead of using side-effect functions like send().

    Old H3 v1 MethodNew H3 v2 Pattern
    send(event, value)return value
    sendStream(event, stream)return stream
    sendRedirect(event, loc, code)return redirect(event, loc, code)
    sendError(event, error)throw createError(error)
    sendNoContent(event)return noContent(event)
    sendProxy(event, target)return proxy(event, target)

    Request Body

    Replace H3 body utilities with native Request methods on event.req:

    • await event.req.json()
    • await event.req.text()
    • await event.req.formData()
    • event.req.body (for streams)
    // Example of new H3 v2 response pattern
    import { redirect } from "nitro/h3"
    
    export default defineHandler(async (event) => {
      if (someCondition) {
        return redirect(event, '/login', 302)
      }
      return { hello: 'world' }
    })
  8. Use environment-specific configuration overrides

    main

    Nitro allows you to provide overrides for specific environments using $development and $production keys. The environment is identified as "development" during nitro dev and "production" during nitro build.

    import { defineConfig } from "nitro";
    
    export default defineConfig({
      logLevel: 3,
      $development: {
        // Options applied only in development mode
        debug: true,
      },
      $production: {
        // Options applied only in production builds
        minify: true,
      },
    })
  9. Override runtime config using environment variables

    main

    Nitro allows you to override any key defined in your runtimeConfig schema using environment variables. To do this, prefix the environment variable name with NITRO_ followed by the config key in uppercase. For example, a config key apiKey is overridden by NITRO_API_KEY.

    # Example .env file
    NITRO_API_KEY=secret-api-key
  10. Understand the difference between Public and Server Assets

    main

    Nitro distinguishes between two types of assets:

    1. Public Assets: Files in the public/ directory that are served directly to the browser (e.g., images, robots.txt). They are accessible via URL paths.
    2. Server Assets: Files in the assets/ directory that are bundled into the server for programmatic access via the useStorage() API. These are intended for server-side logic rather than direct client access.

    Use Public Assets for anything the client needs to download. Use Server Assets for data or templates needed by your server handlers. For large files, prefer Server Assets or external storage to avoid bloating the server bundle.

  11. How the SSR Outlet works in Nitro

    main

    In a Vite + Nitro SSR setup, the <!--ssr-outlet--> comment in your index.html acts as a injection point.

    When a request is made, Nitro executes the fetch method defined in your server entry. The return value of that fetch method (which can be a string or a ReadableStream) is then used to replace the <!--ssr-outlet--> placeholder in the HTML template before the final response is sent to the client.

  12. Enable Cluster mode for multi-core performance

    main

    To leverage multi-core systems and improve performance, use the node_cluster preset. This mode spawns multiple workers to handle incoming requests.

    ### Cluster Configuration
    - `NITRO_CLUSTER_WORKERS`: Number of cluster workers to spawn. Defaults to the number of available CPU cores.
    
    Note: This preset supports all environment variables available to the `node_server` preset.