Logseq/Publish/Explanation/Options for Hosting Larger Files
Options for Hosting Large Media Files on a Logseq GitHub Pages Site
Background: Logseq Publishing and Large Files
- Publishing a Logseq site via GitHub Pages is a convenient way to share notes, but it poses challenges when including large media files (audio 20–80 MB, videos 50–700 MB, images 7–35 MB). GitHub imposes strict file size limits and GitHub Pages does not natively support Git LFS (Large File Storage) for serving assets. This means large files must be handled carefully to avoid exceeding Git limits or incurring performance issues. Below we explore several options for hosting these larger files, considering cost, setup effort, and privacy.
- Git LFS is an extension for Git that replaces large files in the repository with lightweight pointers, storing the actual content in a separate storage. It integrates into the Git workflow, allowing version control for large files without bloating the repository (Efficiently manage large files in Git with Git LFS, Benefits of managing large files with Git LFS).
- Pros: Setup is straightforward and keeps media in the same repo. It allows collaborative versioning of media and uses GitHub's infrastructure, avoiding external services (Different version control tool, Earlier versions if necessary).
- Cons: Git LFS has storage and bandwidth caps: each account gets 1 GB storage and 1 GB/month bandwidth free About storage and bandwidth usage. Exceeding 1 GB/month download bandwidth will disable LFS until the next month (unless more is purchased) (Bandwidth quota, Account until next month). A single 700 MB video viewed just twice could hit this limit. GitHub also blocks normal Git pushes over 100 MB, meaning large files must use LFS.
- GitHub Pages limitations: GitHub Pages does not directly serve LFS content – if an LFS pointer is pushed, the published site won't retrieve the file. In fact, Pages has no built-in support for LFS GitHub Community Discussion. The workaround is to use GitHub Actions to fetch LFS files at build time and include them in the published site. GitHub now supports deploying Pages via Actions, so by enabling
lfs: true in the checkout step, the action downloads the real files (GitHub Community Discussion, Standard deployment). This allows large files to be present in the static site output (bypassing the LFS pointer issue). However, be mindful: if a file exceeds 100 MB, even the Pages artifact may violate GitHub's limits if it were to be stored in a branch. Using the Actions deploy mechanism (which uploads the site via an API rather than a git push) might bypass the 100 MB git limit, but extremely large files could still pose problems or slow deployments. - Cost and privacy: Beyond the free tier, Git LFS requires purchasing data packs (e.g. $5 per 50 GB) for additional storage or bandwidth. If the site is low traffic, it might stay within the 1 GB/month free bandwidth, but any spike (e.g. a few people downloading a 700 MB video) would require additional bandwidth quota (Bandwidth quota, Account until next month). Privacy-wise, files in a public GitHub repository (or served via Pages) are accessible to anyone with the URL; there's no difference in privacy between hosting via GitHub vs. an external host since the site is public. One consideration is that using Git LFS means the large files are stored on GitHub's servers (and served from GitHub's CDN if included in Pages), which one may or may not trust for personal content. In general, if an all-in-one solution is preferred and the media usage is modest, Git LFS with a proper Pages Action can work, but it's not cost-effective for large videos or heavy traffic due to the strict quotas.
- For current R2 versus B2 pricing, see Cloudflare/R2/Concept/Pricing Compared with Backblaze B2. The estimates and free-tier details elsewhere on this older comparison page may no longer match current provider pricing.
- Cloudflare R2 is a relatively new object storage service that is S3-compatible. Is R2 a CDN or just storage? R2 is essentially "object storage" (a drop-in S3 replacement) R2 is an object store. By itself, R2 stores objects in a chosen region. However, when integrated with Cloudflare's network (by using a custom domain or Cloudflare Worker), the content can be cached and delivered via Cloudflare's CDN edges (CDN included if you use managed subdomain, Cloudflare CDN discussion). In practice, R2 is best thought of as storage with optionally CDN-like delivery when configured correctly. Cloudflare's documentation clarifies that if an R2 bucket is exposed through a custom domain (using Cloudflare DNS/proxy), the Cloudflare Cache and other features can be enabled to accelerate it (Production use cases, Development URL). If the default
*.r2.dev bucket URL (meant for development/testing) is used, caching or advanced features are not obtained (Development URL, Development URL). So, R2 itself is not automatically a multi-node CDN – Cloudflare's services must be used on top of it. - For a small personal site, Cloudflare R2's appeal is its pricing model: zero egress fees. Storage is paid for (approximately
$0.015/GB-month) and operations (API requests), but downloading data to users is free (In other words, Free forever tier). R2 also has an extremely generous free tier (e.g. millions of operations per month free) such that a low-traffic site is unlikely to incur any charge 1 million requests per month. This makes hosting large videos or audio files financially attractive compared to AWS/S3 or GitHub/LFS (which meter bandwidth).- Latency considerations
- Because R2 stores data in one region (a region closest to the expected audience can be chosen), the first request for an object will come from that region. Subsequent requests can be served from Cloudflare's cache if a custom domain is used and caching rules are set. However, note that Cloudflare's cache by default won't cache very large files (over ~512 MB) Without added cost or complexity. In other words, a 700 MB video might not be cached at edge locations, meaning each viewer could be pulling it from the R2 origin. This is still free in terms of cost, but could mean higher latency for distant users on initial load. If the audience is geographically distributed and the content is frequently accessed, this is a slight drawback of R2 versus a true CDN with multi-region storage. (Cloudflare R2 is reportedly working on or implying geo-replication, but as of now the data is stored in a single location until cached on demand Without added cost or complexity.)
- Cloudflare/CDN integration and cost: If a custom domain for the Logseq site is available (or a subdomain can be used), that domain can be set up on Cloudflare and pointed to R2. Cloudflare will then cache the R2 content globally by default without extra fees (CDN included if you use managed subdomain, Cloudflare CDN discussion). There is no additional cost for using Cloudflare's CDN on the free plan; only R2 storage/operations are paid for. This means effectively a globally distributed delivery is obtained for no egress cost. However, be mindful of Cloudflare's Terms of Service: the free CDN plan is not meant for serving mostly large media files (they don't want people building a video streaming service on the free tier) (Video chunks over their CDN, Cloudflare discussion). For a personal site with occasional media downloads, this is usually fine. Just ensure the usage is low-volume and primarily for personal/website content. Cloudflare's network has huge capacity and for occasional downloads of videos or audio, it should perform well.
- Summary of Cloudflare R2 for Logseq site: R2 can be an excellent solution to offload large files. Media would be uploaded to an R2 bucket, then referenced in Logseq pages via a URL. The simplest approach is to set the bucket to public and use the
https://<accountid>.r2.dev/bucketname/yourfile URL for each asset. For production use, consider using a custom domain (e.g. media.yourdomain.com) mapped to the R2 bucket for better caching and control (Production use cases, Development URL). In either case, the Logseq site's Markdown or HTML can reference the asset URL directly. The user's browser will fetch from Cloudflare's nearest cache (if available) or from the R2 store. Given a low-traffic personal site, R2's free tier likely covers all needs entirely, making it cost-effective. Just remember the initial fetch latency if not cached, and the 512 MB caching limit (which mainly affects very large videos). Cloudflare R2's privacy is comparable to other cloud storage – files are hosted on Cloudflare's servers (which are globally distributed and secured). If the content is not sensitive, this should be fine. If Encryption/At Rest or more control is required, R2 supports server-side encryption as well.
Other Low-Cost Object Storage and #CDN Solutions
- Beyond Cloudflare R2, there are several alternative storage/CDN providers that can fit a low-budget, low-traffic scenario:
- Backblaze/B2 Backblaze B2 is an object storage service known for its low storage cost (about $
0.005/GB-month) and it's part of the Bandwidth Alliance. Notably, B2 charges no egress fees when data is served through Cloudflare's network (Migrate objects to Backblaze, Cloudflare discussion). In practice, files can be stored in a B2 bucket and Cloudflare can be used as a proxy CDN (similar to using R2). B2's free tier offers 10 GB of storage and 1 GB/day of free download, and beyond that B2's egress fees are modest ($0.01/GB) – but if Cloudflare is fronting it, egress from B2 to Cloudflare is free. This combo is effectively similar to R2's no-egress model. B2 may be slightly cheaper for storage (and their pricing includes some free egress even without Cloudflare, up to 3× the storage as noted by Backblaze Changed pricing last). The trade-off is complexity: a Backblaze account and a Cloudflare domain configuration would be needed. If a Cloudflare setup already exists (for R2 or the site), adding B2 as origin is doable. For a personal site with <10 GB of media, B2 could end up essentially free. Files can also be served directly from B2's own URLs, but then egress would cost money – so it's best used with a Cloudflare (or another CDN) in front for zero-cost delivery. - **Bunny.net
- (BunnyCDN and Bunny Storage):** Bunny.net is a popular low-cost CDN provider that also offers Bunny Storage (a storage zone that integrates with their CDN). Files can be uploaded to a Bunny storage zone and have them served via Bunny's global CDN. Bunny's pricing is pay-as-you-go: e.g. $0.01/GB storage in a single region, and CDN bandwidth starting around $0.01/GB (depending on region, with lower rates for North America/Europe and a bit higher for Asia) – with no monthly minimums beyond a $1 minimum account balance. For very low traffic, only a few cents might be spent. Bunny allows choosing geo-replication for storage (e.g. have files stored in both US and EU), which means the first byte latency can be lower for users in those regions (Bunny will fetch from the nearest storage copy). Bunny's CDN caching is also very effective, and unlike Cloudflare free, Bunny is explicitly happy to serve videos or large files (since bandwidth is being paid for). Bunny was even mentioned to have zero-cost internal egress with Backblaze B2 as well JDBall55 (they too are in the Bandwidth Alliance), so one could mix and match (though if Bunny's own storage is used, that's not needed). The cons of Bunny for an individual: it's not "free" (a prepaid balance must be maintained, though small), and it's an extra external service to set up. Also, some users note Bunny's support or certain features may not be as robust as larger providers (one Reddit user noted slow support for a cache invalidation bug (Cloudflare discussion, Clear all of cache)). For a simple use-case like static file hosting, Bunny is usually very reliable and straightforward. Either Bunny's storage could be used or even point Bunny CDN to a Backblaze B2 bucket or to the GitHub Pages site as origin. But using it as an origin for large files on GH Pages (which might be slow or limited) is less ideal – better to use a proper storage for the origin.
- Wasabi: Wasabi is another object storage service known for no egress fees and a flat pricing of roughly
$5.99 per TB-month of storage. Wasabi's model is optimized for large, stable storage (they have a 90-day minimum retention: if a file is deleted sooner, 90 days are still paid for) WordPress backups. For a small personal site with only a few tens of GB at most, Wasabi's minimum charges (they often round up to at least 1 TB or so) make it less attractive – likely ~$6/month would be paid even if only 50 GB or 100 GB is stored. Also, Wasabi doesn't have a native CDN; something like Cloudflare would still be used in front if global caching is desired. Cloudflare can indeed proxy Wasabi, but at that point, R2 or B2 are simpler. Wasabi's strength is unlimited free egress on their side, but since Cloudflare already provides that for B2 or R2, Wasabi doesn't add much benefit unless huge volumes of data need to be stored very cheaply and lots of egress is needed (which doesn't match "individual low traffic site"). In short, Wasabi is likely overkill for this scenario – it's better suited for backup storage or cases where a lot of data needs to be served consistently (and even then, their terms expect the entire storage not to be repeatedly read constantly). - Other providers: The Reddit discussion on this topic also mentioned IDrive e2 and Telnyx. IDrive e2 is an S3-compatible storage with very low prices (sometimes ~$4/TB-month) and no ingress/egress fees (they follow a similar model to Wasabi). It could be a cheap option, but some users report the support is poor and reliability is unproven (Cloudflare discussion, Yes I know and I am using it). Telnyx is less mainstream as a storage provider (primarily known for telecom APIs), but they launched an object storage with a generous free tier. These could be options if adventurous, but given the strong free/low-cost choices above, they may not be necessary. Another option is to use generic cloud (AWS, Azure, GCP) with a CDN: e.g. Amazon S3 + CloudFront or Azure Blob + Azure CDN, but these tend to be far more expensive for egress (unless falling in a free tier) and thus not ideal for a cost-sensitive personal site.
- Relevance to Logseq + GitHub Pages: All the external storage solutions above (R2, B2, Bunny, Wasabi, etc.) can be used alongside GitHub Pages. The pattern is the same: large media files are uploaded to the storage/CDN, and in the Logseq content an absolute URL is used to embed or link them (rather than trying to store them in the GitHub repo). This keeps the GitHub repository lean and avoids LFS bandwidth issues. For example, in the Logseq markdown:
 for an image, or use an HTML <audio src="https://..."> or <video> tag to reference the externally hosted media. GitHub Pages will happily serve the site with those external links. The content itself (the notes, pages) remain small text files in the repo, and the media loads from the object storage/CDN when a user views the page.
Referencing Files with Object Storage URLs (Hashed or Direct)
- One advantage of using object storage for media is that pretty or human-readable URLs are not needed – the storage service can assign a unique URL or a content-hash can be used in the filename for cache busting without worrying about it. Since the Logseq site content will contain hyperlinks or embeds to these assets, the end user typically doesn't see the full URL anyway (for instance, an embedded image or audio player doesn't show the link). This means whatever naming scheme is convenient can be used or even just the object's ID from the storage.
- Hashed filenames for caching: If an asset is planned to be replaced with a new version occasionally, consider including a hash or version in its filename or path. For example, instead of
intro-video.mp4, it could be named intro-video-abc123.mp4 where abc123 is a short hash of the content. This ensures that when the video is updated, the link in the Logseq page is also updated to a new URL, so browsers and CDNs won't mistakenly use an old cached version. (This technique is common in static site deployments to leverage cache indefinitely for content that doesn't change.) If using R2 or B2, full control over object names is available, so this can be implemented easily. If using a service like Bunny's storage, file names are also controlled. Essentially, treat large files as immutable once uploaded; if they need to be updated, give the updated file a new name. Since a user-friendly URL structure doesn't need to be maintained, this approach is simple and effective. - No need for custom domain (unless desired): For a personal site, it's not required to serve assets from one's own domain. Using the storage provider's URL (like
f002.backblazeb2.com/file/yourbucket/filename or the R2 *.r2.dev link) is perfectly fine if the slightly odd-looking URL doesn't matter. This might even have privacy benefits (no direct association with the custom domain in the asset URL, though security-wise it's equivalent). However, using a custom domain has advantages: storage providers can be switched later by updating DNS, and HTTPS and caching rules can be enabled in one place. Cloudflare R2 in particular encourages custom domain usage to unlock CDN caching (Production use cases, Development URL). If a custom domain for the GitHub Pages site is available, a subdomain like media.yoursite.com might be added through Cloudflare (or Bunny, etc.) to serve the large files. This is optional and mainly for convenience and performance tuning.
Tools and Workflow for Uploading Assets
- Managing large files outside of Git can be made easier with the right tools. Here are some recommended open-source (or free) utilities and approaches for bulk uploading and managing these assets:
- Rclone: Rclone is a powerful open-source command-line program that supports a wide array of cloud storage services (including S3, Backblaze B2, Wasabi, and even FTP/SFTP for Bunny). Rclone can sync or copy entire folders to the storage bucket with one command. For example, Cloudflare's docs provide an example of using
rclone copy to upload files to an R2 bucket (supports files up to 5 TB) Upload and retrieve objects. Rclone can be configured with storage credentials and then easily script uploads. Rclone is particularly useful if media upload is wanted to be integrated into the workflow or an automated GitHub Action (e.g., one could imagine an action that on release builds, uploads any new large media files via rclone to the storage). It supports features like checksums, synchronization, and can even encrypt files if needed. - Official CLI tools (AWS CLI / B2 CLI / etc.): If provider-specific tools are preferred, options like the AWS CLI (which can interact with any S3-compatible storage including R2, Wasabi, IDrive e2, etc.), or Backblaze's B2 CLI for B2 storage are available. For instance, using the AWS CLI with R2 just requires setting the endpoint to R2's; then
aws s3 cp localfile s3://your-r2-bucket/ --endpoint-url https://<accountid>.r2.cloudflarestorage.com can be done. The AWS CLI and B2 CLI are both free and scriptable. These are suitable if comfortable with command-line operations and maybe integrating them in a deployment script. - Bulk upload via web or UI: Some services provide web dashboards to upload files (Cloudflare R2 allows direct file upload in their dashboard, Backblaze B2 has a web interface, etc.), but these are not ideal for large files or many files at once. A GUI like Cyberduck or Mountain Duck (desktop applications) can connect to various storage services and let files be dragged-and-dropped. Cyberduck is open source and supports S3, Backblaze B2, etc., which might be handy if a more visual approach is desired. It can even generate shareable links.
- Logseq integration: Currently, Logseq doesn't have native integration to auto-upload assets to an external store, but it can be managed manually. One approach is to keep large files in a local folder (perhaps within the Logseq workspace or elsewhere) and exclude them from the Git repo. When that folder is updated, a script or rclone can be used to sync it to the object storage. Then the Logseq markdown links can be updated if new files were added. This could be semi-automated with a simple shell or Python script that uploads any new files and prints the URLs to use.
- GitHub Actions for upload: If uploading is wanted to be automated as part of the site publish workflow, a GitHub Action could be configured to run on push that uses one of the above tools (rclone, AWS CLI, B2 CLI) with storage credentials (store them as GitHub Secrets) to upload assets. For example, a GitHub Action might detect any new file in an
assets-large/ directory and push it to the storage, then perhaps even update the Logseq content references (this part would be more complex and usually manual). If a simpler approach is preferred, handle uploads outside of GitHub by running rclone from the machine whenever needed. - In summary, rclone is highly recommended for its flexibility and support of many backends; it can handle whole-folder uploads and even has options to flatten directories or preserve structure as needed. Using the provider's CLI or AWS CLI is also reliable for scripting bulk transfers. All these tools are open-source or freely available. The key is to choose one that fits the workflow – for a one-time setup, a manual upload via a GUI might suffice, but for ongoing updates, a scripted approach will save time.
Choosing an Approach (Recommendations)
- For an individual, low-traffic Logseq site, the simplest and most cost-effective solution is to offload large media to an object storage with free or cheap egress. Cloudflare R2 is a strong option given its no-egress model and seamless CDN integration on Cloudflare's network – all the described files could likely be hosted essentially for free (within the free-tier limits) and with minimal latency impact. If Cloudflare is already used for the domain, R2 fits in neatly. Backblaze B2 with Cloudflare CDN is another excellent choice, especially if more data is anticipated to be stored long-term (B2's storage cost is lower). B2 is proven and reliable I'm not sure about the reliability, and its free egress to Cloudflare makes it nearly equivalent to R2 for this use case. Git LFS is the most integrated with the GitHub Pages workflow but comes with significant limitations (1 GB/month bandwidth cap, requiring an Actions hack to publish, and potential costs) (About storage and bandwidth usage, Bandwidth quota). It's generally not recommended for serving media to end-users unless the files are very infrequently accessed or very small. Finally, commercial CDNs like Bunny.net can offer great performance (global replication and no fear of violating TOS for videos) at a low price point – if spending a few dollars doesn't matter, Bunny could simplify things by handling both storage and delivery. For truly zero-cost setups, sticking to R2 or B2+Cloudflare is ideal.
- Whichever route is chosen, ensure the Logseq publishing configuration is updated to reference the correct URLs for the media. Once configured, the Logseq site will load heavy content from those optimized storage/CDN sources, keeping the GitHub repository light and the GitHub Pages deploys quick. This approach gives the best of both worlds: the convenience of GitHub Pages for the site structure and the efficiency of specialized storage for the large files. (Large files on GitHub.io, Private S3 bucket served by CloudFront)