JSDoc vs Python Docstrings — How to Document Functions Properly

Six months from now, someone is going to open a function you wrote and ask "what does this even do, and what am I supposed to pass into it?" That someone is often you. Good inline documentation — JSDoc in JavaScript, docstrings in Python — answers that question before it gets asked, and it powers IDE autocomplete along the way. This guide compares JSDoc and Python docstring conventions side by side, with worked examples for each, and gives you practical rules for writing documentation that people actually read.

Why Documenting Functions Matters

It is tempting to think of docstrings and JSDoc comments as busywork, but they do three concrete things that plain code alone does not:

  • IDE autocomplete and IntelliSense — editors like VS Code and PyCharm read JSDoc and docstrings to show parameter hints, types, and return values as you type, even without a full type-checking setup
  • Faster onboarding — a new teammate (or your future self) can understand what a function expects and returns without reading the entire implementation
  • Avoiding the "what does this even do" moment — a one-line summary answers the question immediately instead of forcing someone to trace through logic to reverse-engineer intent

Both JSDoc and Python docstrings solve the same underlying problem — describing a function's contract in a structured, tool-readable way — but the syntax and placement differ between the two languages.

JSDoc Syntax: /** ... */, @param, @returns, @throws

JSDoc comments are written as a block comment starting with /** (two asterisks), placed directly above the function they describe. Editors and documentation generators parse the tags inside.

/**
 * Calculates the total price of an order after tax and discount.
 *
 * @param {number} subtotal - The order subtotal before tax or discount.
 * @param {number} taxRate - Tax rate as a decimal, e.g. 0.18 for 18%.
 * @param {number} [discount=0] - Optional flat discount to subtract first.
 * @returns {number} The final total, rounded to 2 decimal places.
 * @throws {Error} If subtotal or taxRate is negative.
 */
function calculateTotal(subtotal, taxRate, discount = 0) {
  if (subtotal < 0 || taxRate < 0) {
    throw new Error('subtotal and taxRate must be non-negative');
  }
  const discounted = subtotal - discount;
  const total = discounted + discounted * taxRate;
  return Math.round(total * 100) / 100;
}

The core tags you will use in almost every JSDoc block:

  • @param {type} name - description — one per parameter; square brackets around the name mark it optional, e.g. [discount=0]
  • @returns {type} description — what the function sends back
  • @throws {type} description — what errors the function can raise and under what condition

Because the type is written in curly braces before the name, editors can validate calls against the documented types even in plain JavaScript files, without needing TypeScript.

Python Docstring Conventions: Google, NumPy, and reST

A Python docstring is a string literal — usually triple-quoted — placed as the very first statement inside a function, class, or module. Unlike JSDoc, it lives inside the function body and is accessible at runtime through function.__doc__. There are three common styles:

  • Google style — uses labeled sections like Args: and Returns:, indented under the label. Compact and easy to read as plain text.
  • NumPy style — uses underlined section headers and a column layout for parameters. More verbose, but handles long parameter lists clearly — common in scientific/data libraries.
  • reST (reStructuredText) style — uses :param name: and :returns: field syntax. Native to Sphinx, the documentation tool used for the official Python docs.

Google style is the most widely recommended default for general application code, so here it is as the primary worked example:

def calculate_total(subtotal, tax_rate, discount=0):
    """Calculate the total price of an order after tax and discount.

    Args:
        subtotal (float): The order subtotal before tax or discount.
        tax_rate (float): Tax rate as a decimal, e.g. 0.18 for 18%.
        discount (float, optional): Flat discount to subtract first.
            Defaults to 0.

    Returns:
        float: The final total, rounded to 2 decimal places.

    Raises:
        ValueError: If subtotal or tax_rate is negative.
    """
    if subtotal < 0 or tax_rate < 0:
        raise ValueError("subtotal and tax_rate must be non-negative")
    discounted = subtotal - discount
    total = discounted + discounted * tax_rate
    return round(total, 2)

Notice the structural parallel to the JSDoc example: a one-line summary, then a blank line, then labeled sections for arguments, return value, and exceptions. The same information, just placed inside the function body as a string instead of above it as a comment.

JSDoc vs Docstrings: Key Differences at a Glance

                JSDoc                       Python Docstring
--------------  --------------------------  ---------------------------
Placement       Comment block above the     String literal as first
                function                    statement inside function
Syntax          /** @tag {type} name */     Triple-quoted string with
                                             labeled sections
Runtime access  Not accessible at runtime   Accessible via __doc__
Type info       In curly braces per tag     In parentheses per arg
                                             (or via type hints instead)
Common styles   One dominant convention     Google, NumPy, or reST

Writing a Good One-Line Summary vs When to Add More Detail

Every function deserves a one-line summary. Not every function needs a full Args/Returns breakdown. Use this rule of thumb:

  • Always write one line that states what the function does in plain language, starting with a verb: "Calculates...", "Fetches...", "Validates..."
  • Add parameter and return docs when the function takes more than one argument, when a parameter's meaning is not obvious from its name, or when the return value has a shape someone would need to look up otherwise
  • Skip the full breakdown for small, self-explanatory helpers where the signature already tells the whole story — def is_even(n): """Return True if n is even.""" does not need an Args/Returns section
  • Document exceptions whenever a function can raise something a caller would reasonably need to catch, not just any internal assertion

The goal is a summary that lets a reader decide whether they need to keep reading. If the one-liner alone answers "what does this do and what do I pass in," you are done — padding it out with sections that repeat the function signature just adds noise.

Frequently Asked Questions

What is the difference between JSDoc and Python docstrings?

JSDoc is a comment block above a JavaScript function using tags like @param and @returns. Python docstrings are string literals inside the function body, commonly written in Google, NumPy, or reST style.

Is there a free tool to generate JSDoc or Python docstrings?

Yes. The Dev Brains AI Docstring Generator turns a pasted function signature into a JSDoc or Python docstring scaffold instantly, for free.

Which Python docstring style should I use, Google or NumPy?

Google style is recommended for most general-purpose code because it is compact and readable. NumPy style suits scientific or data-heavy codebases with long parameter lists.

Try the Free Docstring Generator

Paste a function signature and get a JSDoc or Python docstring scaffold instantly. No signup, no cost.

Related articles