Skip to main content
The Learn section at /learn provides tutorials and guides organized into topic categories. Each category is a directory under apps/site/pages/en/learn/, and each article is a Markdown file inside that directory.

Existing categories

The following nine categories already exist:

getting-started

Introduction to Node.js, the V8 engine, npm, and first steps.

asynchronous-work

Event loop, callbacks, promises, async/await, and timers.

command-line

Running scripts, reading environment variables, CLI argument parsing.

http

HTTP servers, making requests, working with fetch.

manipulating-files

Reading and writing files, working with directories and paths.

modules

CommonJS, ES Modules, package.json, and the module system.

typescript

Using TypeScript with Node.js: setup, transpilation, type checking.

diagnostics

Debugging, profiling, memory analysis, and tracing.

test-runner

The built-in node:test module and writing tests.

Directory structure

apps/site/pages/en/learn/
├── getting-started/
│   ├── introduction-to-nodejs.md
│   └── ...
├── asynchronous-work/
│   └── ...
└── <category-name>/
    └── <article-name>.md

Article frontmatter

Every Learn article uses the learn layout and lists its authors as GitHub usernames:
---
title: Introduction to Node.js
layout: learn
authors: flaviocopes, potch, MylesBorins, RomainLanz, mcollina
---

# Introduction to Node.js

Node.js is an open-source and cross-platform JavaScript runtime...
FieldRequiredDescription
titleYesThe article title shown in the page and sidebar
layoutYesMust be learn
authorsYesComma-separated list of GitHub usernames
descriptionNoOptional meta description for SEO
canonicalNoOriginal URL if the content is syndicated

Adding a new article

1

Create the article file

Create a new .md file under the appropriate category directory:
apps/site/pages/en/learn/getting-started/my-new-article.md
Use lowercase kebab-case for the filename. The filename becomes the URL path segment.
2

Add frontmatter and content

---
title: My New Article
layout: learn
authors: your-github-username
---

# My New Article

Content goes here...
3

Update navigation.json

Add your article to the sideNavigation.learn array in apps/site/navigation.json.Find the object for the relevant category and add an entry to its items map:
{
  "sideNavigation": {
    "learn": [
      {
        "label": "getting-started",
        "items": {
          "myNewArticle": {
            "link": "/learn/getting-started/my-new-article",
            "label": "components.navigation.learn.getting-started.my-new-article"
          }
        }
      }
    ]
  }
}
The label value is a translation key that maps to a human-readable string.
4

Add translation keys

Open packages/i18n/src/locales/en.json and add the translation key referenced in navigation.json:
{
  "components": {
    "navigation": {
      "learn": {
        "getting-started": {
          "my-new-article": "My New Article"
        }
      }
    }
  }
}
The key path must exactly match the dot-separated path in the label field of the navigation entry.
5

Preview and validate

Run pnpm dev and navigate to /learn/getting-started/my-new-article to confirm the article renders and appears in the sidebar.Run pnpm format to apply consistent formatting before opening a pull request.

Adding a new category

If your article doesn’t fit an existing category, you can create a new one:
  1. Create a new directory under apps/site/pages/en/learn/, for example apps/site/pages/en/learn/networking/.
  2. Add articles inside that directory.
  3. In navigation.json, add a new object to the sideNavigation.learn array with a label and items map.
  4. Add the corresponding translation keys in packages/i18n/src/locales/en.json.
Non-translated articles automatically fall back to English content with localized navigation. You do not need to provide translations for every locale before merging.

Code blocks in Learn articles

The site supports GitHub Flavored Markdown and renders consecutive code blocks as a tabbed interface. Use language identifiers on all fenced blocks:
```cjs
const http = require('node:http');
```

```mjs
import http from 'node:http';
```
You can also add an optional displayName to label the tab:
```cjs displayName="CommonJS"
const http = require('node:http');
```

```mjs displayName="ES Modules"
import http from 'node:http';
```

Build docs developers (and LLMs) love