Lightweight, Git-based Content Management System built with Astro and Cloudflare Workers
A minimal, decoupled CMS that manages Markdown/MDX content via GitHub API, designed for modern static sites.
- Git-based: changes commit directly to a configured GitHub branch
- Cloudflare Access first: the Worker fails closed when Access is not configured
- Cloudflare Workers: private self-hosted CMS for one team
- Type-safe config: TypeScript config validated at runtime with Valibot
- Optional R2 uploads: image fields fall back to URL input when R2 is not configured
- Multi-project: manage multiple GitHub repositories from one CMS
# Clone the repository
git clone https://github.com/yourusername/simplegitcms.git
cd simplegitcms
# Install dependencies
pnpm install
# Copy example config
cp simplegitcms.config.example.ts simplegitcms.config.ts
# Edit configuration (add your GitHub repo details)
nano simplegitcms.config.ts
# Set environment variables
cp .env.example .env
nano .env
# Run development server
pnpm devCreate a simplegitcms.config.ts file:
import { defineConfig } from './src/lib/config/types';
export default defineConfig({
projects: [
{
id: 'my-blog',
label: 'My Blog',
repository: {
type: 'github',
owner: 'your-username',
repo: 'blog-content',
branch: 'main',
tokenEnv: 'GITHUB_TOKEN',
},
// Optional image uploads. Omit this block to use URL-only image fields.
// assets: {
// r2: {
// binding: 'CMS_UPLOADS',
// publicUrl: 'https://assets.example.com',
// },
// },
collections: [
{
name: 'posts',
label: 'Blog Posts',
folder: 'src/content/posts',
extension: 'mdx',
fields: [
{ name: 'title', label: 'Title', type: 'string', required: true },
{ name: 'description', label: 'Description', type: 'text', required: true },
{ name: 'body', label: 'Content', type: 'markdown', required: true },
],
},
],
},
],
});- Go to GitHub Settings → Fine-grained tokens
- Create new token with:
- Repository access: Only select repositories
- Permissions: Contents (Read and write)
- Add to
.env:
GITHUB_TOKEN=github_pat_xxxxxxxxxxxxx
CMS_AUTH_DISABLED=true
ENVIRONMENT=development# Install Wrangler
npm install -g wrangler
# Login
wrangler login
# Set secrets
wrangler secret put GITHUB_TOKEN
# Build and deploy
pnpm build
wrangler deployProtect the deployed Worker with Cloudflare Access and set:
CF_ACCESS_TEAM_DOMAIN=yourteam.cloudflareaccess.com
CF_ACCESS_AUD=your-access-aud- Access your CMS at the deployed URL
- Select a project from the dashboard
- Choose a collection
- Create/edit/delete files
- Changes are automatically committed to GitHub
simplegitcms/
├── src/
│ ├── components/ # UI components
│ ├── lib/ # Core libraries
│ │ ├── config/ # Configuration system
│ │ ├── services/ # Config/auth/repository/content/assets boundaries
│ │ └── github/ # GitHub API client
│ └── pages/ # Astro pages & API routes
├── simplegitcms.config.ts # Your configuration
├── wrangler.jsonc # Cloudflare config
└── package.json
string- Single-line texttext- Multi-line textmarkdown- Markdown editor (body content)number- Numeric inputboolean- True/falseselect- Dropdown with optionslist- Array of valuesdatetime- Date/time pickerimage- URL string, with upload control only when project R2 assets are configured
- Use Cloudflare Access for authentication
- Use fine-grained GitHub tokens with minimal permissions
- Never commit tokens to git
- All changes are audited in git history
MIT