Files
Danny White a31ca2bad0 fix(ui): make brand text readable across themes (#49871)
## What kind of change does this PR introduce?

Bug fix and design-system update. Resolves DEPR-316.

Follow-up rename (`text-brand` → `text-primary`) is in a dedicated PR
(https://github.com/supabase/supabase/pull/50564) stacked on this one.

## What is the current behavior?

`text-brand` resolves to the canonical bright brand green in places that
need readable text, which fails WCAG AA on light surfaces. A separate
`text-brand-display` token adds another green for large type.

## What is the new behavior?

- `text-brand` maps to accessible `--primary` (light mode darkened to
meet ~4.5:1 AA)
- `--hue` / `--primary-hue` aligned to 157.5
- `text-brand-display` removed; former display callsites use
`text-brand`
- Bright fills/borders stay on `brand-default`
- Design-system colour and typography docs updated

| Before | After |
| --- | --- |
| <img width="514" height="112" alt="CleanShot 2026-09-02 at 11 13
09@2x"
src="https://github.com/user-attachments/assets/4e0138a9-a32d-4e4c-a426-90736706e1e7"
/> | <img width="512" height="138" alt="CleanShot 2026-09-21 at 11 42
05@2x"
src="https://github.com/user-attachments/assets/164cc5b1-a0c5-4e93-95f1-80016641a114"
/> |
| <img width="864" height="266" alt="CleanShot 2026-09-02 at 11 13
53@2x"
src="https://github.com/user-attachments/assets/3c1ca53f-bf9e-431e-bc15-816b4a275b8e"
/> | <img width="882" height="248" alt="CleanShot 2026-09-21 at 11 41
37@2x"
src="https://github.com/user-attachments/assets/24828e7b-ed6b-44cb-b9dc-becc3398bdfc"
/> |
| <img width="782" height="692" alt="CleanShot 2026-09-02 at 11 16
30@2x"
src="https://github.com/user-attachments/assets/fc871977-77bc-47fb-9e0e-9284e0ecd5cc"
/> | <img width="730" height="690" alt="CleanShot 2026-09-21 at 11 42
52@2x"
src="https://github.com/user-attachments/assets/bf479515-d5f9-471e-b82d-f097c0f4b56c"
/> |
| <img width="480" height="306" alt="CleanShot 2026-09-02 at 11 18
53@2x"
src="https://github.com/user-attachments/assets/03f341f4-f02e-44f8-a2b2-8c31670d0427"
/> | <img width="470" height="300" alt="CleanShot 2026-09-21 at 11 43
19@2x"
src="https://github.com/user-attachments/assets/9df18217-d5e6-48b8-ba0b-579d2664b94b"
/> |
| <img width="960" height="300" alt="CleanShot 2026-09-02 at 11 32
04@2x"
src="https://github.com/user-attachments/assets/6b1d9373-7a71-4247-81ff-26441604b09d"
/> | <img width="980" height="306" alt="CleanShot 2026-09-21 at 11 44
13@2x"
src="https://github.com/user-attachments/assets/41ad4784-02ec-4b29-b860-32af9fa79aa8"
/> |
| <img width="924" height="214" alt="CleanShot 2026-09-02 at 11 34
44@2x"
src="https://github.com/user-attachments/assets/1de661fe-c7b6-499b-a94f-e4737436ec79"
/> | <img width="752" height="162" alt="CleanShot 2026-09-21 at 11 44
56@2x"
src="https://github.com/user-attachments/assets/1811890f-0660-4445-84e9-447720954fa1"
/> |

## To test

Test each callsite **in light mode** (dark mode is largely unchanged).

### WWW

-
[Homepage](https://zone-www-dot-com-git-dnywh-depr-316-brand-text-tokens-supabase.vercel.app/):
“Scale to millions” uses readable brand text (display token is gone)
-
[Careers](https://zone-www-dot-com-git-dnywh-depr-316-brand-text-tokens-supabase.vercel.app/careers):
small “Careers” eyebrow readable; green dividers stay bright
`brand-default`
-
[Contact](https://zone-www-dot-com-git-dnywh-depr-316-brand-text-tokens-supabase.vercel.app/contact-us):
email / policy links use readable brand text
-
[Regions](https://zone-www-dot-com-git-dnywh-depr-316-brand-text-tokens-supabase.vercel.app/regions):
“Ask about early access to BYOC” readable

### Docs

- [Docs
homepage](https://docs-git-dnywh-depr-316-brand-text-tokens-supabase.vercel.app/docs):
“DOCS” wordmark and resource links readable
- [Database
overview](https://docs-git-dnywh-depr-316-brand-text-tokens-supabase.vercel.app/docs/guides/database/overview):
nav / footer brand links readable
- [JavaScript
reference](https://docs-git-dnywh-depr-316-brand-text-tokens-supabase.vercel.app/docs/reference/javascript/introduction):
active sidebar treatment readable

### Design system

-
[Typography](https://design-system-git-dnywh-depr-316-brand-text-tokens-supabase.vercel.app/docs/typography):
documents `text-brand` only (no display)
- [Colour
usage](https://design-system-git-dnywh-depr-316-brand-text-tokens-supabase.vercel.app/docs/color-usage):
`text-brand` vs `bg-brand-default`
- [Design-system
homepage](https://design-system-git-dnywh-depr-316-brand-text-tokens-supabase.vercel.app/):
brand text examples across themes

### Studio

- [Auth
providers](https://studio-staging-git-dnywh-depr-316-brand-text-tokens-supabase.vercel.app/dashboard/project/_/auth/providers):
enabled provider badge text readable; status dot stays bright
- [Database
policies](https://studio-staging-git-dnywh-depr-316-brand-text-tokens-supabase.vercel.app/dashboard/project/_/database/policies?new=true):
template hover text more legible
- [Database
connections](https://studio-staging-git-dnywh-depr-316-brand-text-tokens-supabase.vercel.app/dashboard/project/_/observability/connections):
“Live” status readable; animated dot stays bright green

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
2026-09-22 10:07:28 +10:00

31 KiB

Contributing to Supabase docs

Our docs help developers to get started and keep succeeding with Supabase. We welcome contributions from everyone.

If you'd like to contribute, see our list of recommended issues. We also welcome you to open a PR or a new issue with your question.

Here are some general guidelines on writing docs for Supabase. If you write with an AI coding agent, these skills apply the guidelines for you:

  • /write-the-docs to draft a new page.
  • /edit-the-docs to revise an existing page.
  • /test-the-docs to run the snippets you wrote.
  • /review-the-docs to check your work before you open a pull request.

See AI agent skills for docs authoring for the full set, including the skills that help you frame a page and place it in the information architecture.

General principles

Write helpful, concise, and understandable documentation. We have a global audience whose members speak different native languages.

To make docs as clear as possible:

  • Write for the user. Think about what task they want to complete by reading your doc. Tell them what, and only what, they need to know.
  • Write like you talk. Conversational English is easier for a global audience to understand and localize. Many readers who use English as an additional language learn conversational rather than academic English. Use words and sentences that sound natural when speaking. Cut unnecessary words. Read your writing out loud to help you choose the clearest and simplest phrases.
  • Prefer short, direct sentences. Express one relationship at a time, and avoid unnecessary compound structures. This makes each sentence easier to understand, localize, and interpret consistently.
  • Cover one topic in each paragraph. Start a new paragraph whenever you change the topic, or when you move between information types. Don't worry about paragraphs being too short.
  • Avoid using idioms and colloquialisms, such as piece of cake. These phrases are often specific to a region or culture.
  • Refer to the reader as you. Don't use we to refer to the reader. Use we only to refer to the Supabase team.

Information types

Separating kinds of information helps a reader reach what they came for and retain it afterward. Someone scanning for a command shouldn't have to read past a definition to find it, and someone reading to understand shouldn't have to step around instructions. Blended prose slows down both, along with an AI agent trying to answer a question from the page, and little of it sticks.

The Information Mapping method names six kinds, each answering a different reader question:

Type Answers Present with
Procedure How do I do it? Numbered steps, or an if/then table
Process What is happening? How does it work? A stage-by-stage description, or a when/then table
Structure What are its parts? A part and description table, or a labeled diagram
Principle What should I do or not do? Text, a list, or an admonition
Concept What is it? Text, a list, or a diagram
Fact What are the facts? Text, a list, or a table

Recommendations

  • Separate a procedure, a process, a structure, or a concept: Each usually reads better in its own section. Procedure and process get blended most often, because both answer a question about how, and a reader following steps can't act on the process sentences.
  • Keep context out of the action path: A concept or a process tends to work better before the procedure or after it than threaded through the steps.
  • Let a principle or a fact ride along: Either is often a single sentence, so it can sit in the section it qualifies rather than getting one of its own. A fact about timing fits in the step it describes, and a principle can close the concept paragraph that motivates it.
  • Look again at a long paragraph: Past three or four sentences, it has often picked up a second kind of information. Label each sentence and see where the labels change.
  • Leave connective prose alone: An introduction, a transition, an outcome, and a navigation outline describe the page rather than the product, so none of this applies to them.

Examples

Not recommended, because one paragraph blends a concept, a procedure, and a structure:

Row Level Security is a Postgres feature that restricts which rows a user can read
or write, and it's the main way to secure a table that several users share. Enable
it by running `alter table profiles enable row level security`, which takes effect
immediately. Be careful, because a table with Row Level Security enabled and no
policy returns no rows to every client, so write a policy before you deploy. The
`using` clause of a policy accepts any expression that returns a boolean.

Recommended, with each type in the presentation that suits it:

## Row Level Security

Row Level Security restricts which rows a user can read or write. It's the main way
to secure a table that several users share.

### Enable Row Level Security

1. Run `alter table profiles enable row level security`. The change takes effect
   immediately.
2. Write a policy that grants the access your app needs.

<Admonition type="caution">

A table with Row Level Security enabled and no policy returns no rows to every
client. Write a policy before you deploy.

</Admonition>

### Policy reference

The `using` clause accepts any expression that returns a boolean.

AI agent skills for docs authoring

Use these skills for every docs change you make with an AI coding agent: /write-the-docs to draft, and /edit-the-docs to revise an existing page. They apply this guide and the word list, so you don't have to hold either one in your head.

Skills work in any agent that reads .agents/skills/, such as Claude Code, Cursor, or Codex. Invoke a skill with /name, for example /write-the-docs. The canonical files live in .agents/skills/ (.claude/skills is a symlink).

Write the docs skills

Use the Write the docs checklist when product intent and code drive the change: net-new pages, or revising/restructuring existing ones.

Skill Checklist stage Use for
pm-the-docs Frame / shape Audience, stage, why, content type, cross-repo scope (universe when you have Supabase org access, else OSS path)
ask-the-docs Frame / shape Docs-app architecture, IA placement, where content lives
write-the-docs Draft Draft or revise content grounded in intent and code
test-the-docs Draft / self-review Run snippets in a Docker-isolated stack; verification report
review-the-docs Self-review / PR review Checking a draft; verify a PR

Edit existing pages

Use edit-the-docs for style, structure, or brevity on an existing page when you are not changing the product story.

Document types

Supabase docs contain four types of documents. Before you start writing, think about what type of doc you need.

Explainers

Explainers help the reader to learn a topic. They are conceptual and mostly prose-based. They can include:

  • A description of what a feature is
  • Some reasons why it is useful
  • Some examples of when to use it
  • A high-level explanation of how it works

Explainers don't include:

  • Instructions on how to use it

Tutorials

Tutorials are goal-oriented. They help a reader to finish a large, complex goal, such as setting up a web app that uses multiple Supabase features.

Tutorials mix prose explanations with procedures. Procedures are lists of steps for the reader to follow. Tutorials provide context for why certain instructions are given.

For inspiration, see an example of a tutorial.

Guides

Guides are also goal-oriented, but they focus on shorter, more targeted tasks. For example, a guide might explain how to set up user login for an app.

Guides contain mostly procedures: concise steps that readers can follow in sequence.

A value statement makes a good opener: name what the reader can do, and why it matters to them. That's what tells a reader or an agent whether the page matches their goal.

Keep procedures focused on what the reader must do. Move substantial background or conceptual explanations into a separate section or an explainer. Cross-reference the authoritative explanation instead of repeating it in the procedure. This keeps the action path scannable, gives readers optional depth, and maintains one source of truth.

  • Recommended: Restrict access to a shared table with Row Level Security. To learn how a policy is evaluated, see [Row Level Security](...).
  • Not recommended: Begin with several paragraphs about how Row Level Security works before stating what the reader can do.

Mixed information types: Information types apply at the page level too. Group sections of related types together, and try to keep the procedure group unbroken so context doesn't interrupt the action path. A section serving two types can be split, with a cross-reference between the halves.

Classify a section by what the reader is doing in it, not by what it's about. On a page about tables every section is about tables, so subject matter tells you nothing. A reader opens a section on schemas to understand something, so it's context.

One order that works: a short concept opener, then procedures, then concept and process, then structure and fact.

## What is a table?                    <- concept opener
## Creating and managing tables        <- procedures
### Creating tables
### Securing your tables
### Loading data
## How tables are organized            <- concept and process
### Primary keys
### Relationships between tables
### Schemas
## Reference                           <- structure and fact
### Data types

Navigation: Begin a long guide with a short outline of its major section groups. Link to each group and state when a reader should use it. Don't add section navigation to a short guide when the headings are already easy to scan.

For example, an introduction to a long guide that mixes information types:

Connect your app to Postgres through a connection pooler, a direct connection, or a
Supabase client library.

- [Choose a connection method](#choose-a-connection-method) compares the options and
  their trade-offs. Start here if you aren't sure which one fits your app.
- [Connect your app](#connect-your-app) has the steps for each method.
- [Connection parameters](#connection-parameters) lists every parameter and its
  default.

Each link says what the reader gets from that group, so someone who already knows which method they want goes straight to the procedures.

Cross-references and glue: Connect contextual sections to their corresponding procedures when the relationship helps readers navigate. Add a brief introduction to each section group, a transition when the information type changes, and an outcome after a procedure. Add links selectively rather than linking every adjacent section.

  • Group introduction: The following sections cover each connection method in turn. Every method needs your project reference, which you find on the project settings page.
  • Transition where the type changes: Those are the mechanics of opening a connection. To understand why a pooled connection behaves differently under load, see [Connection pooling](...).
  • Outcome after a procedure: Your app now connects through the pooler. Queries that used to fail at the connection limit queue instead.

For inspiration, see an example of a guide.

Reference

References are factual and to the point. Think of dictionary entries.

References include:

  • Function parameters
  • Return types
  • Code samples
  • Warnings about critical errors, such as missteps that can cause data loss

References don't include:

  • Explanations of the context for a feature
  • Examples of use cases
  • Multi-step instructions

Repo organization

Most docs pages are contained in the apps/docs/content directory. Some docs sections are federated from other repositories, for example pg_graphql. Reference docs are generated from spec files in the spec directory.

You can usually identify a federated or reference doc because it uses a Next.js dynamic route. For example, it might use [[...slug]].tsx. Look for the spec file import or the repo definition to find the content location.

Example spec file import:

import specFile from '~/spec/transforms/analytics_v0_openapi_deparsed.json' with { type: 'json' }

Example repo definition:

const org = 'supabase'
const repo = 'pg_graphql'
const branch = 'master'
const docsDir = 'docs'
const externalSite = 'https://supabase.github.io/pg_graphql'

Check the sections for guide structure and reference structure to learn more about the file structures.

Guide structure

The Supabase docs use MDX. Guides are MDX documents that combine concise prose with structured procedures.

Adding a new guide requires:

  • YAML frontmatter
  • A navigation entry in a separate file

Frontmatter looks like this. title is mandatory. There are also optional properties that you can use to control the page display, including subtitle, tocVideo, and hideToc.

---
title: How to connect to Supabase
hideToc: true
---

The navigation is defined in NavigationMenu.constants.ts.

Add an entry with the name, url, and optional icon for your page.

Reference structure

Reference docs are produced from the reference specs and library source code. A common spec file contains shared function and endpoint definitions, and library-specific spec files contain further details.

Common spec file

Each type of library, such as a language SDK or CLI, has a common spec file. For example, see the spec file for the language SDKs. This file contains definitions for the common SDK functions:

  • id: Identifies the function
  • title: Provides the human-readable title
  • slug: Provides the URL slug
  • product: Identifies the Supabase product that owns the function. For example, database operations are owned by database, and Auth operations are owned by auth.
  • type: Uses function for a structured function definition or markdown for a prose explainer section

To add a new function, manually add an entry to this common file.

Specific spec file

Each library also has its own spec file containing library-specific details. For example, see the JavaScript SDK spec file.

The functions listed in this file match the ones defined in the common spec file.

Each function contains a description, code examples, and optional notes. The parameters are pulled from the source code via the $ref property, which references a function definition in the source code repo. These references are pulled down and transformed using commands in the spec Makefile. Unless you're a library maintainer, you don't need to worry about this.

If you're a library maintainer, follow these steps when updating function parameters or return values:

  1. Merge your changes into the library's master branch.
  2. Wait for the action to update the specification in the gh-pages branch.
  3. Run make from apps/docs/spec in the supabase/supabase repository.
  4. Verify the changes on your local documentation site.

Content reuse

If you copy the same content multiple times across different files, create a partial for content reuse instead. Partials are MDX files contained in apps/docs/content/_partials. They contain reusable snippets that can be inserted in multiple pages. For example, you can create a partial to define a common setup step for a group of tutorials.

To use a partial, import it into your MDX file. You can also set up a partial to automatically import by including it in the components within apps/docs/features/docs/MdxBase.shared.tsx.

Components and elements

Docs include normal Markdown elements such as lists and custom components such as admonitions, also known as callouts.

Here are some guidelines for using elements:

Admonitions

Admonitions draw reader attention to an important point or an aside. They highlight important information, but get less effective if they're overused.

Use an admonition when a reader might otherwise miss information that affects the outcome of their task, or when you want to separate helpful but optional guidance from the main flow. Don't use an admonition for information that belongs in the main explanation or procedure.

Use admonitions sparingly. Don't stack them on top of each other or use them as decoration.

Begin every admonition with its impact and purpose: the "so what." Use the first sentence to tell the reader why the information matters, such as what could happen, what changes, or what benefit they gain. Add background or instructions after the impact is clear.

For example:

  • Recommended: Deleting this project permanently removes its database and backups. Export any data that you want to keep before you continue.
  • Not recommended: Before you continue, there are a few things that you should know about project deletion.

Choose the appropriate type for your admonition:

  • danger: Warn about actions or conditions that could cause data loss, expose sensitive data, or create another severe and difficult-to-reverse outcome. State the consequence first, and then explain how to avoid it.
  • deprecation: Identify a deprecated feature or behavior. State how the change affects the reader, and then provide the supported alternative or migration path.
  • caution: Warn about behavior that could cause bugs, failed operations, unexpected results, or serious inconvenience but doesn't rise to the severity of danger.
  • note: Highlight an important prerequisite, constraint, clarification, or optional shortcut that doesn't represent a risk. If the information is essential to completing a step, include it in the procedure instead.

Structure an admonition with these props and content:

  • title (optional): Add a short callout title. Don't put Markdown or HTML headings inside an admonition. If the content needs a heading to structure the page, move the heading and its section outside the admonition.
  • children: Add rich body content such as paragraphs, lists, links, and code.
  • actions (optional): Add standalone calls to action so they remain separate from the body content. Keep contextual links and interactive examples in the body when they are part of the explanation.
<Admonition
  type="note"
  title="Optional title"
  actions={<Button>Continue</Button>}
>

Your content here

</Admonition>

Blockquotes

Don't use blockquotes.

Code blocks

Keep code lines short to avoid scrolling. For example, you can split long shell commands with \.

  • JavaScript/TypeScript

    The supabase repository uses Prettier, which also formats JS/TS in code blocks. Your PR is blocked from merging if the Prettier check fails. From the repository root, run pnpm format, or set up automatic formatting in your IDE.

  • SQL

    Prefer lowercase for SQL. For example, select * from table rather than SELECT * FROM table.

Optionally specify a filename for the code block by including it after the opening backticks and language specifier:

```ts environment.ts

```

Optionally highlight lines by using mark=${lineNumber}.

```js mark=12:13

```

Emphasis

Use bold, italics, and code formatting for distinct purposes. Don't use them interchangeably or to add visual emphasis alone.

  • Bold: Mark UI labels the reader interacts with, such as buttons, menu items, and field names. For example, Click **Save**. Also use bold for a term the reader must not miss, such as **Never** commit your service role key. Bold is also the convention for an inline label that opens a paragraph or a list item, such as **Recommended**: or **Navigation:**.
  • Italics: Introduce a new term the first time you define it, or reference a title, such as a book or a third-party product name written in italics by convention. Use italics sparingly. Don't use italics for UI labels or for general emphasis.
  • Code: Mark anything the reader types or copies verbatim, or anything the system reads literally. This includes filenames, paths, commands, flags, environment variables, function and parameter names, configuration keys, and literal values. For example, Set `SUPABASE_URL` in your `.env` file.

If a phrase fits more than one category, pick the most specific one. A command name is code, not bold, even though the reader also interacts with it.

Content listings

Overview and index pages use a single <ContentListings id="..." /> component for curated link sections such as "Get started", "Next steps", "Examples", or "Resources". Refer to storage.data.ts and storage.mdx for a full example.

Prompt to add content listings:

Add a content listing block for [TOPIC] / [SECTION]. For example, use Storage / Examples.
Follow CONTRIBUTING § Content listings in apps/docs.
Copy structure from `storageGetStarted` in apps/docs/data/content-listings/storage.data.ts.
Pick a globally-unique kebab-case id like `[topic]-[section]`.
Run `pnpm test:local lib/content-listings.test.ts` from apps/docs.

Manually add content listings:

  1. Add or update a ContentListingGroup export in data/content-listings/[topic].data.ts. The id field must be globally unique across all listing groups. For example, use storage-get-started rather than get-started. The ID is both the lookup key and the telemetry listingId.
  2. Place the component inline in guide MDX, for example <ContentListings id="storage-get-started" />. Use a partial only when the block is reused or gated with $Show at the partial level. For individual items that depend on a feature flag (for example sdk:dart), set feature on the item instead of wrapping the whole listing.
  3. Run pnpm test:local lib/content-listings.test.ts from apps/docs.

Code snippets for manually adding content listings are available in .vscode/content-listing.code-snippets. Use cl-data for a data export with a namespaced ID. Use cl-inline for an MDX component.

Footnotes

Don't use footnotes.

Graphs

Render diagrams, including flowcharts, sequence diagrams, and entity-relationship diagrams, by writing a fenced code block with mermaid as the language. The MDX renderer routes these blocks through the shared Mermaid component, so theming follows light and dark mode automatically.

For the full list of supported diagram types and their syntax, see the official Mermaid diagram reference.

Sequence diagram:

```mermaid
sequenceDiagram
  participant User
  participant Browser
  participant Supabase

  User->>Browser: Clicks "Sign in"
  Browser->>Supabase: Request authorization
  Supabase->>Browser: Return token
```

The flowchart keyword accepts a direction such as LR or TD:

```mermaid
flowchart LR
  A["content/**/*.md"] -->|Contentlayer| B[MDX]
  B --> C[Rehype]
  C -->|Our Plugin| D[SVG]
  D -->|Base64| E[Embedded Images]
```

A few tips:

  • Use a standard Mermaid diagram keyword, such as sequenceDiagram, flowchart, or erDiagram, on the first line of the block.
  • Keep diagrams focused on a single flow or concept. If a diagram gets too dense, split it into multiple smaller diagrams.
  • Wrap node labels that contain special characters in double quotes. Special characters include *, /, spaces, and punctuation. For example, use A["content/**/*.md"].
  • Don't hardcode colors. The component themes the diagram automatically so it matches both light and dark mode.
  • Use diagrams to support the prose, not replace it. Explain the key takeaway in text near the diagram.

Images

Images are uploaded in the apps/docs/public/img folder.

For vector illustrations, use .svg files. For screenshots and non-vector graphics, use .png files. Supported browsers receive .webp versions automatically.

Redact any sensitive information, such as API keys.

Use descriptive link text that tells the reader where the link goes. This is important for accessibility. For example, don't use here as link text.

Keep link text concise. Use the shortest part of the link that is descriptive enough. For example, see the [reference section](/link) rather than [see the reference section](/link).

Don't include the https://supabase.com origin when linking to pages on supabase.com. Use a /docs/... path for a page in Supabase docs, such as [getting started](/docs/guides/getting-started). Use a site-root path for a page outside docs, such as [open the Supabase Dashboard](/dashboard).

Procedures

Use a procedure when a human or agent must perform actions to reach an outcome. The procedural format makes that expectation explicit.

Write sequential actions as an ordered list. Begin each step with an imperative verb, and include one action or a closely related set of actions per step. Give the reader enough context to know where to act.

Apply the Information Mapping chunking principle to procedures. Present 7 ± 2 related steps at a time. This gives readers a manageable chunk of five to nine actions. Aim for the lower end of the range when the task is complex or unfamiliar.

If a procedure has more than nine steps, group related steps into named phases or smaller procedures. If one step contains multiple distinct actions, split it into separate steps. Don't add steps to reach a minimum. The range is a guideline for organizing information, not a required procedure length.

An apparent one-step procedure can become two steps when there is a real orientation action. For example:

  1. Open a terminal in your project directory.
  2. Run supabase start.

The first step establishes the operating context for both readers and agents. Don't add a redundant orientation step to a genuinely atomic instruction. For example, write Click **Save**. instead of adding Locate the **Save** button as a separate step.

Lists

Use ordered lists for steps that must be taken one after the other. Use unordered lists when order doesn't matter.

Use Arabic numerals (1, 2, 3) for ordered lists and dashes (-) for unordered lists.

Don't nest lists more than two deep.

1. List item
2. List item
   1. List item
   2. List item
3. List item
   - List item
   - List item
     <!-- DON'T ADD ANOTHER LEVEL OF NESTING -->
     - Overly nested list item

Tabs

Use tabs to provide alternative instructions for different platforms or languages.

The optional queryGroup prop lets you link directly to a tab. For this example, use /docs/my-page?packagemanager=npm.

<Tabs
  scrollable
  size="small"
  type="underlined"
  defaultActiveId="npm"
  queryGroup="packagemanager"
>
<TabPanel id="npm" label="npm">

// ...

</TabPanel>
<TabPanel id="yarn" label="Yarn">

// ...

</TabPanel>
</Tabs>

Videos

Include videos as table of contents (TOC) videos instead of placing them in the main text.

You can define a TOC video in the page frontmatter:

---
tocVideo: 'rzglqRdZUQE'
---

Styling, formatting, and grammar

Grammar is useful when it makes your writing clearer. Use complete sentences by default because they identify the actor and action. This reduces ambiguity for readers, translators, and agents. Use sentence fragments only where they improve scanning, such as headings, labels, or short list items.

Headings guide the reader's eye and organize the page, but they don't carry information by themselves. Make the content beneath a heading understandable without relying on the heading. The first sentence can restate the heading, even if it sounds redundant. Readers often skim headings and then return to the section that interests them, so use the opening sentence to confirm the context.

Don't use parentheses for asides or supplementary information. Rewrite that information as part of the sentence or as a separate sentence. Use parentheses to introduce an acronym after spelling out its meaning, such as full-text search (FTS), or to mark an item as (Optional). Parentheses that are required by Markdown links or code syntax aren't prose parentheticals.

That said, a few rules help keep the docs concise, consistent, and clear:

  • Format headings in sentence case. Capitalize the first word and any proper nouns. All other words are lowercase. For example, Set up authentication rather than Set Up Authentication.
  • Use the Oxford comma. Place a comma before the and that marks the last item in a list. For example, use functions, tables, and indexes rather than functions, tables and indexes.
  • Use the present tense as much as possible. For example, the AI assistant answers your question rather than the AI assistant will answer your question.

Word usage and spelling

Use American English. If in doubt, consult the Merriam-Webster dictionary.

Follow the Supabase documentation word list for preferred spelling, capitalization, and usage. The word list includes the terminology rules checked by supa-mdx-lint. Run pnpm lint:mdx in apps/docs to check your changes.

Search uses a Supabase instance. During CI, a script collects guides, reference documentation, and other content. The script creates OpenAI embeddings and stores the search index in a Supabase database.

Search combines native Postgres full-text search (FTS) with embedding similarity search based on pgvector. At runtime, a PostgREST call invokes the weighted FTS RPC. An Edge Function runs the embedding search.