Skip to content
/ nuxtpress Public template

🌐 Blog Software powered by Nuxt UI v4

License

Notifications You must be signed in to change notification settings

gmitch215/nuxtpress

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

51 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

NuxtPress

Modern, fast, and beautiful blog software powered by Nuxt UI v4 and Cloudflare Workers

Deploy to NuxtHub


Table of Contents


For Everyone: Getting Started

What is NuxtPress?

NuxtPress is a modern blogging platform that's:

  • Fast: Built on Cloudflare's edge network for lightning-fast performance worldwide
  • Simple: Easy to deploy and use with a clean, intuitive interface
  • Secure: Password-protected admin panel with session management
  • Beautiful: Powered by Nuxt UI v4 for a stunning, responsive design
  • Free: Deploy on Cloudflare's free tier

Deploy Your Own Blog

Option 1: One-Click Deploy to NuxtHub (Recommended)

  1. Click the "Deploy to NuxtHub" button above
  2. Connect your GitHub account
  3. NuxtHub will automatically:
    • Fork this repository to your account
    • Set up Cloudflare Workers integration
    • Deploy your blog
    • Provision the database and KV storage
  4. Configure your blog settings (see below)
  5. Start writing!

Option 2: Manual Deployment

If you prefer to deploy manually:

  1. Fork this repository
  2. Create a NuxtHub account
  3. Link your repository to NuxtHub
  4. Deploy from the NuxtHub dashboard
  5. Configure environment variables (see below)

Configuration

After deployment, you'll need to configure your blog through environment variables:

Required Settings

Variable Description Default
NUXT_PASSWORD Admin password for logging in password

⚠️ Important: Change the default password immediately after deployment!

Optional Settings

These can be configured via environment variables or through the admin panel after logging in:

Variable Description Default
NUXT_PUBLIC_SITE_URL Your blog's public URL https://nuxtpress.pages.dev
NUXT_PUBLIC_NAME Your blog name NuxtPress
NUXT_PUBLIC_DESCRIPTION Blog description My NuxtPress blog
NUXT_PUBLIC_AUTHOR Author name Gregory Mitchell
NUXT_PUBLIC_THEME_COLOR Theme color (hex) #1e40af
NUXT_PUBLIC_FAVICON Favicon URL /_favicon.ico
NUXT_PUBLIC_FAVICON_PNG PNG favicon URL /_favicon.png
NUXT_PUBLIC_GITHUB GitHub profile URL (empty)
NUXT_PUBLIC_INSTAGRAM Instagram profile URL (empty)
NUXT_PUBLIC_TWITTER Twitter/X profile URL (empty)
NUXT_PUBLIC_PATREON Patreon profile URL (empty)
NUXT_PUBLIC_LINKEDIN LinkedIn profile URL (empty)
NUXT_PUBLIC_DISCORD Discord server URL (empty)
NUXT_PUBLIC_SUPPORT_EMAIL Support email address (empty)

How to set environment variables in NuxtHub:

  1. Go to your project on hub.nuxt.com
  2. Navigate to Settings β†’ Environment Variables
  3. Add your variables
  4. Redeploy your application

Installing updates from the template

If you used this repository as a template and want to pull updates from the original template repository, you can add the template as a remote and merge updates into your repository. The following snippet shows the minimal commands you may use.

# one time
git remote add template https://github.com/gmitch215/nuxtpress

# to install an update
git switch master
git fetch --all
git merge template --allow-unrelated-histories -m "chore: merge upstream"

Notes:

  • The first git remote add only needs to be run once per cloned repository.
  • Switch to the branch you want to update (here master) before merging.
  • --allow-unrelated-histories is included to allow merging between repositories that do not share history; resolve conflicts if they appear.
  • Always create a local backup branch before merging so you can recover easily if something goes wrong:
git switch -c before-template-merge

Examples for targeting a specific branch, tag, or commit

  • Merge a specific branch from the template (e.g. experimental):
git fetch template
git switch master
git merge template/experimental --allow-unrelated-histories -m "chore: merge template/experimental"
  • Merge a specific tag from the template (e.g. v1.0.2):
git fetch --tags template
git switch master
git merge template/v1.0.2 --allow-unrelated-histories -m "chore: merge template v1.0.2"

If you prefer to create a local branch that mirrors the tagged state, you can do:

git fetch --tags template
git checkout -b update-v1.0.2 template/v1.0.2
# Inspect changes, then merge into master if desired
git switch master
git merge update-v1.0.2
  • Apply a single commit from the template (e.g. ab12ef3):
git fetch template
git switch master
git cherry-pick ab12ef3

Alternatives and safety tips:

  • Instead of merging directly into master, consider creating a temporary update branch (git switch -c update-from-template) and test there before merging to your main branch.
  • If the template remote is updated frequently, run git fetch template to refresh refs before merging.
  • If you encounter conflicts, resolve them and then git commit to complete the merge.

Using Your Blog

Logging In

  1. Navigate to your blog URL
  2. Click the login button in the navigation
  3. Enter your password (the one you set in NUXT_PASSWORD)

Creating a Blog Post

  1. Log in to your blog
  2. Click "New Post" or navigate to /create
  3. Fill in:
    • Title: Your post title
    • Slug: URL-friendly version (auto-generated from title)
    • Content: Your post content (supports Markdown)
    • Tags: Comma-separated tags
    • Thumbnail (optional): Upload an image
  4. Click "Publish"

Managing Posts

  • Edit: Click on any post while logged in to edit it
  • Delete: Use the delete button on a post's edit page
  • View: All posts are automatically listed on your homepage

Customizing Settings

  1. Log in to your blog
  2. Navigate to /settings
  3. Update your blog information, social links, and appearance
  4. Changes are saved in your Cloudflare KV storage and take effect immediately

For Developers: Technical Documentation

Overview

NuxtPress is a full-stack blogging platform built with:

  • Frontend: Nuxt 4 with Vue 3, Nuxt UI v4, and Tailwind CSS
  • Backend: Nuxt server routes with Cloudflare Workers
  • Database: Cloudflare D1 (SQLite on the edge)
  • Storage: Cloudflare KV for caching and settings
  • Validation: Zod schemas for type-safe data validation
  • Deployment: NuxtHub for seamless Cloudflare integration

Tech Stack

Local Development

Prerequisites

  • Bun or Node.js 18+
  • A Cloudflare account (for deployment)

Setup

  1. Clone the repository:

    git clone https://github.com/gmitch215/nuxtpress.git
    cd nuxtpress
  2. Install dependencies:

    bun install
  3. Set up environment variables:

    cp .env.example .env

    Edit .env and set your NUXT_PASSWORD and other configuration.

  4. Run the development server:

    bun run dev
  5. Open http://localhost:8787

Available Scripts

  • bun run dev - Start development server on port 8787
  • bun run dev:test - Start dev server with test environment
  • bun run build - Build for production
  • bun run preview - Preview production build locally with NuxtHub
  • bun run prettier - Format code with Prettier
  • bun run prettier:check - Check code formatting

Project Structure

nuxtpress/
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ app.vue                 # Root application component
β”‚   β”œβ”€β”€ error.vue              # Error page component
β”‚   β”œβ”€β”€ assets/                # Static assets
β”‚   β”‚   └── css/main.css       # Global styles
β”‚   β”œβ”€β”€ components/            # Vue components
β”‚   β”‚   β”œβ”€β”€ BlogForm.vue       # Blog post creation/edit form
β”‚   β”‚   β”œβ”€β”€ BlogPostGroup.vue  # Blog post listing component
β”‚   β”‚   β”œβ”€β”€ Footer.vue         # Site footer
β”‚   β”‚   β”œβ”€β”€ LoginForm.vue      # Authentication form
β”‚   β”‚   β”œβ”€β”€ NavBar.vue         # Navigation bar
β”‚   β”‚   └── SettingsForm.vue   # Settings management form
β”‚   β”œβ”€β”€ composables/           # Vue composables
β”‚   β”‚   β”œβ”€β”€ useDatabase.ts     # Database utilities
β”‚   β”‚   └── useLogin.ts        # Authentication utilities
β”‚   β”œβ”€β”€ layouts/               # Nuxt layouts
β”‚   β”‚   └── default.vue        # Default layout
β”‚   β”œβ”€β”€ pages/                 # File-based routing
β”‚   β”‚   β”œβ”€β”€ index.vue          # Homepage (blog list)
β”‚   β”‚   └── [year]/            # Date-based blog routes
β”‚   β”‚       β”œβ”€β”€ index.vue      # Posts by year
β”‚   β”‚       └── [month]/
β”‚   β”‚           β”œβ”€β”€ index.vue  # Posts by month
β”‚   β”‚           └── [day]/
β”‚   β”‚               β”œβ”€β”€ index.vue    # Posts by day
β”‚   β”‚               └── [slug].vue   # Individual post
β”‚   β”œβ”€β”€ server/                # Server-side code
β”‚   β”‚   β”œβ”€β”€ utils.ts           # Server utilities
β”‚   β”‚   └── api/               # API routes
β”‚   β”‚       β”œβ”€β”€ login.post.ts  # User login
β”‚   β”‚       β”œβ”€β”€ logout.post.ts # User logout
β”‚   β”‚       β”œβ”€β”€ verify.get.ts  # Session verification
β”‚   β”‚       β”œβ”€β”€ settings.get.ts    # Get settings
β”‚   β”‚       β”œβ”€β”€ settings.post.ts   # Update settings
β”‚   β”‚       └── blog/          # Blog API endpoints
β”‚   β”‚           β”œβ”€β”€ create.post.ts  # Create post
β”‚   β”‚           β”œβ”€β”€ find.get.ts     # Find post by ID/slug
β”‚   β”‚           β”œβ”€β”€ list.get.ts     # List all posts
β”‚   β”‚           β”œβ”€β”€ update.patch.ts # Update post
β”‚   β”‚           └── remove.delete.ts # Delete post
β”‚   └── shared/                # Shared utilities
β”‚       β”œβ”€β”€ schemas.ts         # Zod validation schemas
β”‚       └── types.ts           # TypeScript types
β”œβ”€β”€ public/                    # Public static files
β”œβ”€β”€ nuxt.config.ts             # Nuxt configuration
β”œβ”€β”€ package.json               # Dependencies
└── tsconfig.json              # TypeScript configuration

API Documentation

All API routes are located in src/server/api/ and are automatically available at /api/*.

Authentication

POST /api/login

Authenticate with the admin password.

Request Body:

{
	"password": "your-password"
}

Response:

{
	"ok": true
}

Sets a secure session cookie valid for 30 days.

POST /api/logout

Invalidate the current session.

Response:

{
	"ok": true
}
GET /api/verify

Check if the current session is valid.

Response:

{
	"loggedIn": true
}

Settings

GET /api/settings

Get current blog settings (public endpoint).

Response:

{
	"name": "My Blog",
	"description": "Blog description",
	"author": "Author Name",
	"themeColor": "#1e40af",
	"favicon": "/favicon.ico",
	"faviconPng": "/favicon.png",
	"github": "https://github.com/username",
	"twitter": "https://twitter.com/username",
	"instagram": "https://instagram.com/username",
	"patreon": "https://patreon.com/username",
	"linkedin": "https://linkedin.com/in/username",
	"discord": "https://discord.gg/server-invite",
	"supportEmail": "support@example.com"
}
POST /api/settings

Update blog settings (requires authentication).

Request Body: Same as GET response (partial updates supported)

Response: Updated settings object

Blog Posts

GET /api/blog/list

Get all blog posts (public endpoint).

Response:

[
	{
		"id": "unique-id",
		"title": "Post Title",
		"slug": "post-slug",
		"content": "Post content...",
		"thumbnail_url": "data:image/png;base64,...",
		"created_at": "2025-11-17T00:00:00.000Z",
		"updated_at": "2025-11-17T00:00:00.000Z",
		"tags": ["tag1", "tag2"]
	}
]
GET /api/blog/find

Find a specific blog post by ID or slug.

Query Parameters:

  • id (optional): Post ID
  • slug (optional): Post slug

Response: Single blog post object (same structure as list)

POST /api/blog/create

Create a new blog post (requires authentication).

Request Body:

{
	"post": {
		"title": "Post Title",
		"slug": "post-slug",
		"content": "Post content...",
		"thumbnail": "base64-encoded-image-data",
		"tags": ["tag1", "tag2"]
	}
}

Response: Created blog post object

Note: Slugs are automatically made unique by appending -1, -2, etc. if duplicates exist.

PATCH /api/blog/update

Update an existing blog post (requires authentication).

Request Body:

{
	"id": "post-id",
	"post": {
		"title": "Updated Title",
		"content": "Updated content...",
		"tags": ["updated-tags"]
	}
}

Response: Updated blog post object

DELETE /api/blog/remove

Delete a blog post (requires authentication).

Query Parameters:

  • id: Post ID to delete

Response:

{
	"ok": true
}

Database Schema

NuxtPress uses Cloudflare D1 with the following schema:

blog_posts Table

CREATE TABLE IF NOT EXISTS blog_posts (
  id TEXT PRIMARY KEY,
  title TEXT NOT NULL,
  slug TEXT NOT NULL UNIQUE,
  content TEXT NOT NULL,
  thumbnail BLOB,
  created_at INTEGER NOT NULL,
  updated_at INTEGER NOT NULL,
  tags TEXT NOT NULL
);

Fields:

  • id: Unique identifier (UUID)
  • title: Post title
  • slug: URL-friendly slug (must be unique)
  • content: Post content (Markdown supported)
  • thumbnail: Optional image thumbnail (stored as BLOB)
  • created_at: Unix timestamp of creation
  • updated_at: Unix timestamp of last update
  • tags: JSON-encoded array of tags

Contributing

Contributions are welcome! Here's how to get started:

  1. Fork the repository

    git clone https://github.com/YOUR-USERNAME/nuxtpress.git
  2. Create a feature branch

    git checkout -b feature/amazing-feature
  3. Make your changes

    • Follow the existing code style
    • Run bun run prettier before committing
    • Ensure types are correct with TypeScript
  4. Commit your changes

    git commit -m "feat: add amazing feature"

    Follow Conventional Commits format.

  5. Push and create a Pull Request

    git push origin feature/amazing-feature

Development Guidelines

  • Code Style: Prettier is configured and runs automatically on commit via Husky
  • TypeScript: Strict mode is enabled; ensure all types are correct
  • Components: Use Nuxt UI components when possible for consistency
  • API Routes: Use Zod schemas for validation
  • Server Utils: Helper functions are in src/server/utils.ts
  • Database: Always use parameterized queries to prevent SQL injection

License

This project is open source and available under the MIT License.

About

🌐 Blog Software powered by Nuxt UI v4

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Sponsor this project