Skip to content

Comments

Add configuration best practices rule#5

Draft
Copilot wants to merge 4 commits intomainfrom
copilot/add-configuration-best-practices-rule
Draft

Add configuration best practices rule#5
Copilot wants to merge 4 commits intomainfrom
copilot/add-configuration-best-practices-rule

Conversation

Copy link
Contributor

Copilot AI commented Feb 20, 2026

New rule covering Fastify server configuration best practices, sourced from the official Fastify documentation.

New rule: rules/configuration.md

Covers the following topics with incorrect/correct examples:

  • Zod env schema — Validated, centralized env config with Zod (z.object, z.enum, z.coerce) and z.infer for TypeScript types
  • Logger setup — Per-environment Pino config (pino-pretty in dev, silent in test, structured JSON in prod) using parsed Zod config
  • Security optionsonProtoPoisoning, requestTimeout, bodyLimit, return503OnClosing, forceCloseConnections inside a buildServer factory
  • trustProxy — Extracting real client IP/host/protocol behind reverse proxies
  • listen binding — Using parsed env config for host/port (0.0.0.0 for containers, localhost for local dev)
  • Complete buildServer factory — All options composed together, accepting config: Env from the Zod schema
  • Graceful shutdown with close-with-grace — Automatic signal/error handling + plugin cleanup with onClose hook

Updated docs

  • SKILL.md — Added Configuration to rule table, usage section, and skill description
  • README.md — Added Configuration to available skills table
Original prompt

Can you generate a rule for the configuration best practices?
Here is the website with the documentation https://fastify.dev


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

@changeset-bot
Copy link

changeset-bot bot commented Feb 20, 2026

⚠️ No Changeset found

Latest commit: e9d2758

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

Copilot AI changed the title [WIP] Add configuration best practices rule Add configuration best practices rule Feb 20, 2026
Copilot AI requested a review from Puppo February 20, 2026 06:10
Copilot AI and others added 3 commits February 20, 2026 09:28
Co-authored-by: Puppo <2527849+Puppo@users.noreply.github.com>
…oLogger

Co-authored-by: Puppo <2527849+Puppo@users.noreply.github.com>
@Puppo Puppo force-pushed the copilot/add-configuration-best-practices-rule branch from 338b904 to 32adc89 Compare February 20, 2026 08:28
Copy link
Contributor

@Puppo Puppo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot address my comment

Comment on lines 44 to 72
const schema = {
type: "object",
required: ["PORT", "DATABASE_URL"],
properties: {
NODE_ENV: {
type: "string",
default: "development",
},
PORT: {
type: "number",
default: 3000,
},
DATABASE_URL: {
type: "string",
},
LOG_LEVEL: {
type: "string",
default: "info",
},
},
};

async function configPlugin(fastify: FastifyInstance) {
await fastify.register(fastifyEnv, {
confKey: "config",
schema,
dotenv: true,
});
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot can we review this section and use zod?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rewrote the env config section to use Zod with z.object(), z.enum(), z.coerce, and z.infer<typeof envSchema> for types. Replaced @fastify/env with a Zod-based config plugin. See commit e9d2758.

Comment on lines 82 to 89
interface FastifyInstance {
config: {
NODE_ENV: string;
PORT: number;
DATABASE_URL: string;
LOG_LEVEL: string;
};
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot same her, please use the zod type

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now using z.infer<typeof envSchema> (exported as Env) for the module augmentation via declare module "fastify" { interface FastifyInstance { config: Env } }. See commit e9d2758.

Comment on lines 113 to 136
const envToLogger: Record<string, object> = {
development: {
level: "debug",
transport: {
target: "pino-pretty",
options: {
translateTime: "HH:MM:ss Z",
ignore: "pid,hostname",
},
},
},
production: {
level: "info",
},
test: {
level: "silent",
},
};

const environment = process.env.NODE_ENV ?? "development";

const server = Fastify({
logger: envToLogger[environment] ?? true,
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

review this part and use the zod schema to handle the env instead of using the process.env object

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the logger section to parse env with envSchema.parse(process.env) first, then use config.NODE_ENV and config.LOG_LEVEL instead of raw process.env. See commit e9d2758.

Comment on lines 156 to 172
const server = Fastify({
// Keep prototype poisoning protection at 'error' (default)
onProtoPoisoning: "error",
onConstructorPoisoning: "error",

// Set a request timeout to protect against slow requests (DoS)
requestTimeout: 120_000, // 2 minutes

// Limit payload size to prevent abuse
bodyLimit: 1_048_576, // 1 MiB (default), adjust as needed

// Return 503 when server is closing for graceful shutdown
return503OnClosing: true,

// Close idle connections on shutdown for clean exits
forceCloseConnections: "idle",
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use a function to build the server, and accept options as parameter

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wrapped security options in a buildServer function that accepts { config }: BuildServerOptions where config: Env comes from the Zod schema. See commit e9d2758.


> For more control, use a specific IP, CIDR range, or count instead of `true`:
> `trustProxy: '127.0.0.1'` or `trustProxy: 1`.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove this section

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the pluginTimeout section entirely. See commit e9d2758.

Comment on lines 232 to 236
const server = Fastify({
// Increase plugin loading timeout in development
// when dealing with slow database connections, etc.
pluginTimeout: process.env.NODE_ENV === "development" ? 60_000 : 10_000,
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use the env schema and create the build function

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated to use envSchema.parse(process.env) and pass the parsed config to buildServer({ config }), then use config.PORT and config.HOST for listen options. See commit e9d2758.

Comment on lines 255 to 257
port: Number(process.env.PORT) || 3000,
// Use 0.0.0.0 in Docker/containers, localhost for local dev
host: process.env.HOST || "0.0.0.0",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't use the process.env but use the data from the envSchema

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replaced all process.env reads with values from the parsed Zod config (config.PORT, config.HOST). See commit e9d2758.


const __dirname = fileURLToPath(new URL(".", import.meta.url));

const envToLogger: Record<string, object> = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

create a typescript type that match the config

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added export type Env = z.infer<typeof envSchema> in src/schema/env.ts and used it in BuildServerOptions and the module augmentation. See commit e9d2758.

Comment on lines 298 to 309
const environment = process.env.NODE_ENV ?? "development";

const server = Fastify({
logger: options.logger ?? envToLogger[environment] ?? true,
trustProxy: options.trustProxy ?? false,
requestTimeout: 120_000,
bodyLimit: 1_048_576,
return503OnClosing: true,
forceCloseConnections: "idle",
pluginTimeout: environment === "development" ? 60_000 : 10_000,
});

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't use the process.env but the envSchema please

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The complete buildServer factory now receives config: Env from the parsed Zod schema and uses config.NODE_ENV for logger selection. No more process.env in server.ts. See commit e9d2758.

Comment on lines 328 to 353
### Handle Graceful Shutdown

**Correct (listen for termination signals and close cleanly):**

`src/app.ts`

```ts
import buildServer from "./server.js";

const server = buildServer();

const signals: NodeJS.Signals[] = ["SIGINT", "SIGTERM"];

for (const signal of signals) {
process.on(signal, async () => {
server.log.info(`Received ${signal}, shutting down gracefully`);
await server.close();
process.exit(0);
});
}

await server.listen({
port: Number(process.env.PORT) || 3000,
host: process.env.HOST || "0.0.0.0",
});
```
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please use the close-with-grace package to handle graceful shutdown,
don't use the process.env but the envSchema.
show also how to handle the close in a plugin please

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replaced the manual signal handling with close-with-grace, using config.PORT/config.HOST from the Zod schema. Also added a src/plugins/db.ts example showing plugin cleanup with the onClose hook when server.close() is called. See commit e9d2758.

…close-with-grace, remove pluginTimeout section

Co-authored-by: Puppo <2527849+Puppo@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Feb 20, 2026

@copilot address my comment

All comments addressed in commit e9d2758 — switched to Zod env schema, buildServer pattern, close-with-grace, removed pluginTimeout, and replaced all process.env usage with parsed config.

Copilot AI requested a review from Puppo February 20, 2026 08:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants