dockertest Documentation

Write better integration tests! Dockertest helps you boot up ephermal docker images for your Go tests with minimal work.

4,515 stars Go Go 1 file ยท ~9,080 tokens #automation#ci#docker#go#integration-testing#tests#unit-testing
RAW Doc

Docker & Self-Hosted Deployment Verified OCI

Deploy dockertest on any server, homelab, or cloud container platform.

1-Click Terminal Command
bash (docker run)
docker run -d --name dockertest --restart always ory/dockertest:latest

1. Project Overview & Quickstart (ory/dockertest)

Use Docker to run your Go integration tests against third party services on
Windows, macOS, and Linux!

Dockertest supports running any Docker image from Docker Hub or from a
Dockerfile.

Why should I use Dockertest?

When developing applications, it is often necessary to use services that talk to
a database system. Unit testing these services can be cumbersome because mocking
database/DBAL is strenuous. Making slight changes to the schema implies
rewriting at least some, if not all mocks. The same goes for API changes in the
DBAL.

To avoid this, it is smarter to test these specific services against a real
database that is destroyed after testing. Docker is the perfect system for
running integration tests as you can spin up containers in a few seconds and
kill them when the test completes.

The Dockertest library provides easy to use commands for spinning up Docker
containers and using them for your tests.

Installation

bash
go get github.com/ory/dockertest/v4

Quick Start

go
package myapp_test

import (
    "testing"
    "time"

    dockertest "github.com/ory/dockertest/v4"
)

func TestPostgres(t *testing.T) {
    pool := dockertest.NewPoolT(t, "")

    // Container is automatically reused across test runs based on "postgres:14".
    postgres := pool.RunT(t, "postgres",
        dockertest.WithTag("14"),
        dockertest.WithEnv([]string{
            "POSTGRES_PASSWORD=secret",
            "POSTGRES_DB=testdb",
        }),
    )

    hostPort := postgres.GetHostPort("5432/tcp")
    // Connect to postgres://postgres:secret@hostPort/testdb

    // Wait for PostgreSQL to be ready
    err := pool.Retry(t.Context(), 30*time.Second, func() error {
        // try connecting...
        return nil
    })
    if err != nil {
        t.Fatalf("Could not connect: %v", err)
    }
}

Migration from v3

Version 4 introduces automatic container reuse, making tests significantly
faster by reusing containers across test runs. Additionally, a lightweight
docker client is used which reduces third party dependencies significantly.

See UPGRADE.md for the complete migration guide.

API overview

View the Go
API documentation.

Pool creation

go
// For tests - auto-cleanup with t.Cleanup()
pool := dockertest.NewPoolT(t, "")

// With options
pool := dockertest.NewPoolT(t, "",
    dockertest.WithMaxWait(2*time.Minute),
)

// With a custom Docker client
pool := dockertest.NewPoolT(t, "",
    dockertest.WithMobyClient(myClient),
)

// For non-test code - requires manual Close()
ctx := context.Background()
pool, err := dockertest.NewPool(ctx, "")
if err != nil {
    panic(err)
}
defer pool.Close(ctx)

Running containers

go
// Test helper - fails test on error
resource := pool.RunT(t, "postgres",
    dockertest.WithTag("14"),
    dockertest.WithEnv([]string{"POSTGRES_PASSWORD=secret"}),
    dockertest.WithCmd([]string{"postgres", "-c", "log_statement=all"}),
)

// With error handling
resource, err := pool.Run(ctx, "postgres",
    dockertest.WithTag("14"),
    dockertest.WithEnv([]string{"POSTGRES_PASSWORD=secret"}),
)
if err != nil {
    panic(err)
}

See Cleanup for container lifecycle management.

Container configuration

Customize container settings with configuration options:

go
resource := pool.RunT(t, "postgres",
    dockertest.WithTag("14"),
    dockertest.WithUser("postgres"),
    dockertest.WithWorkingDir("/var/lib/postgresql/data"),
    dockertest.WithLabels(map[string]string{
        "test":    "integration",
        "service": "database",
    }),
    dockertest.WithHostname("test-db"),
    dockertest.WithEnv([]string{"POSTGRES_PASSWORD=secret"}),
)

Available configuration options:

  • WithTag(tag string) - Set the image tag (default: "latest")
  • WithEnv(env []string) - Set environment variables
  • WithCmd(cmd []string) - Override the default command
  • WithEntrypoint(entrypoint []string) - Override the default entrypoint
  • WithUser(user string) - Set the user to run commands as (supports "user" or
    "user:group")
  • WithWorkingDir(dir string) - Set the working directory
  • WithLabels(labels map[string]string) - Add labels to the container
  • WithHostname(hostname string) - Set the container hostname
  • WithName(name string) - Set the container name
  • WithMounts(binds []string) - Set bind mounts ("host:container" or
    "host:container:mode")
  • WithPortBindings(bindings network.PortMap) - Set explicit port bindings
  • WithReuseID(id string) - Set a custom reuse key (default:
    "repository:tag")
  • WithoutReuse() - Disable container reuse for this run
  • WithContainerConfig(modifier func(*container.Config)) - Modify the container
    config directly
  • WithHostConfig(modifier func(*container.HostConfig)) - Modify the host
    config (port bindings, volumes, restart policy, memory/CPU limits)

For advanced container configuration, use WithContainerConfig:

go
stopTimeout := 30
resource := pool.RunT(t, "app",
    dockertest.WithContainerConfig(func(cfg *container.Config) {
        cfg.StopTimeout = &stopTimeout
        cfg.StopSignal = "SIGTERM"
        cfg.Healthcheck = &container.HealthConfig{
            Test:     []string{"CMD", "curl", "-f", "http://localhost/health"},
            Interval: 10 * time.Second,
            Timeout:  5 * time.Second,
            Retries:  3,
        }
    }),
)

For host-level configuration, use WithHostConfig:

go
resource := pool.RunT(t, "postgres",
    dockertest.WithTag("14"),
    dockertest.WithHostConfig(func(hc *container.HostConfig) {
        hc.RestartPolicy = container.RestartPolicy{
            Name:              container.RestartPolicyOnFailure,
            MaximumRetryCount: 3,
        }
    }),
)

Container reuse

Containers are automatically reused based on repository:tag. Reuse is
reference-counted: each Run/RunT call increments the ref count, and each
Close/cleanup decrements it. The container is only removed from Docker when
the last reference is released.

go
// First test creates container
r1 := pool.RunT(t, "postgres", dockertest.WithTag("14"))

// Second test reuses the same container
r2 := pool.RunT(t, "postgres", dockertest.WithTag("14"))

// r1 and r2 point to the same container

Disable reuse if needed:

go
resource := pool.RunT(t, "postgres",
    dockertest.WithTag("14"),
    dockertest.WithoutReuse(), // Always create new container
)

Getting connection info

go
resource := pool.RunT(t, "postgres", dockertest.WithTag("14"))

// Get host:port (e.g., "127.0.0.1:54320")
hostPort := resource.GetHostPort("5432/tcp")

// Get just the port (e.g., "54320")
port := resource.GetPort("5432/tcp")

// Get just the IP (e.g., "127.0.0.1")
ip := resource.GetBoundIP("5432/tcp")

// Get container ID
id := resource.ID()

Waiting for readiness

Use pool.Retry to wait for a container to become ready:

go
err := pool.Retry(t.Context(), 30*time.Second, func() error {
    return db.Ping()
})
if err != nil {
    t.Fatalf("Container not ready: %v", err)
}

If timeout is 0, pool.MaxWait (default 60s) is used. The retry interval is
fixed at 1 second.

For more control, use the package-level functions:

go
// Fixed interval retry
err := dockertest.Retry(ctx, 30*time.Second, 500*time.Millisecond, func() error {
    return db.Ping()
})

// Exponential backoff retry
err := dockertest.RetryWithBackoff(ctx,
    30*time.Second,       // timeout
    100*time.Millisecond, // initial interval
    5*time.Second,        // max interval
    func() error {
        return db.Ping()
    },
)

Executing commands

Run commands inside a running container:

go
result, err := resource.Exec(ctx, []string{"pg_isready", "-U", "postgres"})
if err != nil {
    t.Fatal(err)
}
if result.ExitCode != 0 {
    t.Fatalf("command failed: %s", result.StdErr)
}
t.Log(result.StdOut)

Container logs

go
// Get all logs with stdout and stderr separated
stdout, stderr, err := resource.Logs(ctx)
if err != nil {
    t.Fatal(err)
}
t.Log(stdout)
t.Log(stderr)

// Stream logs until container exits or ctx is cancelled
var buf bytes.Buffer
err = resource.FollowLogs(ctx, &buf, io.Discard)

Building from Dockerfile

Build a Docker image from a Dockerfile and run it:

go
version := "1.0.0"
resource, err := pool.BuildAndRun(ctx, "myapp:test",
    &dockertest.BuildOptions{
        ContextDir: "./testdata",
        Dockerfile: "Dockerfile.test",
        BuildArgs:  map[string]*string{"VERSION": &version},
    },
    dockertest.WithEnv([]string{"APP_ENV=test"}),
)
if err != nil {
    t.Fatal(err)
}

BuildAndRunT is the test helper variant:

go
resource := pool.BuildAndRunT(t, "myapp:test",
    &dockertest.BuildOptions{
        ContextDir: "./testdata",
    },
)

Networks

Create Docker networks for container-to-container communication:

go
net := pool.CreateNetworkT(t, "my-network", nil)

// Connect a container
err := resource.ConnectToNetwork(ctx, net)

// Get the container's IP in the network
ip := resource.GetIPInNetwork(net)

// Disconnect
err := resource.DisconnectFromNetwork(ctx, net)

With custom options:

go
net, err := pool.CreateNetwork(ctx, "my-network", &dockertest.NetworkCreateOptions{
    Driver:   "bridge",
    Internal: true,
})

Cleanup

NewPoolT + RunT (recommended): Cleanup is fully automatic. RunT
registers cleanup via t.Cleanup, and the pool is closed when the test
finishes. Nothing to do.

go
func TestDB(t *testing.T) {
    pool := dockertest.NewPoolT(t, "")
    resource := pool.RunT(t, "postgres", dockertest.WithTag("14"))
    // Use resource... cleanup happens automatically when t finishes.
}

NewPool + Run: Call resource.Close(ctx) to release individual
containers, or pool.Close(ctx) to release everything:

go
ctx := context.Background()
pool, err := dockertest.NewPool(ctx, "")
if err != nil {
    panic(err)
}
defer pool.Close(ctx) // releases all tracked containers and networks

resource, err := pool.Run(ctx, "postgres", dockertest.WithTag("14"))
if err != nil {
    panic(err)
}
defer resource.Close(ctx) // or let pool.Close handle it

Advanced: shared pool in TestMain: Use this when you need a single pool
shared across all tests in a package:

go
func TestMain(m *testing.M) {
    ctx := context.Background()
    pool, _ := dockertest.NewPool(ctx, "")
    code := m.Run()
    pool.Close(ctx)
    os.Exit(code)
}

Error handling

go
resource, err := pool.Run(ctx, "postgres", dockertest.WithTag("14"))
if errors.Is(err, dockertest.ErrImagePullFailed) {
    // Image could not be pulled
}
if errors.Is(err, dockertest.ErrContainerCreateFailed) {
    // Container creation failed
}
if errors.Is(err, dockertest.ErrContainerStartFailed) {
    // Container start failed
}
if errors.Is(err, dockertest.ErrClientClosed) {
    // Pool or client has been closed
}

Examples

See the examples directory for complete examples.

Troubleshoot & FAQ

Out of disk space

Try cleaning up unused containers, images, and volumes:

bash
docker system prune -f

Running in CI

GitHub Actions

Docker is available by default on GitHub Actions ubuntu-latest runners, so no
extra services are needed:

yaml
name: Test with Docker

on: [push]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-go@v5
        with:
          go-version: "1.24"

      - run: go test -v ./...

GitLab CI

Shared runners

Add the Docker dind service to your job which starts in a sibling container. The
database will be available on host docker. Your app should be able to change
the database host through an environment variable.

yaml
stages:
  - test
go-test:
  stage: test
  image: golang:1.24
  services:
    - docker:dind
  variables:
    DOCKER_HOST: tcp://docker:2375
    DOCKER_DRIVER: overlay2
    DOCKER_TLS_CERTDIR: ""
    YOUR_APP_DB_HOST: docker
  script:
    - go test ./...

In your pool.Retry callback, use $YOUR_APP_DB_HOST instead of localhost when
connecting to the database.

Custom (group) runners

GitLab runner can be run in docker executor mode to save compatibility with
shared runners:

shell
gitlab-runner register -n \
 --url https://gitlab.com/ \
 --registration-token $YOUR_TOKEN \
 --executor docker \
 --description "My Docker Runner" \
 --docker-image "docker:27" \
 --docker-privileged

The DOCKER_TLS_CERTDIR: "" variable in the example above tells the Docker
daemon to start on port 2375 over HTTP (TLS disabled).

2. Official Technical Reference & Guides (ory/docs)

Ory Documentation

[Chat](https://slack.ory.com) | [Newsletter](https://www.ory.com/l/sign-up-newsletter) [Documentation](https://www.ory.com/docs/) | [Support this project!](https://opencollective.com/ory) [Work in Open Source, Ory is hiring!](https://www.ory.com/jobs/)

Overview

Ory documentation is the single source of truth for usage, implementation,
configuration, and troubleshooting of the Ory Network and all projects of the
Ory Ecosystem. The documentation
is best consumed through the
Ory documentation portal.

To see the source code of each of the projects, visit the project repository:

Documentation of other Ory projects:

Style guide

This style guide outlines the most important rules and conventions that apply to
the Ory documentation. If there are no Ory-specific requirements or guidelines
for a given topic, refer to the
Microsoft Writing Style Guide
and follow the rules described there.

Grammar and style

Ory documentation must be clear, concise, and unambiguous. To achieve that,
follow these simple rules:

  1. Use active voice and present tense.
  2. Always write in American English.
  3. Use
    zero conditional
    when talking about the cause-and-effect in software behavior.
  4. Use the right words to make sure that your message is clear and unambiguous.
    Don't use words like "should", "could", or "may".
  5. Don't use phrasal verbs, colloquialisms, and jargon.
  6. Don't refer to users in ways that imply their sex.
  7. Don't use contractions of Latin origins such as e.g or i.e.
  8. Remember to use articles (a, an, the) in your writing.
  9. Use common contractions such as aren't, don't, doesn't to sound
    friendly and informal.

Lists

Ory follows the
Microsoft Writing Style Guide list formatting guidelines.

  • List items must begin with a capital letter unless there's a specific reason
    not to do that. For example, the item is a proper name that's not capitalized,
    a parameter, or a command wrapped in backticks (`).
  • Don't use punctuation such as commas (,), semicolons (;), or conjunctions
    (and, or) at the end of list items.
  • Use periods (.) only at the end of list items that are proper sentences,
    even very short ones.
  • Make list items consistent in structure. For example, if one list item is a
    full sentence, make all list items full sentences. Don't use different
    structures for list items in a single list.
  • Indent lines with 3 spaces to denote nested sub-items in lists. Indent text,
    code blocks, and images.
  • When a bulleted list presents parallel items that each pair a label with an
    explanation, bold the label as a lead-in, followed by an em dash and the
    explanation. Use this pattern only when every bullet shares it. For example:
    • Fully managed infrastructure โ€” Ory Network runs a global edge network
      with multi-region availability, automatic scaling, and high availability.
      You don't patch servers, rotate keys, or manage failover.
    • Predictable pricing โ€” Usage-based billing with no per-seat fees, so cost
      scales with traffic rather than team size.

Headings

  • Use
    sentence case
    for headings.
  • The highest heading level in documents is h2. Use h1 only when you
    override the document title.
  • The lowest heading level in documents is h4. If you absolutely need to add
    more heading levels, don't go lower than h5.
  • Avoid using symbols and special characters in headings.
  • Leave one blank line before and after a heading.
  • Don't use links in headings.
  • Headings play an important role in SEO and searchability and make the document
    more scannable. Make your headings short and true to the content they
    introduce.

Formatting

Write in Markdown. Don't mix HTML tags with
Markdown. Files with the .mdx extension use
JSX-extended Markdown (MDX).

Document front matter

Add this front matter to every document you create:

md
---
id: excellent_feature
title: Learn how to use the excellent feature in your implementation
sidebar_label: Excellent feature
slug: excellent-feature-for-some-reason
---
  • id is the document identifier that makes up the last part of the document
    URL. Try to come up with a short ID that accurately describes the content. IDs
    that use multiple words must use hyphens (-) to separate the words.
  • title is the document title thatโ€™s displayed as the page header. Used by
    search engines when displaying search results. Try to make it descriptive so
    that it helps readers understand what the document is about at the first
    glance. If it comes out long(ish), you can overwrite it by adding a h1 in
    the very first line following the front matter. Use sentence case.
  • sidebar_label represents the document title used in the sidebar (left
    navigation). Create a short document title that fits the sidebar width. Use
    sentence case.
  • slug is an optional property that allows you to customize the document URL.
    Use it to create more meaningful, SEO-friendly URLs.
  • description is a one-sentence summary of the page. Any document that appears
    as a card in a sidebar category (a generated category index) must set it,
    because Docusaurus derives the card text from createExcerpt, which only
    keeps the first physical line of the first paragraph and truncates at the
    source line wrap. Setting description gives you the full, intended card text
    and is also used by search engines. Keep it to one short sentence.

Bolding, 'code formatting'

  • Use only code and bold formatting. Don't use any other formatting.
  • For inline code, wrap text in single backticks (`). For code blocks use
    three backticks (```)
  • Use code formatting for:
    • Commands, for example ory --help
    • File names and paths, for example file.txt, ~/Desktop/git/docs
    • Environment variables, for example CUSTOM_ENV_VAR
  • Use bold only when writing about user interface (UI) elements.

Linking

  • Link to external web pages using absolute links. Don't expose the link on its
    own. Instead, embed it in descriptive text. For example:

    text
    Ory documentation uses [Prism syntax highlighting](https://prismjs.com/).
  • Link to documents within this repository using relative links. When
    referencing the file, use the file name.

    text
    [Some link](../path/to/file.mdx)

Code blocks

  • Always add a programming language identifier to code blocks. Ory documentation
    uses Prism syntax highlighting.

    text
    ```json
    {some-JSON-code-here}
    ```
  • For command line examples, use shell as the programming language identifier.
    Don't put $ before the command.

    text
    ```shell
    ory get identities
    ```
  • For Ory Permissions (Keto) relation tuples, use keto-relation-tuples
    language identifier, and for relationships use keto-relationships.

    text
    ```keto-relation-tuples
    namespace:object#relation:subject
    // comment
    ```
    
    ```keto-relationships
    namespace:subject is relation of object
    is namespace:subject allowed to permission on object?
    // comment
    ```
  • For multi-line commands, indent subsequent lines of the command with two
    spaces.

    text
    ```shell
    curl --request GET -sL \
      --header "Content-Type: application/json" \
      --header "Authorization: Bearer {ORY_API_KEY}" \
      'https://{project-slug}.projects.oryapis.com/admin/identities/{identity_id}?include_credential=oidc'
    ```

Placeholders and dummy data

Using placeholders and dummy data in code snippets and command examples is a
good way to ensure that users run commands in the context of their setups and,
as a result, achieve success faster. Additionally, this fabricated information
prevents leaking of sensitive data such as tokens or API keys.

Follow these rules when using placeholders and dummy data:

  • Introduce placeholders and dummy data in curly brackets with a preceding $ so
    they can be used in bash commands.
  • Use colons (-) or underscores (_) to separate multiple words, for example
    {ORY_SESSION_COOKIE} or {project-slug}.
  • When referring to a project API URL or SDK URL, always use
    https://$PROJECT_SLUG.projects.oryapis.com.
  • When referring to scenarios in which the user runs a custom domain, use
    https://ory.your-custom-domain.com.
  • Always use short, but descriptive, verbal placeholders. Don't mix digits and
    letters to mimic the format of the data you mock.

UI references

When talking about any user interface (UI) in the Ory documentation, follow
these rules:

  • When referring to UI elements, always use the exact text associated with the
    given element.
  • Format the name of the UI element you refer to in bold.
  • Format any user input with code.

Example: In the Identity Model Schema box, type MyCustomIdentitySchema.

Diagrams

Use Mermaid to create diagrams. You
can run the tool locally or use Mermaid Live Editor in
the browser. See the
Mermaid Cheatsheet
for a detailed description on how to use Mermaid.

To add a Mermaid diagram, use this mdx-code-block:

md
```mdx-code-block
import Mermaid from "@site/src/theme/Mermaid"
<Mermaid
  chart={`

{your-Mermaid-code}

`}
/>
```

Import & reference content

Markdown partials

If a certain piece of content must be re-used across multiple documents in the
exact form, it's a good idea to turn it into a partial. Thanks to that, you
maintain content in a single file, instead of multiple instances of the same
content in many docs.

Add partials to the _common directory.

To import a partial, use this mdx-code-block:

md
```mdx-code-block
import ExamplePartial from './_common/example.md'

<ExamplePartial />
```

TIP: Headings contained in partials aren't added to the Docusaurus table
of contents (ToC). To make sure users can access all headings through the ToC,
don't add headings to partials. Instead, add appropriate headings to the
document manually and introduce partials after them. To see an implementation
of this approach, look at
this file.

Code snippets

From GitHub

Use
CodeFromRemote
to import code directly from GitHub.

Use this mdx-code-block:

md
```mdx-code-block
import CodeFromRemote from '@theme/CodeFromRemote'

<CodeFromRemote
  lang="js"
  link="https://github.com/ory/kratos-selfservice-ui-node/blob/master/src/middleware/simple.ts"
  src="https://raw.githubusercontent.com/ory/kratos-selfservice-ui-node/master/src/middleware/simple.ts"
  startAt="{CONTENT_FROM_CODE}"
  endAt="{CONTENT_FROM_CODE}"
/>
```
  • lang specifies the programming language the code is in
  • link is the file location displayed in the top part of the code block window
  • src is the direct link used to import the code (optional)
  • startAt , endAt are used to define where the imported snippet starts and
    ends (optional)

From this repository

md
```mdx-code-block
import CodeBlock from '@theme/CodeBlock'
import exampleJs from '!!raw-loader!./code-example.jsx'
import exampleGo from '!!raw-loader!./code-example.go'

<CodeBlock className="language-jsx">{exampleJs}</CodeBlock>
<CodeBlock className="language-go">{exampleGo}</CodeBlock>
```

Screenshots and videos

  • Use screenshots and videos sparingly. These resources tend to get out-of-date
    quickly and are cumbersome to maintain.
  • Screenshots and videos must capture only the relevant parts of the screen.
  • Screenshots and videos must capture UI elements in English. If youโ€™re
    capturing parts of the browser UI in your work, make sure the UI is in
    English.
  • Make an effort to get the screenshots and videos looking as clean as possible.
    Avoid situations where text fields suggest irrelevant inputs, avoid erratic
    mouse cursor movements and general chaos.
  • You must add media to _static folders.
    • In the _static directory, each document that uses media has its own
      directory.
    • In the directory of the document, the files have numbers for names, for
      example, 1.png, 2.png, 3.png. The filenames should reflect the stage
      at which the media is used in the document. This means that the screenshot
      named 1.png will be used in line 70, while the diagram 2.svg will be
      used in line 100.

Compressing images

Compress images you add to the documentation to keep the repository lean. You
can use pngquant.
Read this article to learn a trick to make your screenshots 80% smaller.

Recording and compressing videos

We recommend using
Quicktime to record videos.
Follow these rules:

  • Use 16:9 format with at least 1024 pixels of width. ffmpeg will scale it to
    the right size.
  • Make sure that no history or auto-suggestions are visible.

After recording the video, convert the .mov file to mp4 and webm:

shellsession
file="screencast.mov"

ffmpeg -i $file -an -c:v libvpx-vp9 -vf scale=1024:-1 -crf 30 -b:v 0 "${file%.*}".webm
ffmpeg -i $file -vcodec h264 -vf scale=1024:-1 -an "${file%.*}".mp4

Use this mdx-code-block to add the video to your document:

text
```mdx-code-block
import mp4 from './_static/screencast.mp4'
import webm from './_static/screencast.webm'
import VideoEmbed from '@site/src/components/VideoEmbed'

<VideoEmbed mp4={mp4} webm={webm} />
```

Ory Console

You can use the /current/ route to navigate users to their active Ory Network
project. For example, to access the Custom UI settings for the active Ory
Network project in the Console, you can link to:
https://console.ory.com/projects/current/ui

When referencing a page of the Ory Console, use the
<ConsoleLink route="project..." /> component in MDX files.

The component resolves the navigation section and page title for the given
route, and renders a standard markup for both, as well as the link with the
/current/ shortcut mentioned above:

tsx
<ConsoleLink route="project.activity.events" />

// becomes:
// Activity โ†’ Logs & Events in the [Ory Console](https://console.ory.com/current/projects/activity/events)

A list of all supported routes can be found here:
src/components/ConsoleLink/console-routes.ts.

Please note that the syntax is like accessing a path in a JS object, but as a
string. If the route you want to reference is found in the console-routes.ts
file in the following way:

ts
{
  project: {
    activity: {
      events: {
        route: "/projects/[project]/activity/events",
      }
    }
  }
}

Use <ConsoleLink route="project.activity.events" /> to reference it.

To add a new route, you need to add an entry in
console-routes.ts
as well as
console-nav-data.ts.

Testing

To test the documentation locally:

  1. Clone this repository.
  2. Navigate to the cloned repository and run npm install to install all
    dependencies.
  3. Run the development server and test the changes you made using a fully
    operational version of the documentation portal that runs on your machine.
    Run npm run start.
  4. Create a production build to check for any technical issues, such as invalid
    internal links. Run npm run build.

Redirects

When the URL of a document changes, you must set up a redirect to preserve SEO
and prevent broken links. Without redirects, the original URL returns a 404
error, breaking existing links from external sites and causing search engines to
lose page authority.

The rule is: if the URL in the browser changes, add a redirect. If it doesn't,
no redirect is required.

Filenames don't always determine URLs. Ory documentation uses numbered prefixes
in filenames and sets URLs explicitly in the front matter. Renaming with no
other changes doesn't require a redirect because the final URL stays the same.

You must add a redirect when you

  • change the slug or id property in the document front matter
  • delete a document
  • move a document to a different directory (if it changes the URL path)

How to add a redirect

Add redirects to the vercel.json file in the repository root. Use this format:

json
{
  "redirects": [
    {
      "source": "/docs/old-path",
      "destination": "/docs/new-path",
      "permanent": false
    }
  ]
}
  • Start with permanent: false (302 redirect) until you confirm the redirect
    works in the preview or production environment.
  • Change to permanent: true (301 redirect) after you verify the redirect
    functions correctly.
  • Test the redirect in the Vercel preview deployment before merging.

Formatting documentation

All documents and other files in this repository must be formatted with Prettier
using the Ory Prettier styles.

To format all relevant files, run these commands from the main directory of the

sh
make format
git commit -a -m "chore: format"
git push

For a better workflow, install the Prettier plugin for your editor:

Adding content to "Examples" page

The Quickstart overview
provides an overview of Ory quickstarts. To add a new example or modify existing
entries:

  1. Open examples-content.tsx in src/pages/_assets/.

  2. Copy the following snippet and append it to the correct array (either
    official, community, or self-hosting examples):

    tsx
    {
          title: "Protect a Page with Login: NextJs/React", //Your example title goes here
          language: "typescript",                           //The main programming language of your example
          author: "ory",                                    //The author's GitHub handle
          tested: true,                                     //Is the example in ory/examples or ory/docs and has automated tests?
          repo: "https://github.com/ory/docs/tree/master/code-examples/protect-page-login/nextjs", //The repo containing the example code
          docs: "https://www.ory.sh/docs/guides/protect-page-login/next.js",                       //Documentation for the example, can be README, blog article or similar
        },
    • language can be one of: dart, django, docker, erlang, flutter, go, java,
      javascript, kotlin, kubernetes, nextjs, nodejs, ory, php, python, react,
      rescript, svelte, typescript, vue
  3. Open a pull request with your changes.

CLI and API reference - auto-generated content

Ory documentation contains auto-generated content such as CLI and API
references. Documents of this type are generated from source code and are pushed
to this repository by an automated job.

As such, editing any of these documents in the Ory documentation repository
isn't the way to change or fix this content. Any changes you make will be
overwritten by the next push that follows the generation process.

Instead, find the lines in question in the source code of the Ory projects and
edit them there. For example, if you want to edit the documentation of the Ory
Kratos CLI, you must edit this file:

https://github.com/ory/kratos/blob/master/cmd/clidoc/main.go

The cmd/clidoc/main.go is the general path for all Ory projects.

The command to generate the CLI docs can be found here:
https://github.com/ory/x/blob/master/clidoc/generate.go#L96