All reports
by deep-research

astro cloudflare pages moklabs portfolio

Research: Astro 5.x + Cloudflare — Multi-Product Portfolio Site for moklabs.io

MOKA-346 | Priority: Medium | Project: Research Date: 2026-03-20 Author: Deep Research Agent Supports: moklabs.io Landing Page — Build and deploy Astro site


Executive Summary

moklabs.io needs a multi-product portfolio site showcasing 6 AI products. This report covers Astro 5.x architecture, Cloudflare deployment (Pages vs Workers), performance optimization, SEO setup, and messaging patterns for AI venture studios.

Key Decision: Deploy as Astro static site on Cloudflare Workers (not Pages — Astro adapter dropped Pages support in 2026). Use Content Collections for product data and Cloudflare Web Analytics + Zaraz for privacy-friendly analytics.


1. Astro 5.x Architecture for Multi-Product Sites

1.1 Why Astro for moklabs.io

  • Zero JS by default — Pure HTML output, instant page loads
  • Islands Architecture — Interactive components only where needed (product demos, animations)
  • Content Collections — Type-safe structured data for products, team, blog
  • 5x faster builds in Astro 5.0 vs 4.x (Content Layer API)
  • 25-50% less memory during build
  • Native image optimization — WebP/AVIF generation, responsive sizes

1.2 Content Collections Structure

src/
├── content/
│   ├── products/
│   │   ├── argus.md
│   │   ├── octantos.md
│   │   ├── remindr.md
│   │   ├── narrativ.md
│   │   ├── neuron.md
│   │   └── agentscope.md
│   ├── team/
│   │   └── ...
│   └── blog/
│       └── ...
├── content.config.ts
└── pages/
    ├── index.astro          # Hero + product grid
    ├── products/
    │   └── [slug].astro     # Product detail pages
    ├── about.astro
    ├── blog/
    │   ├── index.astro
    │   └── [slug].astro
    └── contact.astro

1.3 Product Content Schema

// src/content.config.ts
import { defineCollection, z } from 'astro:content'
import { glob } from 'astro/loaders'

const products = defineCollection({
  loader: glob({ pattern: '**/*.md', base: './src/content/products' }),
  schema: z.object({
    name: z.string(),
    tagline: z.string(),
    description: z.string(),
    category: z.enum(['security', 'developer-tools', 'productivity', 'creative', 'ai-infra', 'knowledge']),
    status: z.enum(['launch-ready', 'beta', 'mvp', 'phase-0']),
    icon: z.string(),
    color: z.string(),
    features: z.array(z.object({
      title: z.string(),
      description: z.string(),
    })),
    cta: z.object({
      text: z.string(),
      url: z.string(),
    }),
    order: z.number(), // GTM priority order
  }),
})

export const collections = { products }

2. Cloudflare Deployment

2.1 Pages vs Workers (Critical Decision)

As of 2026, the Astro Cloudflare adapter (@astrojs/cloudflare) no longer supports Cloudflare Pages. Cloudflare recommends Workers for new projects.

FeatureCloudflare WorkersCloudflare Pages (Legacy)
Astro adapter supportYes (current)No (dropped in 2026)
Static sitesYes (assets directory)Yes
SSR/on-demandYes (full support)Limited
Preview deploysVia WranglerBuilt-in with GitHub
Custom domainsYesYes
Web AnalyticsYesYes
Build-in CI/CDNo (use GitHub Actions)Yes (GitHub integration)

Recommendation for moklabs.io:

  • Static site (SSG) — No adapter needed, deploy directly via Wrangler
  • Deploy to Cloudflare Workers with assets
  • Use GitHub Actions for CI/CD (build + wrangler deploy)

2.2 Deployment Setup

// wrangler.jsonc
{
  "name": "moklabs-io",
  "compatibility_date": "2026-03-01",
  "assets": {
    "directory": "./dist"
  }
}
# .github/workflows/deploy.yml
name: Deploy to Cloudflare
on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: pnpm/action-setup@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: pnpm
      - run: pnpm install
      - run: pnpm build
      - uses: cloudflare/wrangler-action@v3
        with:
          apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
          command: deploy

2.3 Custom Domain Setup

# Add custom domain via Wrangler CLI
npx wrangler domains add moklabs.io
# Or configure in Cloudflare dashboard:
# Workers & Pages → moklabs-io → Settings → Domains

DNS (already on Cloudflare): Add CNAME moklabs.io → moklabs-io.<account>.workers.dev


3. Performance Optimization

3.1 Target: Lighthouse 95+ on All Metrics

MetricTargetStrategy
LCP< 2.5sPreload hero image, inline critical CSS
FID/INP< 100msZero JS default, islands only for interactive
CLS< 0.1Explicit image dimensions, font-display: swap
TTFB< 200msCloudflare edge serving, static HTML

3.2 Image Optimization

---
// Use Astro's built-in Image component
import { Image } from 'astro:assets'
import heroImage from '../assets/hero.png'
---

<!-- Above-fold: eager loading -->
<Image
  src={heroImage}
  alt="Moklabs AI Products"
  width={1200}
  height={630}
  loading="eager"
  format="avif"
  quality={80}
/>

<!-- Below-fold: lazy loading -->
<Image
  src={productImage}
  alt={product.name}
  width={600}
  height={400}
  loading="lazy"
  format="webp"
/>

3.3 Font Optimization

---
// Use astro-google-fonts-optimizer or self-host
---
<head>
  <!-- Self-hosted fonts (recommended for privacy + performance) -->
  <link rel="preload" href="/fonts/inter-var.woff2" as="font" type="font/woff2" crossorigin>
  <style>
    @font-face {
      font-family: 'Inter';
      src: url('/fonts/inter-var.woff2') format('woff2');
      font-weight: 100 900;
      font-display: swap;
    }
  </style>
</head>

3.4 Critical CSS

# Install critical CSS extraction
pnpm add -D critical

# Add to build pipeline (astro.config.mjs integration or post-build script)

4. SEO Setup

4.1 Essential Integrations

pnpm add @astrojs/sitemap astro-robots-txt astro-seo
// astro.config.mjs
import { defineConfig } from 'astro/config'
import sitemap from '@astrojs/sitemap'
import robotsTxt from 'astro-robots-txt'

export default defineConfig({
  site: 'https://moklabs.io',
  integrations: [
    sitemap({
      filter: (page) => !page.includes('/draft/'),
    }),
    robotsTxt(),
  ],
})

4.2 Meta Tags Template

---
// src/layouts/BaseLayout.astro
import { SEO } from 'astro-seo'

interface Props {
  title: string
  description: string
  image?: string
}

const { title, description, image = '/og-default.png' } = Astro.props
const canonicalURL = new URL(Astro.url.pathname, Astro.site)
---

<html lang="en">
<head>
  <SEO
    title={`${title} | Moklabs`}
    description={description}
    canonical={canonicalURL.href}
    openGraph={{
      basic: {
        title: `${title} | Moklabs`,
        type: 'website',
        image: new URL(image, Astro.site).href,
      },
      optional: {
        description,
        siteName: 'Moklabs',
      },
    }}
    twitter={{
      card: 'summary_large_image',
      title: `${title} | Moklabs`,
      description,
      image: new URL(image, Astro.site).href,
    }}
  />
  <!-- JSON-LD Structured Data -->
  <script type="application/ld+json" set:html={JSON.stringify({
    "@context": "https://schema.org",
    "@type": "Organization",
    "name": "Moklabs",
    "url": "https://moklabs.io",
    "description": "AI venture studio building privacy-first products",
    "foundingDate": "2026",
    "sameAs": ["https://github.com/moklabs"],
  })} />
</head>

4.3 Product JSON-LD

<!-- On product detail pages -->
<script type="application/ld+json" set:html={JSON.stringify({
  "@context": "https://schema.org",
  "@type": "SoftwareApplication",
  "name": product.name,
  "description": product.description,
  "applicationCategory": "SecurityApplication",
  "operatingSystem": "macOS, Windows, Linux",
  "offers": {
    "@type": "Offer",
    "price": "0",
    "priceCurrency": "USD",
  },
  "author": {
    "@type": "Organization",
    "name": "Moklabs",
  },
})} />

5. Analytics Setup (Privacy-Friendly)

5.1 Cloudflare Web Analytics

Free, privacy-first, no cookies, GDPR-compliant by default.

Setup for Workers deployment:

  1. Go to Cloudflare Dashboard → Web Analytics
  2. Create a site for moklabs.io
  3. Get the JS snippet or beacon token
  4. Add to Astro layout:
<!-- src/layouts/BaseLayout.astro -->
<body>
  <slot />
  <!-- Cloudflare Web Analytics -->
  <script
    defer
    src="https://static.cloudflareinsights.com/beacon.min.js"
    data-cf-beacon='{"token": "YOUR_TOKEN"}'
  />
</body>

5.2 Zaraz (Optional — for additional tools)

Zaraz offloads third-party scripts to Cloudflare’s edge:

  • Google Analytics without client-side GA script
  • Meta Pixel, LinkedIn Insight, etc.
  • Requires custom domain (moklabs.io)
  • Enable in Dashboard → Zaraz → Settings

Note: Zaraz requires a custom domain associated with the project.


6. Messaging Framework for AI Venture Studio

6.1 Portfolio Site Messaging Patterns (from existing research)

Based on our earlier research on AI Venture Studio Portfolio Sites:

Hero messaging formula:

[What we build] + [Who benefits] + [Why it matters]

Example for Moklabs:

“Privacy-first AI products for teams that refuse to compromise. Six products. One mission. Your data stays yours.”

6.2 Product Grid Strategy

ElementPattern
Card layoutIcon + Name + Tagline + Status badge + CTA
OrderingBy GTM priority (Argus → OctantOS → Remindr → Narrativ → Neuron → AgentScope)
Status badges”Launch Ready”, “Beta”, “MVP”, “Coming Soon”
CTA hierarchyPrimary: “Try Argus” / Secondary: “Learn More”

6.3 Trust Signals

  1. Open source — Link to GitHub repos (credibility for developers)
  2. Privacy-first — “All processing happens on your device” (differentiator)
  3. Built with AI — “Moklabs is an AI-native venture studio. Our agents write code, review PRs, and ship features.” (unique story)
  4. Real products — Show screenshots, demos, or GIFs (not just descriptions)

6.4 Page Structure Recommendation

Homepage:
├── Hero (tagline + product count + primary CTA)
├── Product Grid (6 cards, GTM order)
├── Philosophy/Approach (privacy-first, AI-native, open source)
├── Tech Stack / Architecture (for developer credibility)
├── Blog Preview (latest 3 posts)
└── Footer (GitHub, contact, newsletter)

Product Detail (/products/argus):
├── Hero (screenshot + tagline + CTAs)
├── Problem Statement
├── Features (3-5 key features with visuals)
├── How It Works (architecture diagram)
├── Pricing (if applicable)
└── Get Started CTA

{
  "dependencies": {
    "astro": "^5.6",
    "@astrojs/sitemap": "^3.5",
    "@astrojs/tailwind": "^6.0",
    "astro-seo": "^0.8",
    "astro-robots-txt": "^1.0",
    "tailwindcss": "^4.0"
  },
  "devDependencies": {
    "wrangler": "^4.0",
    "sharp": "^0.33",
    "critical": "^8.0"
  }
}

Note: No @astrojs/cloudflare adapter needed for static sites. Just build and deploy via Wrangler.


8. Risk Assessment

RiskLikelihoodImpactMitigation
Astro Pages adapter deprecation confusionMediumLowUse Workers directly; no adapter needed for static
AVIF generation slow on CIMediumLowPre-optimize images; use WebP as default, AVIF as bonus
Zaraz requires custom domain setupLowLowSet up custom domain first; use CF Web Analytics as fallback
Content Collections schema changes in Astro 5.xLowLowPin Astro version; review changelogs before upgrading

Sources