{
"printWidth": 100,
"tabWidth": 2,
"semi": true,
"singleQuote": true,
"quoteProps": "as-needed",
"trailingComma": "all",
"bracketSpacing": true,
"arrowParens": "always",
"endOfLine": "lf",
"plugins": ["prettier-plugin-tailwindcss"],
"overrides": [
{
"files": "*.md",
"options": {
"tabWidth": 2,
"proseWrap": "preserve"
}
},
{
"files": ["*.yml", "*.yaml"],
"options": {
"singleQuote": false
}
},
{
"files": "*.json",
"options": {
"printWidth": 80,
"trailingComma": "none"
}
}
]
}
{
"root": true,
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 2021,
"sourceType": "module"
},
"plugins": ["@typescript-eslint"],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:prettier/recommended",
"prettier"
],
"rules": {
"prettier/prettier": "error",
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": ["warn", { "argsIgnorePattern": "^_" }]
},
"ignorePatterns": ["dist/", "build/", "coverage/", "node_modules/"]
}
{
"name": "@acme/monorepo",
"private": true,
"version": "1.4.0",
"workspaces": ["packages/*", "apps/*"],
"scripts": {
"format": "prettier --write \"**/*.{ts,tsx,js,jsx,json,md,yml,yaml,css}\"",
"format:check": "prettier --check \"**/*.{ts,tsx,js,jsx,json,md,yml,yaml,css}\"",
"lint": "eslint . --ext .ts,.tsx,.js,.jsx",
"prepare": "husky install"
},
"lint-staged": {
"*.{ts,tsx,js,jsx}": ["eslint --fix", "prettier --write"],
"*.{json,md,yml,yaml,css}": ["prettier --write"]
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "6.21.0",
"@typescript-eslint/parser": "6.21.0",
"eslint": "8.57.0",
"eslint-config-prettier": "9.1.0",
"eslint-plugin-prettier": "5.1.3",
"husky": "9.0.11",
"lint-staged": "15.2.2",
"prettier": "3.2.5",
"prettier-plugin-tailwindcss": "0.5.11"
}
}
This snippet shows how a shared Prettier setup is wired into a JavaScript/TypeScript monorepo so that every package formats code the same way, with a few well-justified per-language exceptions. The core idea is to make formatting a non-negotiable, machine-enforced concern: developers stop debating quote style and trailing commas because a single config decides, and a pre-commit hook guarantees the rules are applied before anything lands in version control.
The .prettierrc.json tab is the single source of truth. Base options like singleQuote, trailingComma: "all", and printWidth: 100 set the house style, while the overrides array narrows behavior by file glob. Markdown gets proseWrap: "preserve" so hand-wrapped prose is not reflowed, and .md files use two-space tabs; YAML sets singleQuote: false because YAML string quoting rules differ from JS and double quotes are safer. The plugins entry pulls in prettier-plugin-tailwindcss, which reorders utility classes deterministically. Using overrides rather than multiple config files keeps everything discoverable in one place.
Because a formatter and a linter can disagree, .eslintrc.json disables stylistic ESLint rules and delegates them to Prettier. Extending "prettier" last turns off conflicting rules, and "plugin:prettier/recommended" surfaces formatting drift as a single prettier/prettier lint error. This separation of concerns lets ESLint focus on correctness while Prettier owns layout.
The package.json tab connects the config to actual workflows. The format and format:check scripts run Prettier over the tree, the latter used in CI to fail builds on unformatted code. The prepare script installs Husky, and lint-staged runs Prettier only on staged files matching each glob, so commits are fast and touch only what changed. A .prettierignore (referenced implicitly) would exclude build output.
A common pitfall is letting editors reformat entire files and creating noisy diffs; scoping lint-staged to changed files avoids that. Another is forgetting to pin the Prettier version, since output can shift between majors — pinning keeps formatting reproducible across machines and CI. This layout is the pragmatic default for teams that want zero formatting bikeshedding.
Related snips
const withBundleAnalyzer = require('@next/bundle-analyzer')({
enabled: process.env.ANALYZE === 'true',
openAnalyzer: true,
});
/** @type {import('next').NextConfig} */
Next.js bundle analyzer for targeted performance work
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { fileURLToPath, URL } from 'node:url';
const resolvePath = (relative: string): string =>
fileURLToPath(new URL(relative, import.meta.url));
TypeScript path aliases (tsconfig + bundler)
package config
import (
"errors"
"os"
"strconv"
Config parsing with env defaults and strict validation
import js from '@eslint/js';
import tseslint from 'typescript-eslint';
import prettierConfig from 'eslint-config-prettier';
export default [
js.configs.recommended,
ESLint config that avoids bikeshedding
use std::fmt;
struct Point {
x: i32,
y: i32,
}
std::fmt::Display for user-facing string representations
use std::env;
fn main() {
let port: u16 = env::var("PORT")
.unwrap_or_else(|_| "8080".to_string())
.parse()
Environment variables with std::env for configuration
Share this code
Here's the card — post it anywhere.