🎯

nodejs-best-practices

🎯Skill

from fil512/upship

VibeIndex|
What it does

Enforces clean, maintainable Node.js code with best practices for Express routes, PostgreSQL database interactions, async handling, and secure testing.

πŸ“¦

Part of

fil512/upship(9 items)

nodejs-best-practices

Installation

πŸ“‹ No install commands found in docs. Showing default command. Check GitHub for actual instructions.
Quick InstallInstall with npx
npx skills add fil512/upship --skill nodejs-best-practices
2Installs
-
AddedFeb 4, 2026

Skill Details

SKILL.md

Clean, maintainable Node.js code following industry best practices. Use when writing Express routes, services, database queries, error handling, or tests. Covers PostgreSQL connection pooling, transactions, async/await patterns, and Jest testing.

Overview

# Node.js Best Practices Skill

Overview

This skill ensures clean, maintainable, production-ready Node.js code. It covers Express application structure, PostgreSQL database patterns, error handling, testing, and security.

Project Structure

Organize code into distinct layers:

```

server/

β”œβ”€β”€ index.js # App setup, middleware mounting

β”œβ”€β”€ routes/ # HTTP handling only, no business logic

β”œβ”€β”€ services/ # Business logic, database operations

β”œβ”€β”€ data/ # Static data, definitions, constants

β”œβ”€β”€ db/ # Database connection, migrations

└── auth/ # Authentication middleware

```

Routes handle HTTP concerns (parsing requests, sending responses).

Services contain business logic and database operations.

Data modules export static definitions and pure functions.

Core Principles

1. Separation of Concerns

Routes should delegate to services, not contain business logic:

```javascript

// GOOD: Route delegates to service

router.post('/:gameId/action', async (req, res) => {

try {

const result = await gameService.processAction(

req.params.gameId, req.session.userId, req.body

);

res.json(result);

} catch (error) {

res.status(400).json({ error: error.message });

}

});

```

2. Consistent Async/Await

Use async/await consistently. Never mix with callbacks:

```javascript

// GOOD: Clean async/await

async function getUser(userId) {

const result = await pool.query('SELECT * FROM users WHERE id = $1', [userId]);

return result.rows[0] || null;

}

```

3. Always Use Parameterized Queries

Never interpolate user input into SQL:

```javascript

// GOOD: Parameterized (safe)

await pool.query('SELECT * FROM users WHERE id = $1', [userId]);

// BAD: SQL injection vulnerability

await pool.query(SELECT * FROM users WHERE id = ${userId});

```

4. Proper Error Handling

Always handle errors - never swallow them:

```javascript

router.post('/:id/action', async (req, res) => {

try {

const result = await processAction(req.params.id, req.body);

res.json({ success: true, ...result });

} catch (error) {

console.error('Action failed:', error);

res.status(400).json({ error: error.message });

}

});

```

Database Patterns

See [DATABASE.md](DATABASE.md) for complete database patterns including:

  • Connection pooling configuration
  • Transaction handling with proper rollback
  • Row locking with FOR UPDATE
  • N+1 query prevention

Quick Reference

```javascript

// Connection pool (singleton)

const pool = new Pool({

connectionString: process.env.DATABASE_URL,

max: 20,

idleTimeoutMillis: 30000

});

// Transaction pattern

const client = await pool.connect();

try {

await client.query('BEGIN');

// ... operations ...

await client.query('COMMIT');

} catch (error) {

await client.query('ROLLBACK');

throw error;

} finally {

client.release(); // ALWAYS release

}

```

Testing Patterns

See [TESTING.md](TESTING.md) for complete testing patterns including:

  • Mocking the database pool
  • Testing transaction rollbacks
  • Route testing patterns

Quick Reference

```javascript

// Mock database at top of test file

jest.mock('../../server/db', () => ({

pool: { query: jest.fn(), connect: jest.fn(), on: jest.fn() }

}));

// Reset mocks between tests

beforeEach(() => {

jest.clearAllMocks();

});

// Mock transaction client

const mockClient = { query: jest.fn(), release: jest.fn() };

pool.connect.mockResolvedValue(mockClient);

```

Express Patterns

Middleware Order

```javascript

app.set('trust proxy', 1); // 1. Proxy settings

app.use(express.json()); // 2. Body parsing

app.use(sessionMiddleware); // 3. Session

app.use(express.static('public')); // 4. Static files

app.use('/api', routes); // 5. Routes

app.use(errorHandler); // 6. Error handler (last)

```

Authentication Middleware

```javascript

function requireAuth(req, res, next) {

if (!req.session?.userId) {

return res.status(401).json({ error: 'Not authenticated' });

}

next();

}

router.use(requireAuth); // Apply to all routes in file

```

Input Validation

Validate early in route handlers:

```javascript

router.post('/:gameId/action', async (req, res) => {

const { actionType } = req.body;

if (!actionType) {

return res.status(400).json({ error: 'Action type is required' });

}

// Proceed with validated input...

});

```

Security Essentials

Environment Variables

```javascript

// GOOD: From environment

const pool = new Pool({ connectionString: process.env.DATABASE_URL });

// BAD: Hardcoded credentials

const pool = new Pool({ connectionString: 'postgres://user:pass@host/db' });

```

Password Hashing

```javascript

const bcrypt = require('bcrypt');

const SALT_ROUNDS = 10;

await bcrypt.hash(password, SALT_ROUNDS); // Hash

await bcrypt.compare(password, hash); // Verify

```

Session Configuration

```javascript

app.use(session({

secret: process.env.SESSION_SECRET,

cookie: {

secure: process.env.NODE_ENV === 'production',

httpOnly: true,

maxAge: 24 60 60 * 1000

}

}));

```

Performance Tips

Parallel Operations

Use Promise.all for independent operations:

```javascript

const [game, players, state] = await Promise.all([

getGameById(gameId),

getGamePlayers(gameId),

getGameState(gameId)

]);

```

Health Checks

Include database status:

```javascript

app.get('/health', async (req, res) => {

const dbHealthy = await db.healthCheck();

res.status(dbHealthy ? 200 : 503).json({

status: dbHealthy ? 'healthy' : 'degraded',

database: dbHealthy ? 'connected' : 'disconnected'

});

});

```

When This Skill Activates

Use this skill when:

  • Writing Express routes or middleware
  • Creating service layer functions
  • Working with PostgreSQL queries
  • Implementing database transactions
  • Writing Jest tests for Node.js code
  • Handling errors and edge cases
  • Setting up authentication or sessions