Color mode

Attachments, media, and publishing

Attachments and media

An attachment or media file is a vault file that is neither Markdown nor an image. Images in the vault are handled separately as content images, so keep the two apart.

obsidianMarkdown() gives vault files logical paths relative to contentRoot. For example, ![[attachments/report.pdf]] is rendered by attachment() and ![[media/interview.mp3]] by media(). Their generated URLs use this stable public shape:

text
/assets/attachments/<logical-path-relative-to-the-vault>

attachment() reads the embedded file size from the resolved vault root and rejects paths outside it. media() renders supported audio and video formats using the same logical path.

Asset URLs and published files

Generating a URL and publishing the file are two separate things. Assets fall into three kinds, each published by a different owner:

Kind Subject Public URL Published by
Content image An image in the vault /<logical-path-relative-to-the-vault> The Riebeckite build
Attachment / Media A file that is neither Markdown nor an image /assets/attachments/<logical-path-relative-to-the-vault> The site application
Static asset A file the site application owns anywhere under / Vite's public/ directory
Diagram source
text
flowchart LR
    Vault["Vault"]
    Image["Content image"]
    Attach["Attachment / Media"]
 
    Vault --> Image
    Vault --> Attach
 
    Image -->|"written by the build"| Output["Build output"]
    Attach -->|"URL only"| Public["public/"]
    Public --> Output

Content images are published by the build

obsidianMarkdown() writes every image referenced from a public page as build output. The image reaches the build output and is reachable through the generated URL without any action from the site application, keeping its logical path intact:

text
assets/logo.png
 
↓
 
/assets/logo.png

During development the same logical path is served directly from the content source. Images that nothing references, and images referenced only from non-public pages, are not written.

Publishing attachments and media is the site's responsibility

For attachments and media, generating a URL does not copy the binary file into the Vite public directory. The site application must copy only the assets it intends to publish to public/assets/attachments/, preserving their logical vault-relative paths. The reference application's build_images.ts shows an incremental, referenced-attachment-only implementation.

Static assets in public/

public/ is where the site application keeps its own assets. Everything below it is copied into the build output as-is. Keep it for site-owned files instead of dumping every vault image or attachment there, so the published set stays narrow.

Vaults are not published wholesale

Do not copy the whole vault as a shortcut:

text
vault/**
   ↓
public/**

That can expose private notes, images referenced only from non-public pages, unreferenced attachments, and .obsidian metadata.

Diagram source
text
flowchart TD
    Vault["Vault"]
 
    Vault --> Published["Published content"]
    Vault --> UsedAssets["Referenced assets"]
    Vault --> Private["Non-public content"]
    Vault --> Metadata[".obsidian / Metadata"]
 
    Published --> Public["Public site"]
    UsedAssets --> Public
    Private -. "not published" .-> Public
    Metadata -. "not published" .-> Public

The build emits images referenced by published content. Attachment cards and audio/video embeds render URLs under /assets/attachments/<logical path>, and the site application must copy those files into public/assets/attachments/ before build if you want them served after deployment. See Separate Content Repository for the detailed data flow.

History

1 changesCollapseExpand
1 + ---
2 + title: Attachments, media, and publishing
3 + sidebar:
4 + label: Attachments, media, and publishing
5 + order: 40
6 + ---
7 +
8 + # Attachments, media, and publishing
9 +
10 + ## Attachments and media
11 +
12 + An attachment or media file is a vault file that is **neither Markdown nor an
13 + image**. Images in the vault are handled separately as content images, so keep
14 + the two apart.
15 +
16 + `obsidianMarkdown()` gives vault files logical paths relative to
17 + `contentRoot`. For example, `![[attachments/report.pdf]]` is rendered by
18 + `attachment()` and `![[media/interview.mp3]]` by `media()`. Their generated
19 + URLs use this stable public shape:
20 +
21 + ```text
22 + /assets/attachments/<logical-path-relative-to-the-vault>
23 + ```
24 +
25 + `attachment()` reads the embedded file size from the resolved vault root and
26 + rejects paths outside it. `media()` renders supported audio and video formats
27 + using the same logical path.
28 +
29 + ## Asset URLs and published files
30 +
31 + Generating a URL and publishing the file are two separate things. Assets fall
32 + into three kinds, each published by a different owner:
33 +
34 + |Kind|Subject|Public URL|Published by|
35 + | --- | --- | --- | --- |
36 + |Content image|An image in the vault|`/<logical-path-relative-to-the-vault>`|The Riebeckite build|
37 + |Attachment / Media|A file that is neither Markdown nor an image|`/assets/attachments/<logical-path-relative-to-the-vault>`|The site application|
38 + |Static asset|A file the site application owns|anywhere under `/`|Vite's `public/` directory|
39 +
40 + ```mermaid
41 + flowchart LR
42 + Vault["Vault"]
43 + Image["Content image"]
44 + Attach["Attachment / Media"]
45 +
46 + Vault --> Image
47 + Vault --> Attach
48 +
49 + Image -->|"written by the build"| Output["Build output"]
50 + Attach -->|"URL only"| Public["public/"]
51 + Public --> Output
52 + ```
53 +
54 + ### Content images are published by the build
55 +
56 + `obsidianMarkdown()` writes every image referenced from a public page as build
57 + output. The image reaches the build output and is reachable through the
58 + generated URL without any action from the site application, keeping its logical
59 + path intact:
60 +
61 + ```text
62 + assets/logo.png
63 +
64 + ↓
65 +
66 + /assets/logo.png
67 + ```
68 +
69 + During development the same logical path is served directly from the content
70 + source. Images that nothing references, and images referenced only from
71 + non-public pages, are not written.
72 +
73 + ### Publishing attachments and media is the site's responsibility
74 +
75 + For attachments and media, generating a URL does **not** copy the binary file
76 + into the Vite public directory. The site application must copy only the assets
77 + it intends to publish to `public/assets/attachments/`, preserving their logical
78 + vault-relative paths. The reference application's
79 + `build_images.ts` shows an
80 + incremental, referenced-attachment-only implementation.
81 +
82 + ### Static assets in `public/`
83 +
84 + `public/` is where the site application keeps its own assets. Everything below
85 + it is copied into the build output as-is. Keep it for site-owned files instead
86 + of dumping every vault image or attachment there, so the published set stays
87 + narrow.
88 +
89 + ## Vaults are not published wholesale
90 +
91 + Do not copy the whole vault as a shortcut:
92 +
93 + ```text
94 + vault/**
95 + ↓
96 + public/**
97 + ```
98 +
99 + That can expose private notes, images referenced only from non-public pages,
100 + unreferenced attachments, and `.obsidian` metadata.
101 +
102 + ```mermaid
103 + flowchart TD
104 + Vault["Vault"]
105 +
106 + Vault --> Published["Published content"]
107 + Vault --> UsedAssets["Referenced assets"]
108 + Vault --> Private["Non-public content"]
109 + Vault --> Metadata[".obsidian / Metadata"]
110 +
111 + Published --> Public["Public site"]
112 + UsedAssets --> Public
113 + Private -. "not published" .-> Public
114 + Metadata -. "not published" .-> Public
115 + ```
116 +
117 + The build emits images
118 + referenced by published content. Attachment cards and audio/video embeds render
119 + URLs under `/assets/attachments/<logical path>`, and the site application must
120 + copy those files into `public/assets/attachments/` before build if you want them
121 + served after deployment. See [Separate Content Repository](../../guides/deployment/separate-content-repository.md#4-3-content-images-and-attachments-are-published-differently) for the detailed data flow.
122 +