---
title: "Pandoc relative paths with multiple files: tests"
slug: markdown-relative-paths-multiple-files
excerpt: "Under Turning on rebase_relative_paths, read the image and link paths pandoc wrote for two files kept in separate folders."
quickAnswer: "The section The two sample files prints both inputs and the folder they were run from. Plain runs of both readers are quoted in Plain readers keep paths as typed. Markdown-reader HTML carrying the extra switch is quoted under Turning on rebase_relative_paths. The same switch on the other reader fills Switching it on for commonmark. A URL and a slash-led path get their own look in Paths the extension left alone. One link that climbs a folder is traced in A parent-folder path kept as typed. A run made from inside one file's folder is quoted in One file run from its own folder. A numbered command list fills Steps for converting files from different folders."
keyTakeaways:
  - "Folder layout and file text for the inputs appear in The two sample files."
  - "Converted HTML for both files, switch on, is quoted in Turning on rebase_relative_paths."
  - "The section Paths the extension left alone looks at the URL and the slash-led path from the sample files."
  - "Read A parent-folder path kept as typed for the link out of the b folder."
  - "Commands to repeat this test come in order under Steps for converting files from different folders."
publishedDate: 2026-10-21
dateModified: 2026-10-21
author: Bobby Huang
cluster: B
role: post
status: published
faq:
  - q: Does pandoc fix relative paths when I convert files from different folders?
    a: "Compare the runs in Plain readers keep paths as typed against those in Turning on rebase_relative_paths."
  - q: Why did a path come out with two dots still in it?
    a: "The section A parent-folder path kept as typed walks through that link and the line counts taken on it."
  - q: Does a lone file get a folder prefix?
    a: "See One file run from its own folder for the command and the HTML it gave."
  - q: Can commonmark take the same switch?
    a: "That reader's HTML with the plus sign added sits in Switching it on for commonmark."
related:
  - markdown-images
  - markdown-links-to-local-files
  - markdown-image-link
---

Say you pass pandoc two Markdown files that live in different folders, and each one points at images and pages relative to its own folder. Here you'll find the paths pandoc wrote in that case, with and without a pandoc extension called `rebase_relative_paths`.

Each command got one run on one macOS computer, and `pandoc --version` printed 3.8.3. The output below is copied from the logs of that test. It says what pandoc wrote and makes no claim about how any other program treats those paths afterward.

## The two sample files

The test folder `rb` holds two subfolders, `a` and `b`, with one file in each. From inside `rb`, the first file printed as:

```sh
cat a/one.md
```

```text
# One

![Chart](img/chart.png)

See [the notes](notes.md), the [site](https://example.com/page) and [the root file](/top.md).
```

And the second:

```sh
cat b/two.md
```

```text
# Two

![Logo](logo.png)

Back to [one](../a/one.md).
```

`one.md` carries four targets. The image path is `img/chart.png`, the first link goes to `notes.md`, the second is the full URL `https://example.com/page`, and the third is `/top.md`, which starts with a slash. `two.md` has an image called `logo.png` and one link, `../a/one.md`, written to reach `one.md` from the `b` folder.

For how image and link paths are written inside a single file, read [images in Markdown](markdown-images.md) and [links to local files](markdown-links-to-local-files.md). Here the interest is what changes once two files from two folders go through one pandoc command.

Each multi-file run below was started from `rb`, so the arguments read `a/one.md b/two.md`.

## Plain readers keep paths as typed

First, the `markdown` reader with nothing added:

```sh
pandoc -f markdown -t html a/one.md b/two.md
```

```html
<h1 id="one">One</h1>
<figure>
<img src="img/chart.png" alt="Chart" />
<figcaption aria-hidden="true">Chart</figcaption>
</figure>
<p>See <a href="notes.md">the notes</a>, the <a
href="https://example.com/page">site</a> and <a href="/top.md">the root
file</a>.</p>
<h1 id="two">Two</h1>
<figure>
<img src="logo.png" alt="Logo" />
<figcaption aria-hidden="true">Logo</figcaption>
</figure>
<p>Back to <a href="../a/one.md">one</a>.</p>
```

Pandoc joined the two inputs into a single HTML stream, `one.md` first. Each `src` and `href` matches its source byte for byte: `img/chart.png`, `notes.md`, `logo.png` and `../a/one.md` came out with no folder in front. This reader also put each image inside a `figure` element with a caption.

The `commonmark` reader, again with nothing added:

```sh
pandoc -f commonmark -t html a/one.md b/two.md
```

```html
<h1>One</h1>
<p><img src="img/chart.png" alt="Chart" /></p>
<p>See <a href="notes.md">the notes</a>, the <a
href="https://example.com/page">site</a> and <a href="/top.md">the root
file</a>.</p>
<h1>Two</h1>
<p><img src="logo.png" alt="Logo" /></p>
<p>Back to <a href="../a/one.md">one</a>.</p>
```

The markup differs: no heading ids, and each image sits in a plain `p` element. The paths, though, are identical to those in the `markdown` run, unchanged from the source. Whatever wrapper each reader chose, the `src` and `href` values came through as written.

Why nothing moved: line 55 of the extension listing pandoc printed for `markdown` reads `-rebase_relative_paths`. That listing came from `pandoc --list-extensions`. For `commonmark`, line 19 of its listing holds that same text. The minus sign in front marks it as off unless you ask for it.

## Turning on rebase_relative_paths

Next, `+rebase_relative_paths` goes on the end of the reader name:

```sh
pandoc -f markdown+rebase_relative_paths -t html a/one.md b/two.md
```

```html
<h1 id="one">One</h1>
<figure>
<img src="a/img/chart.png" alt="Chart" />
<figcaption aria-hidden="true">Chart</figcaption>
</figure>
<p>See <a href="a/notes.md">the notes</a>, the <a
href="https://example.com/page">site</a> and <a href="/top.md">the root
file</a>.</p>
<h1 id="two">Two</h1>
<figure>
<img src="b/logo.png" alt="Logo" />
<figcaption aria-hidden="true">Logo</figcaption>
</figure>
<p>Back to <a href="b/../a/one.md">one</a>.</p>
```

Four paths got longer. From `one.md`, the image became `a/img/chart.png` and the notes link became `a/notes.md`. From `two.md`, the image became `b/logo.png` and the link back became `b/../a/one.md`.

Look at the prefix in each case. Targets from `a/one.md` gained `a/`, and targets from `b/two.md` gained `b/`. Here, the text pandoc added equals the folder part of each input path as it was typed on the command line.

Pandoc wrapped the paragraph lines at the same spots as in the plain run; this copy keeps its wraps.

## Switching it on for commonmark

The same plus sign works on `commonmark`:

```sh
pandoc -f commonmark+rebase_relative_paths -t html a/one.md b/two.md
```

```html
<h1>One</h1>
<p><img src="a/img/chart.png" alt="Chart" /></p>
<p>See <a href="a/notes.md">the notes</a>, the <a
href="https://example.com/page">site</a> and <a href="/top.md">the root
file</a>.</p>
<h1>Two</h1>
<p><img src="b/logo.png" alt="Logo" /></p>
<p>Back to <a href="b/../a/one.md">one</a>.</p>
```

Here the four rewritten paths match the `markdown` run string for string. What still separates the two outputs is the markup the plain runs already showed: heading ids and `figure` wrappers on one side, bare headings and `p` around images on the other.

The name `rebase_relative_paths` belongs to pandoc. It shows up in both extension listings cited above, and both readers took it: each run logged rc=0.

## Paths the extension left alone

Two of the targets in `one.md` came through both rebase runs untouched. The link to `https://example.com/page` kept its full URL, and the link to `/top.md` kept its leading slash with no `a/` in front.

Counts from the extra test back this up. `href="https://example.com/page"` matched once in the `markdown` output and once in the `commonmark` output. `href="/top.md"` matched once in each as well.

Put together, pandoc rewrote the four targets in this test that began with a plain name or with `..`, and skipped the one with a scheme and the one starting at a slash.

## A parent-folder path kept as typed

The link in `two.md` was `../a/one.md`. After the switch, pandoc wrote `b/../a/one.md` in its place.

Pandoc put `b/` in front and stopped there. The `b/..` pair stayed in the string; it was not shortened to `a/one.md`. Counting in the `markdown` rebase output found `href="b/../a/one.md"` on one line and `href="a/one.md"` on none. The `commonmark` rebase output gave the same count for the longer form.

If your later steps compare paths as plain strings, `b/../a/one.md` and `a/one.md` are different strings, and this run produced the first one.

## One file run from its own folder

The last run moved into `rb/a` and passed a bare file name, with the extension still on:

```sh
pandoc -f markdown+rebase_relative_paths -t html one.md
```

```html
<h1 id="one">One</h1>
<figure>
<img src="img/chart.png" alt="Chart" />
<figcaption aria-hidden="true">Chart</figcaption>
</figure>
<p>See <a href="notes.md">the notes</a>, the <a
href="https://example.com/page">site</a> and <a href="/top.md">the root
file</a>.</p>
```

No path changed. The image stayed `img/chart.png` and the notes link stayed `notes.md`, the same lines the plain `markdown` run printed for this file. A search for `a/img` in this output matched zero lines.

The argument `one.md` has no folder part, and pandoc added no prefix. That fits the two-file runs, where each prefix matched the folder written in front of the file name.

## Steps for converting files from different folders

These steps repeat this test's own commands with the same pandoc build. Step 4 is the run quoted under Turning on rebase_relative_paths, so your output can be held up against the logged bytes line by line.

1. Pick one folder to run from. Here it was `rb`, the parent of `a` and `b`.
2. Name each input with its folder, as in `a/one.md b/two.md`.
3. Add `+rebase_relative_paths` to the reader name, either `markdown` or `commonmark`.
4. Convert with `pandoc -f markdown+rebase_relative_paths -t html a/one.md b/two.md`.
5. Search the output for a folder followed by `..`, such as `b/../a/one.md`. Pandoc left that pair in place during this run.
6. Check the full URL and the slash-led path. In both rebase runs here, they kept their original text.

A sibling post in this batch, on [LaTeX macros in pandoc Markdown](markdown-latex-macros.md), puts another pandoc extension through the same kind of test.

## Where Sashmark fits

Sashmark's first version, as designed, would let you fix a sentence directly on the formatted page. If that clean Round-Trip holds, every line you skip should keep its bytes, with nothing lost. Changes View, planned for that version too, would point out what moved between one reading and the next, whether or not git is around.

It is in development and has not been released. The app itself has no AI features. See the [planned features](/features), the [help pages](/help) and the [roadmap](/roadmap) for where each part stands.

More at [sashmark.com](https://www.sashmark.com/).
