Document built-in S3 storage adapter - #118
Conversation
ref https://linear.app/ghost/issue/HKG-1948 Ghost now ships an S3Storage adapter in core, but the config docs only listed third-party storage modules. Document the built-in adapter and its configuration options so operators can set up S3-compatible object storage without reverse-engineering the schema.
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Workflows to automatically generate PRs for you. |
WalkthroughThe documentation adds coverage for Ghost’s built-in Estimated code review effort: 2 (Simple) | ~10 minutes Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@config.mdx`:
- Line 550: Update the multipartUploadThresholdBytes description in the
S3Storage configuration table to state that files at least this size use
multipart upload, reflecting the inclusive greater-than-or-equal threshold
behavior.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
| | `bucket` | Yes | Name of the S3 bucket. | | ||
| | `cdnUrl` | Yes | Public base URL that stored files are served from (your CDN or the bucket's public URL). Ghost builds each file's public URL from this value. | | ||
| | `staticFileURLPrefix` | Yes | Path prefix within the bucket that files are stored under, e.g. `content/images`. | | ||
| | `multipartUploadThresholdBytes` | Yes | Files larger than this size (in bytes) are uploaded using S3 multipart upload. | |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -eu
printf '%s\n' '--- candidate files ---'
git ls-files | rg '(^|/)(config\.mdx|S3Storage(\.[^/]*)?|.*S3.*[Tt]est.*)$' || true
printf '%s\n' '--- threshold references ---'
rg -n -C 4 'multipartUploadThresholdBytes|multipart upload' . \
-g '!node_modules' -g '!dist' -g '!build' || trueRepository: TryGhost/Docs
Length of output: 1715
🏁 Script executed:
#!/bin/bash
set -eu
url='https://unpkg.com/ghost@6.13.2/core/server/adapters/storage/S3Storage.ts'
printf '%s\n' '--- published S3Storage.ts threshold logic ---'
curl -fsSL "$url" | rg -n -C 8 \
'multipartUploadThresholdBytes|createMultipartUpload|uploadPart|>=|>'
printf '%s\n' '--- exact source lines ---'
curl -fsSL "$url" | nl -ba | rg -n -C 5 \
'multipartUploadThresholdBytes|createMultipartUpload|uploadPart'Repository: TryGhost/Docs
Length of output: 9917
Document the threshold as inclusive.
S3Storage uses multipart upload when the file size is greater than or equal to multipartUploadThresholdBytes. Change “Files larger than this size” to “Files at least this size.”
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@config.mdx` at line 550, Update the multipartUploadThresholdBytes description
in the S3Storage configuration table to state that files at least this size use
multipart upload, reflecting the inclusive greater-than-or-equal threshold
behavior.
Source: MCP tools
| "multipartUploadThresholdBytes": 52428800, | ||
| "multipartChunkSizeBytes": 10485760 | ||
| } | ||
| } |
There was a problem hiding this comment.
The config should also have urls.image / urls.media / urls.files. When assets are served from a different CDN host, Ghost needs these values to recognize them as its own. Without them, responsive image sizes aren't generated, and the CDN URL gets stored directly in your content instead of Ghost's portable __GHOST_URL__ form.
|
|
||
| | Option | Required | Description | | ||
| |---|---|---| | ||
| | `bucket` | Yes | Name of the S3 bucket. | |
There was a problem hiding this comment.
NIT - Bucket must be publicly readable. "Name of the public S3 bucket." maybe?
| |---|---|---| | ||
| | `bucket` | Yes | Name of the S3 bucket. | | ||
| | `cdnUrl` | Yes | Public base URL that stored files are served from (your CDN or the bucket's public URL). Ghost builds each file's public URL from this value. | | ||
| | `staticFileURLPrefix` | Yes | Path prefix within the bucket that files are stored under, e.g. `content/images`. | |
There was a problem hiding this comment.
The example is correct but staticFileURLPrefix isn't really a free-form value. It needs to be content/images, content/media, or content/files depending on the feature, since Ghost matches those prefixes when building URLs.
|
|
||
| Ghost ships with an `S3Storage` adapter that stores files in Amazon S3 or any S3-compatible provider (such as MinIO, Google Cloud Storage, or Cloudflare R2). No additional module needs to be installed. | ||
|
|
||
| Because images, media, and files each need their own path prefix, share a single `S3Storage` configuration block and override `staticFileURLPrefix` per feature: |
There was a problem hiding this comment.
It may be worth mentioning that adapters can be mixed per feature. Media and files can use S3 while images stay on local storage; they don't all need to move together.
|
|
||
| #### Ghost's built-in S3-compatible storage adapter | ||
|
|
||
| Ghost ships with an `S3Storage` adapter that stores files in Amazon S3 or any S3-compatible provider (such as MinIO, Google Cloud Storage, or Cloudflare R2). No additional module needs to be installed. |
There was a problem hiding this comment.
Users will have to do the migration as existing images on the local will start failing - this is something that's needed, but not sure if we need to add this in the docs.
Copy the existing content/images|media|files into the bucket under the same prefix first
| | `staticFileURLPrefix` | Yes | Path prefix within the bucket that files are stored under, e.g. `content/images`. | | ||
| | `multipartUploadThresholdBytes` | Yes | Files larger than this size (in bytes) are uploaded using S3 multipart upload. | | ||
| | `multipartChunkSizeBytes` | Yes | Size (in bytes) of each multipart part. Must be at least 5 MiB (`5242880`). | | ||
| | `region` | No | Region of the bucket. | |
There was a problem hiding this comment.
NIT - Not a required field but AWS S3 needs it
Ghost now ships an
S3Storageadapter in core, but the config docs only listed third-party storage modules. This documents the built-in adapter and its full configuration options so operators can set up S3-compatible object storage (Amazon S3, MinIO, GCS, Cloudflare R2, etc.) without reverse-engineering the schema.ref https://linear.app/ghost/issue/HKG-1948
Test plan
pnpm lintpassesconfig.mdxwithpnpm dev, confirm the new "Ghost's built-in S3-compatible storage adapter" subsection renders under Storage adapters with the JSON block and options table intact