> For the complete documentation index, see llms.txt.
Skip to main content

Check out Port for yourself ➜ 

Manage and surface technical documentation in Port

This guide demonstrates how to bring a TechDocs experience into Port, so your markdown documentation lives alongside the rest of your software catalog.

Three ideas drive the implementation of this guide:

  • Documentation lives as entities.
    Port persists each markdown file as a techDoc entity in your software catalog. Once data is in the catalog, every Port surface (search, AI, dashboards, plugins) can reach it through the same blueprint and relations.

  • Ingestion is source-agnostic.
    This guide uses GitHub as the example, but the same data model works with any source that can fetch markdown and upsert it into Port: GitLab, Bitbucket, Azure DevOps, Confluence, a webhook, or a CI job that calls Port's upsert entity API. Pick the source you have, keep the techDoc shape, and every downstream visualization keeps working unchanged.

  • Visualization follows context.
    The TechDocs plugin and the built-in markdown widget scope what they render based on the page they sit on. When placed on a service entity page, they show that service's documents; when placed on a repository entity page, they show that repository's documents; on a global dashboard, they show everything. The scoping uses the relations you define on the techDoc blueprint.

Available Github Integrations

This guide includes one or more steps that require integration with GitHub.
Port supports two GitHub integrations:

  • GitHub (Legacy) - uses a GitHub app, which is soon to be deprecated.
  • GitHub (Ocean) - uses the Ocean framework, recommended for new integrations.

Both integration options are present in this guide via tabs, choose the one that fits your needs.

Common use cases

  • Centralize technical documentation from many repositories into a single, queryable catalog.
  • Display documentation next to the service or repository it describes, on the relevant entity page.
  • Surface documentation in Port's global search and Port AI for fast, contextual answers.
  • Track ownership and freshness of documentation alongside the rest of your software catalog.
  • Optionally give your team a navigable in-Port reading experience for documentation, with a folder-based sidebar and document metadata.
  • Optionally let teammates discuss documents and resolve threads alongside the content.

Prerequisites

This guide assumes the following:

Set up data model

  • If you completed Port's onboarding, you already have a service blueprint with a relation to githubRepository. In this case, relate techDoc directly to service so documents follow the service they describe. The plugin can still scope by repository through the existing service-to-repository link.
  • If you do not have a service blueprint, or it is not connected to your repository blueprint, relate techDoc directly to githubRepository. This is the right choice for legacy catalogs where services were never modeled.

Choose the case that matches your catalog and follow the matching tab below. The rest of the guide carries the same choice through the integration mapping and the plugin parameters.

Create the techdoc blueprint with a service relation

  1. Go to the Builder page of your portal.

  2. Click on + Blueprint.

  3. Click on the {...} Edit JSON button.

  4. Copy and paste the following JSON schema:

    Tech Doc blueprint (click to expand)
    {
    "identifier": "techDoc",
    "title": "Tech Doc",
    "icon": "Book",
    "schema": {
    "properties": {
    "content": {
    "title": "Content",
    "type": "string",
    "format": "markdown",
    "description": "The raw markdown content of the document"
    },
    "filePath": {
    "title": "File Path",
    "type": "string",
    "description": "Path to the file within the repository"
    },
    "folderPath": {
    "title": "Folder Path",
    "type": "string",
    "description": "Parent folder path (e.g. apps/Frontend)"
    },
    "url": {
    "title": "GitHub URL",
    "type": "string",
    "format": "url",
    "description": "Direct link to the file on GitHub"
    },
    "lastUpdated": {
    "title": "Last Updated",
    "type": "string",
    "format": "date-time"
    },
    "archived": {
    "type": "boolean",
    "title": "Archived",
    "default": false
    }
    },
    "required": [
    "content"
    ]
    },
    "mirrorProperties": {},
    "calculationProperties": {},
    "aggregationProperties": {},
    "relations": {
    "service": {
    "title": "Service",
    "target": "service",
    "required": true,
    "many": false
    }
    }
    }
  5. Click Create to save the blueprint.

Update integration mapping

Next, we will configure the GitHub integration to fetch markdown files from your repositories and upsert them as techDoc entities.
The integration uses the file kind, which fetches file contents and exposes them in your JQ mappings.

The mapping below ingests each repository's top-level README.md from a list of repositories you specify. We start narrow on purpose so you can confirm the pipeline end-to-end with a couple of known repos, then broaden the file selection (more repos, docs/ folders, other markdown sources) once everything looks right.

  1. Go to your data sources page and click on your GitHub integration.

  2. Open the Mapping tab.

  3. Click on the {...} Edit YAML button.

  4. Append the following block to your existing configuration :

    Tech Doc mapping for GitHub (Ocean) (click to expand)
    resources:
    - kind: file
    selector:
    query: '.path | startswith("node_modules/") | not'
    files:
    - path: '**/*.md'
    repos:
    - name: my-service-repo # Replace with your repository name
    branch: main
    - name: my-other-service-repo # Replace with your repository name
    branch: main
    skipParsing: true
    port:
    entity:
    mappings:
    identifier: '.repository.name + "-" + (.path | gsub("/"; "-") | gsub("\\."; "-") | gsub(" ";"-"))'
    title: '.path | split("/") | .[-1] | split(".") | .[0]'
    blueprint: '"techDoc"'
    properties:
    content: .content
    filePath: .path
    folderPath: .path | split("/") | .[:-1] | join("/")
    url: '.repository.html_url + "/blob/" + .repository.default_branch + "/" + .path'
    lastUpdated: >-
    (try (.commit.commit.committer.date // .commit.commit.author.date //
    .commit.committer.date // .commit.author.date) catch null)
    // .repository.pushed_at // .repository.updated_at
    relations:
    service: .repository.name
  5. Click Save & Resync to apply the mapping and trigger a sync.

After the sync completes, open your catalog and switch to the Tech Doc tab to confirm that documents were ingested.
The title field is a JQ expression, so you can shape entity titles to suit how you browse the catalog (for example, include the repository name or the full path) when the default produces collisions like several README entries.

Refine the file selection

Once the initial sync looks right, you can broaden or tighten the selection in two ways:

  • Glob patterns and repository scope in files[] control which files are fetched. Add more entries (each with its own path, repos, and skipParsing) to ingest more sources. Examples:

    • Replace **/*.md with **/docs/**/*.md to ingest every markdown file under any docs/ folder in the listed repos.
    • Add a second path entry with a different repo list to ingest from another set of repositories.
    • Omit repos entirely to scan every repository the integration has access to.
  • JQ filters in selector.query control which fetched files become entities. The examples below use the Ocean field paths (.path, .name); for Legacy, prefix them with .file. (.file.path, .file.name).

    # Exclude node_modules and files whose name starts with an underscore.
    query: '(.path | startswith("node_modules/") | not) and (.name | startswith("_") | not)'

    # Only include files under a top-level "docs" folder.
    query: '.path | startswith("docs/")'

    # Regex match on file name (using JQ's test function).
    query: '.name | test("^(README|CHANGELOG|guide-.*)\\.md$")'

Add the TechDocs plugin (optional)

The built-in markdown widget displays a single techDoc entity at a time. For a richer experience with a folder-based navigation across multiple documents, Port provides a reference TechDocs plugin built on the plugins framework. You can use this plugin as-is, customize it to fit your needs, or build your own visualization from scratch.

The plugin reads the page it sits on and scopes the document list automatically, so the same plugin works for both data-model cases above:

  • On a service entity page, it shows only the documents related to that service.
  • On a repository entity page, it shows only the documents related to that repository.
  • On a dashboard, it is not scoped to any single entity and displays every techDoc in the catalog (across all services and repositories).
Image support

The TechDocs plugin does not render images embedded in markdown.

Set up the plugin

  1. Clone Port's Plugin repository.

  2. Enter the techdocs folder.

  3. Build the plugin and upload it with the Port plugins CLI by running the following commands:

    npm install
    npm run build
    port-plugins upload \
    --file dist/index.html \
    --identifier techdocs-port-plugin \
    --title "TechDocs Viewer" \
    --params "$(cat upload-params.json)" \
    --upsert
  4. On a dashboard or entity page, click + Widget, select Custom, choose the TechDocs Viewer plugin.

  5. Type TechDocs Viewer in the Title field.

  6. Select TechDoc as the TechDoc blueprint parameter.

  7. Select GitHub Repository or Service as the Tech Doc related blueprint parameter depending on your data model.

  8. Click Create to save the plugin.

Use Port AI and search to find documentation

Once documents live in the catalog, they are automatically available everywhere else in Port:

  • Global search: type a phrase from any document into Port's global search (Ctrl + K or Command + K) to find matching techDoc entities. See global search for query syntax.
  • API: read documents programmatically with the POST /v1/blueprints/techDoc/entities/search endpoint. See the search entities API reference.
  • Port AI: open the AI assistant with Ctrl + I (or Command + I) and ask natural-language questions such as:
    • "What tech stack was used in x service?"
    • "Which services are missing documentation in our catalog?"
    • "Where do we describe how to rotate the auth service's signing keys?"

Conclusion

You now have a complete pipeline for managing technical documentation in Port:

  • A techDoc blueprint that captures markdown content, file context, and a link back to either the service or the repository it belongs to, depending on your data model.
  • A GitHub integration mapping that keeps documentation in sync with its source of truth.
  • Built-in widgets and a dashboard that expose documentation across the catalog.
  • An optional plugin for a richer, navigable reading experience that scopes itself to the current service or repository entity page.
  • Out-of-the-box availability in global search, the Port API, and Port AI.

Because the contract is on the techDoc shape, you can extend this pattern to additional sources (GitLab, Bitbucket, Confluence, a webhook, or a CI job) without changing the dashboards or plugin layer.