jarvusinnovations/agent-skills · Archived

jarvus-fastify

Backend development using Fastify + TypeScript on Bun. Use when creating new backend APIs, adding routes, implementing services, working with plugins, or configuring environment variables.

First seen Jun 28, 2026

Installation

$ npx skills add jarvusinnovations/agent-skills --skill jarvus-fastify

Stronger alternatives

This repository is archived — consider an actively maintained alternative.

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from jarvusinnovations/agent-skills · top by installs.

npx skills add jarvusinnovations/agent-skills

Browse all from jarvusinnovations/agent-skills

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Repository health

Stars 1
Default branch main
Open issues 1
Status Archived

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 8,715 B
  • docs SUMMARY.md 210 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 6 installs

SKILL.md

Backend Fastify Stack (Bun)

High-performance backend stack, run on Bun:

  • Bun - Runtime, package manager, test runner, and watch-mode dev server (no Node.js, npm, or tsx)
  • Fastify 5.x - Web framework
  • TypeScript - Type safety, executed directly by Bun (no build step for services)
  • pino-pretty - Pretty logging for development
  • @fastify/env - Environment variable validation with JSON Schema
  • @fastify/cors - CORS support
  • fastify-plugin - Plugin system

Bun runs TypeScript source directly, so there is no compile step in the dev loop and none in production for a service — you ship and run the source. tsc is kept only as a type checker (tsc --noEmit), never as a build tool.

Environment Setup

Use asdf to manage Bun:

# Install the Bun plugin (one-time)
asdf plugin add bun

# Pin Bun for the project (writes .tool-versions)
asdf set bun latest
asdf install

This writes a .tool-versions file pinning Bun so the whole team runs the same version. A born-on-Bun service needs only bun in .tool-versions — add nodejs only if the repo also ships an npm-distributed CLI that needs the Node toolchain.

Reference Files

File When to Use
[setup-guide.md](references/setup-guide.md) Starting a new backend project from scratch
[patterns.md](references/patterns.md) Implementing routes, services, schema validation
[authentication.md](references/authentication.md) Auth: deny-by-default gateway, sessions, tokens, OIDC, local dev mode
[api-design.md](references/api-design.md) Swagger/OpenAPI integration, response format, errors
[mcp-integration.md](references/mcp-integration.md) Integrating MCP server for AI agent access
[gotchas.md](references/gotchas.md) Debugging issues, common mistakes and fixes

Quick Reference

Commands

# Dev server with watch mode (Bun reloads on change)
bun run dev          # → bun --watch src/index.ts

# Type check (no emit — Bun runs the source, tsc only checks types)
bun run typecheck    # → tsc --noEmit

# Run the server (no build needed — Bun executes the source)
bun run start        # → bun run src/index.ts

# Tests (Bun's built-in runner)
bun test

Package Management

Use Bun for all dependency management — never edit package.json by hand:

bun add fastify-plugin @fastify/cors        # runtime deps
bun add -d @types/bun pino-pretty           # dev deps
bun remove <pkg>                            # remove

bun add resolves the latest compatible version and keeps bun.lock in sync. Commit bun.lock.

Key Imports

// Fastify types
import Fastify, { FastifyInstance, FastifyPluginAsync } from 'fastify'
import fp from 'fastify-plugin'

// Common plugins
import fastifyEnv from '@fastify/env'
import cors from '@fastify/cors'

Configuration Access

Always access configuration through fastify.config, never process.env directly:

// CORRECT - type-safe, validated at startup
const port = fastify.config.PORT
const apiKey = fastify.config.API_KEY

// WRONG - no validation, no type safety
const port = process.env.PORT  // Don't do this

@fastify/env's JSON Schema covers per-variable shape validation. When config needs cross-field contracts ("exactly one of these two modes"), environment-detection guards, or strict tri-state booleans, hand-rolled fail-fast validation at boot is the right tool — see setup-guide.md "When JSON Schema isn't enough".

Response Format

Pick one convention per API and stick to it. The envelope below is one option; structured domain-specific bodies (e.g. {error: "forbidden", required, environment, your_role}) are equally valid and often spec-mandated — see [api-design.md](references/api-design.md).

// The envelope option
{
  success: boolean
  data?: T
  error?: string
  metadata?: { timestamp: Date }
}

Plugin Pattern

import fp from 'fastify-plugin'

export default fp(async (fastify, opts) => {
  // Plugin logic here
  fastify.decorate('something', value)
}, '5.x')

Route Pattern

import { FastifyPluginAsync } from 'fastify'

const routes: FastifyPluginAsync = async (fastify, opts) => {
  fastify.get('/', async (request, reply) => {
    return { success: true, data: 'example' }
  })
}

export default routes

Service Pattern

// 1. Create service class
export class MyService {
  constructor(private fastify: FastifyInstance) {}

  async doWork() {
    // Access config through fastify instance
    const apiKey = this.fastify.config.API_KEY
    this.fastify.log.info('Service method called')
  }
}

// 2. Declare module augmentation
declare module 'fastify' {
  interface FastifyInstance {
    myService: MyService
  }
}

// 3. Initialize and decorate in app.ts
fastify.decorate('myService', new MyService(fastify))

TypeScript Config

Bun runs the source directly, so tsconfig.json is for type checking only ("noEmit": true). The Bun-native config:

{
  "compilerOptions": {
    "target": "ESNext",
    "module": "Preserve",          // let Bun own module resolution
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "verbatimModuleSyntax": true,
    "types": ["@types/bun"],        // Bun globals (Bun.file, Bun.serve, etc.)
    "strict": true,
    "noUncheckedIndexedAccess": true,
    "skipLibCheck": true,
    "noEmit": true
  }
}

In a Bun-workspaces monorepo, the package tsconfigs use TypeScript project references ("composite": true, per-package references) and the root runs tsc -b; the runtime story is unchanged — Bun still executes the source.

Project Structure

backend/
├── src/
│   ├── plugins/          # Fastify plugins (env, auth, etc.)
│   ├── routes/           # HTTP route handlers
│   ├── services/         # Business logic classes
│   ├── lib/              # Shared utilities / clients
│   ├── app.ts            # Plugin registration & setup
│   └── index.ts          # Server entry point
├── package.json
├── tsconfig.json
├── .env.example
└── .gitignore

Common Gotchas

  • Plugin order matters: Register env plugin first, then services, then routes
  • Config access: Use fastify.config.VAR not process.env.VAR
  • Server ready: Call await server.ready() before accessing config in index.ts
  • No build step: Bun runs the source; tsc is --noEmit for type checking only
  • Path normalization: Centralize path utilities, handle root '/' as special case
  • Package management: Use bun add <pkg> not manual package.json edits

CI & Code Quality

Wire lint, format, and type-check into CI from the start. The cross-cutting setup (asdf provisioning + caching, path-filtered workflows, lockfile-frozen installs, the GitHub Actions templates) lives in the ci-quality-gates skill; this section is the Fastify-stack specifics that plug into it.

Linter + formatter: oxlint + oxfmt (the Jarvus standard — not eslint/prettier):

bun add -d oxlint oxfmt

The script contract. Expose the same four scripts every Jarvus TS package does, so CI just calls bun run <name>:

{
  "scripts": {
    "dev":          "bun --watch src/index.ts",
    "start":        "bun run src/index.ts",
    "typecheck":    "tsc --noEmit",
    "lint":         "oxlint index.ts src",
    "format":       "oxfmt index.ts src",
    "format:check": "oxfmt --check index.ts src",
    "test":         "bun test"
  }
}

Use the base oxc config (references/templates/oxlintrc.base.json from ci-quality-gates, correctness=error) as the service's .oxlintrc.json — backend code doesn't need the React tier. In a Bun-workspaces monorepo, put the base config at the repo root as .oxlintrc.base.json and have each package extend it; a service that contains a UI subfolder adds "ignorePatterns": ["ui"] so the UI is linted by its own config.

CI workflow. A single service uses one ts-lint-style job (lint + format:check + typecheck) plus a test job; a monorepo uses the per-package matrix in ci-quality-gates's lint.yml / test.yml. All provisioned by the shared setup-asdf composite. Type-check is a required gate — tsc --noEmit catches bugs no linter does.