DESIGN.md Best Practices with Example


DESIGN.md Best Practices with Example

One question keeps popping up in our comments whenever developers share repository setups: “Why do I need a DESIGN.md if I already wrote a README.md?”

Other readers ask if maintaining an internal design document is overkill for a solo freelancing gig or a small client portal. Most developers avoid writing a design document because it feels like corporate paperwork. When they do write one, they build a thirty-page document, close it, and never update it again as code evolves.

The Reality: A practical DESIGN.md is not an academic paper or a bureaucratic chore. It is a decision log. A good design document explains why you built a system a certain way, what alternatives you rejected, and what trade-offs you chose. A short, living, decision-focused Markdown file beats a massive, outdated technical document every single time.


Diagram showing how DESIGN.md bridges architectural decisions, database schemas, and AI coding assistants.

Diagram showing how DESIGN.md bridges architectural decisions, database schemas, and AI coding assistants.

What’s the difference between DESIGN.md and README.md?

Developers often confuse these two files because both live in the project root. Their audiences and objectives are completely different.

  • README.md is for users and consumers. It answers: What does this project do, and how do I run or install it? It contains quick-start guides, system requirements, environment variable samples, and license notes.
  • DESIGN.md is for maintainers and architects. It answers: How is this system assembled under the hood, and why was it designed this way? It explains database schemas, folder conventions, data flow, and trade-offs.
project-root/
│
├── README.md        # Public-facing: Setup instructions, run scripts, requirements
├── DESIGN.md        # Internal-facing: Architectural rationale, DB schemas, trade-offs
├── src/
└── docs/

If a client asks how to spin up the local server, point them to the README.md. If a client or new collaborator asks why you chose session cookies over JSON Web Tokens for a dashboard, your DESIGN.md holds the answer.


Is DESIGN.md overkill for a small project like a CRM or portal?

No, especially if you are working alone.

When you build a small web application—like a custom client CRM or an internal records portal—architectural choices feel obvious in the moment. Six months later, you revisit that code to patch a bug or hand it over to another developer, and your own choices look like a riddle. Why did you isolate database queries in a separate class? Why did you pick raw PDO statements instead of a heavy ORM?

Writing down three or four major decisions in a compact file saves hours of code archaeology down the road. You do not need twenty pages. Two well-structured pages in Markdown are plenty.


Is it useful for solo developers, or only for teams?

Solo developers and freelancers benefit from a DESIGN.md just as much as large engineering teams.

When you work alone, you don't have teammates reviewing your pull requests or challenging your design choices. Your future self is your only teammate. When a freelance client requests a new feature a year after deployment, your design document reminds you of server constraints, rejected libraries, and table relationships in five minutes.

For teams, it acts as a lightweight Architecture Decision Record (ADR) that keeps code reviews focused on code quality rather than re-arguing established architecture.


What sections should a DESIGN.md have?

A reliable design document markdown template keeps cognitive load low. Use these core sections:

  1. Overview & Problem Statement: What problem does this system solve?
  2. Goals and Non-Goals: What must the system do, and what is explicitly out of scope?
  3. Architecture & Directory Layout: How do files and modules communicate?
  4. Data Model & Schema: Core database tables and relationships.
  5. Key Design Decisions: The rationale behind major technical choices.
  6. Alternatives Considered: Why specific libraries, patterns, or tools were turned down.
  7. Trade-offs & Constraints: Hosting limitations, performance compromises, or security boundaries.
  8. Changelog / Decision History: Brief dated notes on architectural pivots.

Real-world DESIGN.md template and example

Here is a practical, production-ready DESIGN.md for a custom PHP and MySQL management portal deployed on shared cPanel hosting.

# System Design Document: Client Service Management Portal

*Last Updated: 2026-09-28*  
*Status: Approved / Active*

## 1. Overview
A lightweight administrative portal designed to manage internal service tickets, client records, and monthly billing summaries. Built for fast response times on budget infrastructure.

## 2. Goals and Non-Goals
* **Goals:** Fast page generation (< 150ms), simple deployment without complex build pipelines, secure relational data management.
* **Non-Goals:** Real-time websockets (long polling or manual refresh is acceptable), multi-tenant SaaS capabilities.

## 3. Architecture & Project Structure
The application follows a clean Single Responsibility structure without the overhead of a full-stack framework:

src/
├── Config/         # Environment configurations & database connection
├── Controllers/    # Request handling & input sanitization
├── Models/         # Database queries using PDO
├── Views/          # Pure PHP/HTML templates
└── public/         # Public webroot (index.php, CSS, assets)

## 4. Key Design Decisions

### Decision 1: Native PHP with PDO instead of Laravel
* **Context:** The application is hosted on low-resource shared cPanel hosting without SSH root access or Composer daemon control.
* **Decision:** Use vanilla PHP 8.x with native PDO prepared statements.
* **Why:** Minimizes memory consumption per request and removes deployment dependencies.
* **Alternatives Considered:** Laravel was rejected because its memory footprint and reliance on background workers exceeded the hosting tier's 128MB RAM process cap.

### Decision 2: Server-Rendered HTML over a Decoupled Single-Page App (SPA)
* **Context:** The portal is used internally on office desktops with stable connections.
* **Decision:** Render HTML server-side with standard forms and lightweight JavaScript for progressive enhancement.
* **Why:** Avoids API versioning, CORS configuration, and bundle management issues.

## 5. Data Model & Schema Decisions
[users] 1 --- * [service_tickets] * --- 1 [clients]

* Passwords hashed using PASSWORD_ARGON2ID.
* Strict foreign keys enabled on all relational tables with ON DELETE RESTRICT to prevent accidental orphaned financial records.

## 6. Security Boundaries
* All SQL queries must strictly use parameterized bindings to prevent injection vulnerabilities.
* Sessions store authenticated state using HttpOnly, Secure, and SameSite=Strict cookie flags.
* User roles are strictly validated at the controller level before running any model queries.

## 7. Trade-offs and Known Limitations
* **Shared Server File Uploads:** Uploaded invoices are stored outside public webroot with PHP streaming access, which consumes slightly more PHP worker time than direct cloud object storage (e.g., S3).
* **Search:** Uses SQL LIKE queries with table indexing rather than dedicated search engines (like Elasticsearch) to keep costs low.

## 8. Decision Changelog
* **2026-09-15:** Switched session store from database records back to native filesystem sessions to eliminate database locks during bulk reporting exports.

How do I add diagrams (ER diagrams, flowcharts) in Markdown?

You do not need to export PNG images from external graphic tools every time you tweak a database column. Use Mermaid.js, which renders natively inside GitHub, GitLab, and most modern Markdown editors.

To build an Entity-Relationship (ER) diagram, enclose a mermaid block inside standard triple backticks:

```mermaid
erDiagram
    CLIENT ||--o{ TICKET : places
    CLIENT {
        int id PK
        string company_name
        string email
    }
    TICKET {
        int id PK
        int client_id FK
        string issue_title
        string status
    }
```

For interactive prototyping or complex user journey flowcharts, you can also design diagrams in draw.io and embed the exported SVG directly into your project repository. To preview your work locally as you write, use the built-in Markdown preview in VS Code or dedicated extensions.


DESIGN.md best practices to follow

  • Document decisions, not just descriptions: Describing how a function works belongs in code comments or docstrings. DESIGN.md answers why the function exists in that pattern.
  • Keep it to 2 to 3 pages: If your document looks like a book, nobody will read it or update it. Keep it punchy.
  • Date every major choice: Technologies change. What made sense two years ago might look obsolete today. Adding a timestamp clarifies what constraints existed when the decision was made.
  • Review during pull requests: Whenever a pull request introduces a new architectural pattern, make updating DESIGN.md a mandatory requirement for merging.
  • Link it directly from README.md: Make your design file easy to find by placing a direct link in the development or contributing section of your README.md.

Why DESIGN.md matters for AI coding assistants

AI developer tools—including Cursor, GitHub Copilot, and Claude—are standard parts of modern coding workflows. While these assistants excel at writing boilerplate code, their accuracy depends entirely on context.

When you feed an AI coding assistant an empty prompt or a single script, it guesses your architecture. It might suggest an ORM you don't use, generate code targeting an incompatible runtime, or introduce libraries that clash with your server constraints.

A concise DESIGN.md acts as a perfect system context prompt. By pointing your assistant to your design document (such as referencing @DESIGN.md in Cursor or pasting the design rules into your system prompt), the model instantly knows:

  • Your exact database query conventions (such as native PDO with prepared statements).
  • Directory layout and separation of concerns.
  • Architectural constraints (such as avoiding external heavy packages for shared hosting).

Instead of producing generic code that you have to rewrite, the assistant generates code that fits your exact project architecture on the first try.


Common mistakes that ruin design docs

  • Copying massive enterprise templates: Downloading an enterprise design framework with fifty sub-sections for a three-page app results in empty headers and abandoned files.
  • Treating it as a one-time chore: If the document never changes when the database schema changes, it turns into misleading technical debt.
  • Mixing installation steps with design rationale: Keep server setup commands inside README.md. Keep design tradeoffs inside DESIGN.md.

A well-kept design file keeps your code maintainable and makes project handoffs painless. If you are structuring new web projects, explore our guide on how to prevent SQL injection in PHP using PDO to keep your database layer secure, or check out our breakdown of the best AI coding assistants to streamline your development process[cite: 1].

Post a Comment

Previous Post Next Post