Prompt Engineering Codex · CH 24

Chapter 24: Advanced Code Generation — Prompting for Production-Ready Code

⏱️ 4 min read·Updated Jul 2026

The Demo-to-Production Gap

AI-generated code that works in a demo often fails in production for predictable reasons:

  • Missing error handling (happy path only)
  • No input validation
  • Security vulnerabilities (SQL injection, missing auth, secret exposure)
  • No consideration for edge cases or concurrent access
  • No logging or observability
  • Hard-coded values that should be configuration
The gap between demo code and production code is not about correctness — it is about defensive programming, security, observability, and resilience. This chapter shows you how to get production-ready code from AI by asking for it explicitly.

---

The Production Code Prompt Framework

The key insight: AI generates code at the quality level implied by the prompt. A prompt that does not mention error handling gets code without error handling. A prompt that explicitly requires production standards gets production-quality code.

The Production Code System Prompt

code
You write production-quality code by default. This means:

MANDATORY FOR ALL CODE:
- Every async operation wrapped in try/catch with appropriate error handling
- All user inputs validated before use (type, range, required fields)
- Meaningful error messages that distinguish different failure modes
- Structured logging for operations that matter
- Constants for magic values (no raw strings or numbers that will change)

SECURITY DEFAULTS:
- Parameterised queries for all database operations
- Authentication check before any sensitive operation
- Authorisation check (not just authentication -- user X should not access user Y's data)
- No secrets, credentials, or sensitive data in logs or responses
- Rate limiting recommendation on any public endpoint

NEVER:
- Silent catch blocks (catch(err) {} with no action)
- Broad exception swallowing (catch(err) { return null } without logging)
- Unchecked type assumptions (assuming req.body.id is a number without validation)

---

Error Handling Patterns

The most common production failure in AI-generated code is inadequate error handling.

The pattern AI typically generates:

javascript
async function getUser(userId) {
  const user = await db.query(`SELECT * FROM users WHERE id = ${userId}`);
  return user[0];
}

Problems: SQL injection, no error handling, silent undefined return.

Prompt for production-quality error handling:

code
Write a getUser function. Requirements:
- Parameterised query (never interpolate userId directly)
- Explicit handling for: user not found (null/404 scenario), database connection error, invalid userId format
- Typed return: User | null (with a custom UserNotFoundError vs DatabaseError distinction)
- Logging for errors at appropriate severity levels
- Input validation: userId must be a non-empty string matching UUID format

Production output:

typescript
class UserNotFoundError extends Error {
  constructor(userId) {
    super('User not found: ' + userId);
    this.name = 'UserNotFoundError';
  }
}

const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;

async function getUser(userId) {
  if (!userId || !UUID_REGEX.test(userId)) {
    throw new Error('Invalid userId format: ' + userId);
  }
  
  try {
    const result = await db.query(
      'SELECT id, email, created_at FROM users WHERE id = $1',
      [userId] // Parameterised -- never interpolated
    );
    
    if (result.rows.length === 0) {
      return null; // User not found -- not an error
    }
    
    return result.rows[0];
  } catch (err) {
    logger.error('Database error in getUser', { userId, error: err.message });
    throw new Error('Failed to retrieve user due to database error');
  }
}

---

The Security Review Prompt

After generating any API route or data access function, always run this review prompt:

code
Security review this code. For each issue found, classify severity and provide the exact fix.

Check specifically for:
1. Authentication: Is the user's identity verified before any data access?
2. Authorisation: Can user A access user B's data through this code?
3. Injection: Is any user-controlled data interpolated into queries, commands, or evaluated code?
4. Secrets: Are any API keys, passwords, or tokens visible in the code or return values?
5. Rate limiting: Could this endpoint be abused at scale?
6. IDOR: Do object IDs in URLs/params get validated against the authenticated user's ownership?
7. Input validation: Are all inputs validated for type, length, format, and range before use?

Code to review:
[paste code]

---

Testing Integration From the Start

The most efficient time to write tests is immediately after writing the code, while context is fresh.

code
I have just written this function:
[paste function]

Now write Jest tests for it. Cover:
1. Happy path with valid inputs -- all return paths
2. Each validation failure (invalid types, missing required fields, out-of-range values)
3. Error handling paths -- what happens when the database throws?
4. Edge cases specific to this function's logic

For each test:
- Descriptive test name that explains what is being tested
- Clear arrange/act/assert structure
- Mock external dependencies (database, external APIs) -- do not make real calls

---

The Observability Prompt

Production code needs to be debuggable when things go wrong.

code
Add structured logging to this function. Log:
- Function entry with key parameters (redact any PII or secrets)
- Each major decision point
- All errors with full context
- Performance metrics for operations over 100ms

Use our logger utility: logger.info(), logger.warn(), logger.error()
Each log call should include: { event: 'descriptive_name', ...relevant_context }

---

Configuration vs. Hard-Coding

code
Add this rule to every code generation prompt:
"Replace all hard-coded values (URLs, timeouts, limits, feature flags, magic numbers) with named constants defined at the top of the file. Where a value should be configurable per environment, use process.env.VARIABLE_NAME with a documented default."

Finished reading this chapter?

Mark it completed to update your AI Builder skill profile score on your dashboard.

📋

Download Printable Chapter Checklist

Get a print-friendly, formatted checklist of workspace actions to apply this chapter offline.