src/content/blog/ as .mdoc files alongside their cover images in public/blog/images/. Every publish action becomes a GitHub Pull Request, and merging that PR triggers a Netlify deployment. This keeps the entire content history in git, makes rollbacks trivial, and ensures the CMS never drifts out of sync with the codebase.
Storage modes
Keystatic switches storage backends based on theNODE_ENV environment variable. The logic lives at the top of keystatic.config.ts:
Local storage (development)
In local mode Keystatic is effectively a local GUI for editing files undersrc/content/blog/. Changes are written directly to disk — commit or discard them with git as you would any other file.
GitHub storage (production)
In production Keystatic authenticates via Keystatic Cloud (projectborrissol/borrissol) and uses the GitHub API to:
- Create a new branch with the prefix
keystatic/(e.g.keystatic/blog-nou-taller-tufting) - Commit the new or updated MDX file and any uploaded images to that branch
- Open a Pull Request against
main
Full configuration
keystatic.config.ts
Blog collection schema
Each blog entry has five fields:The blog is Catalan-only by design. There are no translated versions of blog posts. Non-Catalan
/es/blog, /en/blog, and /fr/blog URLs 301-redirect to /blog — see the redirects in astro.config.mjs.Author workflow: publishing a new post
1
Open the admin UI
Navigate to
https://borrissol.com/keystatic in your browser. Keystatic Cloud will prompt for authentication if you are not already signed in. (In local dev, no login is required — go to http://localhost:4321/keystatic.)2
Create a new entry
In the left sidebar, click Blog, then click New entry in the top-right corner.
3
Fill in the fields
Complete all five fields:
- Títol — the post title. The URL (slug) is filled automatically from the title; edit it manually if needed (lowercase, hyphens, no accents).
- Resum — a summary of up to 160 characters. This appears as the card blurb on the blog listing page and as the SEO meta description. The field validates the character limit in real time.
- Data de publicació — choose the date the post should appear to have been published.
- Imatge destacada — upload the cover image. Minimum recommended size: 1200 × 630 px (standard Open Graph dimensions). The image is saved to
public/blog/images/in the repository. - Contingut — write the post body using the rich-text Markdoc editor.
4
Save the entry
Click Save. In production mode, Keystatic creates a new branch (
keystatic/...) and commits the MDX file and any uploaded images to it, then opens a Pull Request on GitHub against main.5
Merge the Pull Request
Review the PR on github.com/constanza101/borrissol. Once satisfied, merge it. Netlify detects the push to
main and automatically deploys the updated site — the new post is live within a few minutes.Deploy and cost considerations
Cover image bandwidth
Cover images are stored inpublic/blog/images/[slug]/ and served directly from Netlify’s CDN. On the Personal plan, bandwidth is limited to ~50 GB/month (≈ 20 credits/GB). High-resolution images multiply quickly if the blog gets traffic. Optimise images before uploading:
- Use WebP or JPEG at 80–85% quality
- Resize to no wider than 2400 px before uploading
- Astro’s
<Picture>component will still generate AVIF/WebP variants at build time
Deploy previews for keystatic/* branches
Deploy previews for keystatic/ branches are disabled to avoid consuming credits on every draft save. Only merges to main trigger a production deploy.
Local dev workflow
Innpm run dev mode, Keystatic uses local storage. Editing posts in the admin UI at http://localhost:4321/keystatic writes files directly to disk with no authentication and no Netlify credits consumed. This is the recommended way to draft and proof content before committing.