We love your input! We want to make contributing to the Solana Developer content as easy and transparent as possible, whether it's:
- Reporting a bug
- Submitting a fix
- Discussing the current state of this repo
- Proposing new features
- called the "developer content" repo or "developer content API"
- written in markdown with YAML frontmatter
- uses YAML frontmatter, with structure enforced with Contentlayer
- all pages are grouped into "content types"
- supports some select custom components
- publicly displayed via the UI of solana.com (located in a different repo)
- content translations are supported via Crowdin
Since the content within this repo is meant to be publicly displayed on
solana.com
, we have very specific guidelines for the content that can be
merged into this repo (and eventually displayed on solana.com). If you would
like to submit changes to existing content or add new content, all of these
guidelines should be observed:
Avoid any language around making "official recommendations" such as "I recommend product X" or "Product Y is the best". The content within this repo will be publicly published on solana.com which is maintained by the Solana Foundation. As such, any "product recommendations" may appear as if coming directly from the Solana Foundation. The Solana Foundation does not make official recommendations for products but rather helps share what options are available in the broader Solana ecosystem.
Avoid language similar to "service X is my favorite". When talking about or naming specific products within the Solana ecosystem, writers and maintainers should make their best attempt to list multiple options that meet similar use cases. As a general rule of thumb, try to share at least 3-4 options of similar products or services, not just a single named one. For example, when talking about wallet providers, a writer could list Phantom, Solflare, Backpack, and Ultimate. When talking about RPC providers, a writer should link to solana.com/rpc instead of listing specific names.
Write content that uses up-to-date code. Code bases change, functions get deprecated, and methods get removed. When submitting code snippets within the content here, use the most up-to-date code available for the given functionality being used. Especially net new content, like adding a new guide.
To aid in keeping both consistent content and a high-quality experience, all code/content maintained within this repo shall use the style guidelines set forth here.
Failure to adhere to these style guidelines will slow down the review process and block approval/merging.
This repo uses prettier to help maintain the quality and consistency of the
content within. There is a master
prettier configuration file
(.prettierrc
) in the root of this repo.
On all commits and PRs, there is a GitHub action that checks if your PR follows the master prettier formatting. If your branch/code does NOT meet the prettier formatting requirements, it will not be merged and it will delay its review.
If your editor is not configured to auto-format on save using prettier, then you can run the following command to auto-format all files in your local repo/PR:
yarn prettier:fix
You can also run the prettier check command to see which files do not follow the prettier formatting guidelines.
yarn prettier
The content within a document should not start with a heading. It should start with a paragraph of text. After each heading should be non-heading content (i.e. do not stack headings without putting a sentence/paragraph between them).
Content should NOT include a h1
tag within it since solana.com will
automatically render a specific h1 based on the frontmatter's title
. As such,
all markdown h1
will be auto-converted to a h2
.
The text within a heading should NOT include inline code blocks (i.e. single
backtick). They should also NOT end with any special characters (i.e.
:;!@#$%^&*
). Ending in a question mark is allowed.
All h2-h4 headings will be auto-anchored, allowing anyone to directly link to the specific section of content. A clickable anchor link will be rendered aside from the heading's text.
## Simple, valid heading
The heading above is valid! Yay :)
## This is an `invalid` header
The heading above is invalid since it contains single backticks, aka this
character: `
### This is also invalid:
The heading above is invalid since it ends with a colon.
# this will become an h2
The heading above will be converted to a `h2` element
## This is okay?
The heading above is valid! Yay :)
#### this in not okay since it does not increment by only 1
The heading above is invalid since it skips the `h3` heading (`###`)
When linking to other developer content pages (i.e. docs, guides, etc) or images, the markdown link should be use the absolute path to the file relative to the repo root. Including the file extension.
For example: /docs/index.md
(good) vs https://solana.com/docs
(bad)
By linking to files this way, code editors will get better auto-complete for files and subheadings within those files. Ultimately providing a better experience when editing/maintaining the content.
It will also allow GitHub to provide correct links to view the markdown files within GitHub itself.
Using relative paths and directory climbing is not allowed. Including "single
dot" and "double dot" (i.e. ./file.md
and ../../another.md
).
This is a good link to the [Accounts](/docs/core/accounts.md) document
This [linking without](/docs/core/accounts) the `.md` file extension should be
avoided.
This is a good link to the
[Instructions](/docs/core/transactions.md#instruction) section of the
Transaction document.
This is a another good link to the
[Hello World in your browser](/content/guides/getstarted/hello-world-in-your-browser.md)
document.
For images, you can use the path starting with `/public` like this:
![this is the image caption](/public/assets/guides/hello-world/solpg.gif)
Note: When the content pages are generated and deployed on solana.com, the links will be automatically adjusted to function on the website. Including making the images viewable and removing
.md
file extensions.
When a content page is rendered on solana.com, a table of contents will be
auto-generated based on the markdown headings within the document's content.
Specifically: all h2
, h3
, and h4
(aka h2-h4) tags will be included in the
table of contents. All headings greater than h4
will be ignored from the table
of contents.
The exact text within the heading will be rendered as a line item in the table of contents. As such, thought should be put into the text within a heading, especially for accessibility.
This repo contains multiple different types of developer content records. Each
grouping of records (called a "content type") serves a different purpose and is
handled differently when displayed in the UI of solana.com
.
Below is a table describing each active content type group, including the corresponding path within this repo and webpage for viewing on solana.com:
Content Type | Repo Path | Webpage URL |
---|---|---|
docs |
/docs |
View Docs |
rpc |
/docs/rpc |
View Docs |
guides |
/content/guides |
View Guides |
resources |
/content/resources |
View Resources |
cookbook |
/content/cookbook |
View Cookbook |
Note: Even though
rpc
is technically a different record type, it is treated effectively the same as thedocs
type. More details in the "Frontmatter for Docs" section.
Every piece of content within this repo is normally written in markdown with YAML frontmatter. With some support for specific custom components using React and MDX.
We typically use GitHub flavor markdown (GFM) which you can learn more about here.
The YAML frontmatter is used to provide additional metadata about a given piece of content. Each content type has specifically supported frontmatter fields, some required and some optional. All available frontmatter fields are enforced via Contentlayer (see more below).
Here is an example of the frontmatter within a piece of content within this repo.
Contentlayer offers YAML frontmatter structure enforcement and type safety for the frontmatter fields on every content record, including generating TypeScript types for each content type's grouping.
Contentlayer does this code generation by enabling us to define a custom data
schema for the frontmatter. You can view the current Contentlayer schema here:
contentlayer.config.ts
If any content records contain unsupported or misspelled fields in the frontmatter, Contentlayer will throw an error, preventing misconfigured content from being shipped to production.
Each content type (i.e. docs
, guides
, resources
, etc) has the ability to
support different custom metadata fields within the YAML frontmatter.
While each content group may support additional frontmatter fields, the following are default supported by all content groups:
The primary title of the individual piece of content
- name:
title
- type:
string
- required:
true
Example: this line of text
The title
field will be used in auto-generating the social share card images
(aka OpenGraph images) that people will see when linking to the content page on
solana.com.
Brief description of the content (also used in the SEO metadata)
- name:
description
- type:
string
- required:
false
Example: these lines of text
This field will be used when a short description is needed to be displayed, like in typical blog style "overview cards" and for SEO related metadata.
List of filterable tags for content
- name:
tags
- type:
string
- required:
false
Example: these lines of text
List of keywords for the content, primarily used for SEO metadata when generating the website.
- name:
keywords
- type:
list
ofstring
s - required:
false
Example: these lines of text
The date this content was published
- name:
date
- type:
date
as an ISO-8601 formatted date (i.e.2023-12-06T00:00:00Z
) - required:
false
The date this content was last updated
- name:
updatedDate
- type:
date
string in the format ofMMM DD, YYYY
- required:
false
At this time, the docs
content type does not have any additional frontmatter
fields. They only support the shared default fields
Note: While technically, the
docs
content type is separate than therpc
content type, these are effectively treated the same. Therefore, assume all mentions ofdocs
also apply to therpc
type unless otherwise noted.
At this time, the guides
content type does not have any additional frontmatter
fields. They only support the shared default fields.
In addition to the default frontmatter fields, resources
support the following
fields:
General category of the resource
- type:
enum
- required:
true
- values:
documentation
framework
sdk
Repository URL for the developer resources
- type:
string
- required:
false
In addition to the standard GitHub-flavored markdown text, the content records within this repo support some extra functionality powered by custom React components (or custom implementations of standard components). The following is a list of available components
Note: While markdown does normally support standard HTML tags being rendered with the rest of the markdown document's content, this should normally be avoided within this developer content repo. See more in the Style Guidelines section.
- html tags - generally not to be used, with a few exceptions
- headings - details about how to include headings in a piece of content
- images - details about how to include images in a piece of content
- code blocks - additional functionality on top of standard markdown code blocks
- blockquote - additional functionality on top of the standard
HTML
blockquote
element - Callout - custom component used to render message to the reader in a more visually distinctive way (i.e. error messages, warnings, etc)
- Embed - embedding specific types of external content (i.e. YouTube videos)
Since the content files in this repo use markdown, using HTML tags within should be avoided. The markdown content render/parser will handle converting the text blocks into the associated HTML code blocks when rendered on page.
A few HTML elements are acceptable to use, the rest will normally be rejected:
details
- see this example
Headings (i.e. standard HTML tags of h1, h2, h3, etc) can be added to content using standard markdown-based headings.
Example:
# this gives an h1 (and should not be used)
## this gives an h2
### this gives an h3
#### this gives an h4
##### this gives an h5
Note: All markdown
h1
s will be auto converted to anh2
tag.
See more details above about the Heading styles.
Images can be embedded directly within markdown using standard markdown
formatting. Each image should use the absolute path of the image file located
within this repo (i.e. /public/assets/*
) and have a descriptive label
attached. This label will be rendered on the page with the image.
All images should be uploaded via a PR to this repo and stored within the
/public/assets/
directory.
Embedding external images within markdown is generally not allowed.
![descriptive label here](/public/assets/docs/transaction.svg)
In addition to standard markdown "fenced" code blocks (i.e. using triple backticks), the developer content repo supports additional functionality on top of code blocks.
Code block syntax highlighting and some other features utilize
rehype-pretty-code
andskiki
under the hood for some of the additional functionality supported.
Fenced code blocks support including additional metadata within their first line, called "meta strings". These meta strings allow the markdown processor to handle different logic of this user-defined metadata.
While most are familiar with language meta string, which enables syntax
highlighting. The following example has the language meta string of
typescript
:
```typescript
const example: string = "'typescript' is the language meta string";
```
This repo supports other meta strings as well:
- the standard syntax for the language value, which enables syntax highlighting
- file names
- line highlighting
- character/word highlighting
- diff lines
Each code block can have syntax highlighting for its specific language by noting the language used immediately following the triple backticks.
Most code languages are supported including these commonly used ones: rust
,
ts
or typescript
, js
or javascript
, toml
, shell
The code block's language should be in all lowercase and have no space between the language name and the backticks.
Examples:
```ts
const example: string = "this is typescript";
```
```shell
solana airdrop 2
```
Code blocks can have an optional header displayed on top of the code block element itself. This is commonly used to display the "file name" in which a code snippet comes from.
To display the file name header on a code block, in the same line of the triple
backticks and language add the filename=
field and set your desired name.
Examples:
```ts filename="index.ts"
const example: string = "this is typescript";
```
```rust filename="lib.rs"
use anchor_lang::prelude::*;
declare_id!("Bims5KmWhFne1m1UT4bfSknBEoECeYfztoKrsR2jTnrA");
```
Code blocks can highlight lines using the
syntax provided via rehype-pretty-code
.
In the meta string, place a numeric range inside {}
.
Examples:
```js {1}
// this will be highlighted
// this will NOT
```
```rust filename="lib.rs" {1,3}
// this will be highlighted
// this will NOT
// this will be highlighted
```
Code blocks can highlight characters using the
syntax provided via rehype-pretty-code
.
In the meta string, place character segments between two /
symbols. You can
also highlight multiple segments of characters.
Examples:
```js /word/
// this will be highlighted: word
// this will partially highlight: hello-word
```
```js /word/ /partially/
// this will be highlighted: word
// this will partially highlight: hello-word
```
```rust filename="lib.rs" /word/ {1,3}
// this will be highlighted: word
// nothing highlighted
// this will partially highlighted word and line: hello-word
```
Within a code block, you can create a "diff" style line (i.e. a line was added or a line was removed) using the
At the end of a line, add one of the following notations to the end of a line:
- to show a red "line removed" diff line:
// [!code --]
- to show a green "line added" diff line:
// [!code ++]
Example:
const keep = "line that stays";
const updated = "example that was should be removed"; // [!code --]
const updated = "example that was should be added"; // [!code ++]
const didNotChange = "this line did not change";
Standard markdown quote blocks are rendered with our custom
Callout
component.
Nested blockquotes are not allowed.
> This will be the `Callout` component with its default styles
Multiline blockquotes are allowed and will still be rendered as the default
Callout
.
> This blockquote will also be rendered as the `Callout` component with default
> styles. But since the text is much longer (and we enforce a Prettier
> configuration with a max line width) it should be wrapped to multiple lines.
> > This is a nested blockquote and is not allowed
The custom Callout
component can be used to render a message to the reader in
a more visually distinctive way (i.e. error messages, warnings, etc). Allowing a
writer to draw more focus to a specific statement.
Note: All standard markdown blockquotes will be auto converted to a
Callout
component with default styles.
The contents within the Callout
(aka children
in React land) will be
processed just like any other markdown. So you can put code blocks, lists, or
whatever else inside.
<Callout>
This will be the default "info" type callout
</Callout>
The Callout
component has the following props:
- name:
type
- required:
false
- type:
enum
- default:
info
- values:
info
- a blue callout block (equivalent values:note
,blue
)warning
- a red callout block (equivalent values:yellow
)caution
- a yellow callout block (equivalent values:yellow
)success
- a green callout block (equivalent values:green
)
- required:
- name:
title
- override the default title that is thetype
- required:
false
- type:
string
- default: the same text as the
type
's enum variant
- required:
<Callout type="caution">
this will render as a yellow callout with a title of "Caution"
</Callout>
<Callout type="success" title="You did it!">
this will render as a green callout with a title of "You did it!"
</Callout>
Callouts can also render other markdown content within it, just like you might expect. See this example here or the one below:
<Callout type="success" title="You did it!">
- list item 1
- list item 2
</Callout>
The custom Embed
component can be used to handle custom rendering of
specifically supported external content.
Currently supported external content:
To embed a YouTube video:
<Embed url="https://youtu.be/eudSSvyZF9o" />
Or
<Embed url="https://www.youtube.com/watch?v=eudSSvyZF9o" />
To embed a Whimsical diagram:
<Embed url="https://whimsical.com/embed/PjBVAREV3DMyW5722tFKJ8" />
Note: The preferred way to display a Whimsical diagram is to export the diagram as an SVG and directly embed the image within a specific piece of content.
Content translations are supported via the Crowdin platform.
All the markdown content committed to this repo is in the base language of
English
. On each successful merge of content, all changes are uploaded to
Crowdin (via GitHub actions) for them to be translated into the supported
locales.
During production deployments of the developer content api, all the currently translated content is downloaded from Crowdin and deployed for solana.com to correctly render the user-requested locale of content. Falling back to the base language when no translated content was found.
This developer content repo is a NextJS application that serves markdown-based content as REST API for solana.com to consume. Think of it like a microservice for content.
We call this microservice the "developer content API", or content API for short.
With this repo being only a "content API", there is no web app frontend to view the content within this repo. The frontend UI that will render all the markdown content within this repo is actually solana.com (which is a different repo).
To set up the developer content API:
- Clone the repo to your local machine:
git clone https://github.com/solana-foundation/developer-content.git
cd developer-content
- Install the dependencies via
yarn
:
yarn install
- Run the developer content API locally:
yarn dev
Note: The developer content API normally runs locally on port
3001