Nitro

website·Indexed 36 days ago

https://nitro.build/

A server engine that provides everything a server needs, featuring filesystem routing, a built-in SQL database layer, and a flexible storage system with KV caching. Nitro supports a wide range of deployment presets including Node.js, Deno, Bun, AWS Lambda, Vercel, Netlify, and Cloudflare Workers. It integrates with Vite and provides tools for OpenAPI specification generation, prerendering, and WebSocket support via CrossWS and H3.

Tokens
64.3K
Snippets
387
Records
431
Agent score
74%

What's inside Nitro

  1. Overview of built-in Nitro server features

    Nitro includes several integrated tools that behave consistently across all deployment targets:

    • KV Storage: Unified key-value API for filesystem, Redis, Cloudflare KV, etc.
    • Database: SQL layer powered by db0 (Experimental).
    • Tasks: Runtime operations triggered via CLI or cron (Experimental).
    • WebSockets: Cross-runtime support via crossws.
    • Plugins: Lifecycle hooks defined in the plugins/ directory.
    • OpenAPI: Automatic spec generation for handlers (Experimental).
    • Assets: Direct serving of public files and runtime access to server assets.
    • Renderer: Catch-all handler for SSR, SPA shells, or HTML.
  2. Overview of Nitro server framework

    Nitro is a full-stack, runtime-agnostic server framework designed to be deployable to any target (Node.js, Bun, Deno, Cloudflare Workers, Netlify, Vercel, etc.). It provides a production-ready server featuring filesystem routing (via the routes/ directory), code-splitting, and optimized builds that result in near-0ms boot times for serverless environments. It can be used as a standalone server, as a foundation for meta-frameworks, or integrated into a Vite project.
  3. Understand Nitro renderer routing priority

    The Nitro renderer acts as a catch-all route (/**) and has the lowest priority. Requests are matched in the following order:

    1. Specific API routes (e.g., /api/users)
    2. Specific server routes (e.g., /about)
    3. The renderer (catches all remaining requests)

    If a custom catch-all route ([...].ts) is defined, it is chained with other /** handlers. They run in registration order: file-based catch-all, then server entry, then the renderer. The first handler to return a response wins.

  4. Understand the Nitro request lifecycle order

    Nitro processes incoming requests in the following sequence:

    1. Static Assets: If a match is found, the file is served immediately with appropriate headers (Content-Type, ETag, etc.), and the request terminates.
    2. Global Middleware: Handlers in the middleware/ directory run next.
    3. Routed Middleware: Middleware registered for specific route patterns via config runs after global middleware.
    4. Route-specific Middleware: Middleware attached directly to the matched route runs last, immediately before the handler.
    5. Routes: Nitro matches the request against routes in the routes/ folder.
    6. Server Entry: If no route matches, a defined server entry (acting as a /** handler) catches the request.
    7. Renderer: If still unmatched, Nitro uses a renderer handler (defined or auto-detected).
    8. Response Hook: The response hook runs after the response is created, regardless of which layer produced it.
  5. Create the TanStack Start Server Entry

    Create a server.ts file to serve as the entry point for Nitro. Use createServerEntry from @tanstack/react-start/server-entry and pass the request to the TanStack handler's fetch method.
    import handler, { createServerEntry } from "@tanstack/react-start/server-entry";
    
    export default createServerEntry({
      fetch(request) {
        return handler.fetch(request);
      },
    });
  6. Deploy Nitro apps to GitHub Pages using GitHub Actions

    Deploy a Nitro application to GitHub Pages using the github_pages preset. This requires a GitHub Actions workflow that builds the project with NITRO_PRESET=github_pages, uploads the .output/public directory as an artifact, and uses the actions/deploy-pages action for deployment.
    # .github/workflows/deploy.yml
    name: Deploy to GitHub Pages
    
    on:
      workflow_dispatch:
      push:
        branches:
          - main
    
    jobs:
      build:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v5
          - run: corepack enable
          - uses: actions/setup-node@v6
            with:
              node-version: "20"
    
          - run: npx nypm install
          - run: npm run build
            env:
              NITRO_PRESET: github_pages
    
          - name: Upload artifact
            uses: actions/upload-pages-artifact@v3
            with:
              path: ./.output/public
    
      deploy:
        needs: build
        permissions:
          pages: write
          id-token: write
        environment:
          name: github-pages
          url: ${{ steps.deployment.outputs.page_url }}
        runs-on: ubuntu-latest
        steps:
          - name: Deploy to GitHub Pages
            id: deployment
            uses: actions/deploy-pages@v4
  7. Deploy Nitro apps to AWS Amplify Hosting

    Nitro supports the aws_amplify preset for deployment to AWS Amplify Hosting. Integration is possible with zero configuration. The deployment process involves connecting a Git repository via the AWS Amplify Hosting Console, auto-detecting build settings, and optionally enabling SSR logging to Amazon CloudWatch.
  8. Discover routes automatically via link crawling

    Enable crawlLinks to let Nitro discover routes by following href attributes in prerendered HTML pages. If no routes are specified in prerender.routes, crawling starts from /. External links, hash links, and files with extensions (except .json) are skipped.

    Additionally, server handlers can queue more routes for prerendering by setting the x-nitro-prerender response header to a comma-separated list of paths.

    import { defineConfig } from "nitro";
    
    export default defineConfig({
      prerender: {
        crawlLinks: true,
        routes: ["/"],
      },
    });
  9. Deploy Nitro apps to Vercel

    Nitro supports Vercel with zero configuration. To deploy, use the vercel preset. Note that Nitro's top-level /api directory is incompatible with Vercel; you must use the routes/api/ directory instead.
    # Use the vercel preset in your configuration
    # Preset: vercel
  10. Perform internal server-to-server requests using serverFetch

    When one route needs to call another within the same Nitro application, use the fetch function (or serverFetch in config) from the nitro package instead of the global fetch. This ensures the request stays in-process, avoiding network round-trips and overhead.
    // routes/index.ts
    import { defineHandler } from "nitro";
    import { fetch } from "nitro";
    
    export default defineHandler(() => fetch("/hello"));
    // nitro.config.ts
    import { defineConfig, serverFetch } from "nitro";
    
    export default defineConfig({
      hooks: {
        "dev:start": async () => {
          const res = await serverFetch("/hello");
          const text = await res.text();
          console.log("Fetched /hello in nitro module:", res.status, text);
        },
      },
    });
  11. Deploy Nitro apps to Render.com using Infrastructure as Code (IaC)

    You can deploy to Render.com using a render.yaml blueprint file at the root of your repository. This allows you to define the service type, build command, start command, and required environment variables.
    services:
      - type: web
        name: <PROJECTNAME>
        env: node
        branch: main
        startCommand: node .output/server/index.mjs
        buildCommand: npx nypm install && npm run build
        envVars:
        - key: NITRO_PRESET
          value: render_com
  12. Implement Nitro server routes alongside React Router

    You can add standalone API or server routes by placing them in the server/routes/ directory. Nitro handles these server routes first; if no match is found, it falls through to the React Router SSR handler.
    import { defineHandler } from "nitro";
    
    export default defineHandler(() => {
      return { status: "OK" };
    });