Quick Start

Meridian requires PostgreSQL 16 and optionally Redis for caching. The fastest way to get started is Docker Compose, which handles everything for you.

Prerequisites: Docker and Docker Compose installed, or Deno 2.x and PostgreSQL 16 for local development.

$ git clone https://github.com/meridian-blog/meridian.git $ cd meridian $ cp .env.example .env $ make dev

Open http://localhost:8000 and log in with the default admin credentials. Change these immediately in production.

SettingDefault
Admin Emailadmin@meridian.blog
Admin Passwordchangeme123
App Port8000

Docker Deployment

The included docker-compose.yml sets up PostgreSQL, Redis, and the Meridian app. This is the recommended way to run Meridian in production.

Production Setup

# Clone and configure $ git clone https://github.com/meridian-blog/meridian.git $ cd meridian $ cp .env.example .env # Edit .env with production values $ nano .env # Start in production mode $ docker compose up -d # View logs $ docker compose logs -f app

Docker Commands

CommandDescription
make devStart all services (development)
make stopStop all services
make logsTail application logs
make db-shellOpen PostgreSQL shell
make db-resetReset database (destroys all data)

Warning: make db-reset destroys all data. Always back up your database before running this in production.

Local Development (Deno)

If you prefer running without Docker, install Deno 2.x and have a PostgreSQL 16 instance available.

# Install Deno (macOS/Linux) $ curl -fsSL https://deno.land/install.sh | sh # Configure $ cp .env.example .env # Edit DATABASE_URL to point to your PostgreSQL # Run migrations and seed admin user $ deno task db:migrate # Start dev server with hot reload $ deno task dev

Development Commands

CommandDescription
deno task devDev server with hot reload
deno task testRun all tests
deno task db:migrateRun database migrations
deno task db:seedSeed sample content
deno fmtFormat code
deno lintLint code

Configuration

All configuration is via environment variables. Copy .env.example to .env and edit as needed.

Required Variables

# Admin credentials (used during first migration) ADMIN_EMAIL=admin@meridian.blog ADMIN_PASSWORD=your-secure-password ADMIN_NAME=Admin # Application secret (minimum 32 characters) APP_SECRET=change-this-to-a-random-string # Database connection DATABASE_URL=postgres://meridian:secret@localhost:5432/meridian

Optional Variables

# Payments STRIPE_SECRET_KEY=sk_live_... STRIPE_WEBHOOK_SECRET=whsec_... # Email (for newsletters) EMAIL_PROVIDER=resend EMAIL_API_KEY=re_... EMAIL_FROM=newsletter@yourdomain.com # Redis (optional, for caching) REDIS_URL=redis://localhost:6379

Tip: Without email configured, newsletters log to console — useful for local development.

Stripe Setup

Meridian integrates with Stripe for member subscriptions. You connect your own Stripe account and keep 100% of revenue (minus Stripe's standard processing fees).

  • Create a Stripe account
  • Add your STRIPE_SECRET_KEY to .env
  • Create subscription tiers in the Meridian admin dashboard
  • Set up a webhook endpoint at https://yourdomain.com/api/stripe/webhook
  • Subscribe to events: checkout.session.completed, customer.subscription.updated, customer.subscription.deleted, invoice.payment_failed
  • Add the STRIPE_WEBHOOK_SECRET to .env

Meridian auto-creates Stripe Products and Prices from your tiers — no manual Stripe dashboard configuration needed beyond the initial API key setup.

Email Setup

Meridian supports multiple email providers for sending newsletters. Resend is recommended for its developer experience and deliverability.

  • Create a Resend account and verify your domain
  • Set EMAIL_PROVIDER=resend in your .env
  • Add your EMAIL_API_KEY
  • Set EMAIL_FROM to your verified sender address

Deliverability: Meridian enforces DKIM/DMARC/SPF and includes one-click unsubscribe headers for Gmail/Yahoo compliance.

Deploy to Railway

Railway provides the simplest deployment experience with managed PostgreSQL and automatic SSL.

  • Click the "Deploy on Railway" button on our GitHub repo
  • Railway auto-provisions PostgreSQL and Redis
  • Set your environment variables in the Railway dashboard
  • Add a custom domain (optional, Railway provides a free subdomain)
# Or deploy via Railway CLI $ railway login $ railway init $ railway add --plugin postgresql $ railway up

Estimated cost: Railway's Hobby plan ($5/mo) is sufficient for most publications under 10,000 monthly views.

Deploy to Fly.io

Fly.io deploys your app globally on micro-VMs with automatic edge routing. Great for publications with a global audience.

# Install Fly CLI $ curl -L https://fly.io/install.sh | sh # Launch the app $ fly launch # Create a PostgreSQL database $ fly postgres create $ fly postgres attach # Set environment variables $ fly secrets set APP_SECRET="your-secret-here" $ fly secrets set ADMIN_EMAIL="admin@yourdomain.com" $ fly secrets set ADMIN_PASSWORD="your-secure-password" # Deploy $ fly deploy

Deploy to Render

Render auto-deploys from GitHub and offers a free PostgreSQL tier — ideal for getting started at no cost.

  • Fork the Meridian repository on GitHub
  • Create a new Web Service on Render, connected to your fork
  • Add a PostgreSQL database (free tier available)
  • Set environment variables in the Render dashboard
  • Render auto-deploys on every push to main

Note: Render's free PostgreSQL tier expires after 90 days. Upgrade to a paid tier for production use.

API Reference

Meridian exposes a REST API for all operations and a GraphQL endpoint for content queries.

Public Endpoints (No Auth)

MethodEndpointDescription
GET/api/public/siteSite settings and social links
GET/api/public/postsPublished posts (paginated)
GET/api/public/posts/:slugSingle post by slug
GET/api/public/tagsAll tags with post counts
GET/api/public/pages/:slugStatic page
GET/api/public/search?q=Full-text search
GET/api/public/rssRSS 2.0 feed
POST/api/public/subscribeNewsletter signup

Admin Endpoints (JWT Required)

MethodEndpointDescription
GET/POST/api/postsList or create posts
PUT/DELETE/api/posts/:idUpdate or delete a post
GET/POST/api/pagesList or create pages
GET/api/membersList members
POST/api/newsletters/:id/sendSend a newsletter
GET/api/analytics/dashboardDashboard statistics
GET/PUT/api/settingsSite settings

Stripe Endpoints

MethodEndpointDescription
GET/api/stripe/tiersActive subscription tiers
POST/api/stripe/checkoutCreate checkout session
POST/api/stripe/portalCustomer billing portal
POST/api/stripe/webhookStripe webhook handler

GraphQL

Available at /graphql in development mode. Supports content queries with personalization and member context.

# Example query { posts(filter: { status: "published", limit: 10 }) { edges { node { title slug excerpt publishedAt author { name } tags { name } } } pageInfo { hasNextPage } } }

Updating Meridian

Pull the latest changes and restart. Migrations run automatically on startup.

# Docker $ git pull origin main $ docker compose up -d --build # Local Deno $ git pull origin main $ deno task db:migrate $ deno task dev

Backup first: Always back up your database before updating. pg_dump meridian > backup.sql