Alternate Futures
Retired af CLI guides

Deploy an Astro Site

Legacy guide - retired af CLI

This page was written for the retired af CLI and the sites/storage workflow. The current CLI is acc (compute services), which does not include these commands yet. Commands on this page will not work with acc. Kept for reference while this functionality is rebuilt.

Deploy your Astro site to decentralized infrastructure using Alternate Futures. Astro's static-first architecture makes it an excellent fit for decentralized hosting.

Prerequisites

Before you begin, make sure you have:

  • An Alternate Futures account - Sign up here (free, no credit card required)
  • The AF CLI installed - npm install -g @alternatefutures/cli
  • Node.js 18 or later - Download here
  • An Astro project (or we will create one below)

Quick Deploy (Existing Astro Project)

If you already have an Astro project, deploy it in three commands:

# Build the production output
npm run build

# Initialize AF configuration
af sites init

# Deploy to IPFS
af sites deploy

Output Directory

Astro outputs to ./dist by default. When running af sites init, set the output directory to dist.

Step 1: Create a New Astro Project

If you do not have a project yet, start from our template or create one from scratch.

# Clone the AF-optimized Astro template
git clone https://github.com/alternatefutures/template-astro my-astro-site
cd my-astro-site

# Install dependencies
npm install

Option B: Create from Scratch

# Create a new Astro project
npm create astro@latest my-astro-site
cd my-astro-site

# Install dependencies
npm install

When prompted by the Astro CLI, choose your preferred template (blog, portfolio, minimal, etc.).

Step 2: Verify Static Output

Astro generates static HTML by default, which is exactly what you need for decentralized hosting. Verify your astro.config.mjs is set to static output:

import { defineConfig } from 'astro/config';

export default defineConfig({
  // Static output is the default - no 'output' setting needed
  // output: 'static',  // This is the default

  // Optional: Set the site URL for canonical links and sitemap
  site: 'https://my-astro-site.com',

  // Optional: Set a base path if deploying to a subdirectory
  // base: '/my-site/',
});

SSR Mode

If your project uses output: 'server' or output: 'hybrid', you will need to change it to output: 'static' (or remove the output option entirely) for decentralized hosting. Server-rendered pages require a runtime server, which is not available on static hosting.

To convert SSR pages to static:

  • Replace export const prerender = false with export const prerender = true (or remove it)
  • Move dynamic data fetching to client-side JavaScript
  • Use getStaticPaths() for dynamic routes

What Works with Static Astro

FeatureSupportedNotes
Static pages (.astro)YesFull support
Markdown/MDX contentYesFull support
Content CollectionsYesFull support
View TransitionsYesClient-side navigation
React/Vue/Svelte islandsYesHydration works normally
getStaticPaths()YesDynamic routes at build time
Image optimizationYesBuilt-in <Image /> component
CSS/TailwindYesFull support
SSR (output: 'server')NoUse static output instead
Server endpointsNoUse external API or cloud functions

Step 3: Build Your Project

# Build the static output
npm run build

# Preview locally (optional)
npm run preview

The build output will be in the ./dist directory.

Step 4: Authenticate with AF

If you have not already authenticated:

# Interactive login (opens browser)
af login

# Or use a Personal Access Token
export AF_TOKEN=pat_your_token_here

Step 5: Initialize and Deploy

# Initialize AF site configuration
af sites init

# When prompted, configure:
#   Site name: my-astro-site
#   Build command: npm run build
#   Output directory: dist
#   Storage network: ipfs (recommended for getting started)

# Deploy to decentralized storage
af sites deploy

You should see output like:

  Building site...
  Uploading files to IPFS...
  Deployment successful!
  CID: bafybei...
  URL: https://ipfs.io/ipfs/bafybei...

Step 6: Set Up a Custom Domain (Optional)

Point your own domain to your deployment:

# Add a custom domain
af domains add my-astro-site.com --site my-astro-site

Then configure your DNS:

Record TypeNameValue
CNAME@Your AF gateway URL
TXT_dnslinkdnslink=/ipfs/<your-cid>

See Custom Domains for detailed DNS configuration.

Using Astro Integrations

Astro's integration ecosystem works seamlessly with Alternate Futures. Here are common setups:

Tailwind CSS

# Add Tailwind integration
npx astro add tailwind

No additional configuration needed for deployment.

React Components (Islands)

# Add React integration
npx astro add react

Use React components as interactive islands within your Astro pages:

---
import Counter from '../components/Counter.tsx';
---

<html>
  <body>
    <h1>My Astro Site</h1>
    <!-- This React component hydrates on the client -->
    <Counter client:load />
  </body>
</html>

Sitemap

# Add sitemap integration
npx astro add sitemap

Make sure to set the site property in astro.config.mjs:

import { defineConfig } from 'astro/config';
import sitemap from '@astrojs/sitemap';

export default defineConfig({
  site: 'https://my-astro-site.com',
  integrations: [sitemap()],
});

Automating Deployments with CI/CD

Deploy automatically on every push using GitHub Actions:

# .github/workflows/deploy.yml
name: Deploy to Alternate Futures

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'

      - name: Install dependencies
        run: npm install

      - name: Build
        run: npm run build

      - name: Deploy to AF
        run: npx @alternatefutures/cli sites deploy ./dist --network ipfs
        env:
          AF_TOKEN: ${{ secrets.AF_TOKEN }}

See CI/CD Integration for more providers.

Using the SDK

Deploy programmatically with the Alternate Futures SDK:

import { AlternateFuturesSdk, PersonalAccessTokenService } from '@alternatefutures/sdk/node';

const af = new AlternateFuturesSdk({
  accessTokenService: new PersonalAccessTokenService({
    personalAccessToken: process.env.AF_TOKEN,
    projectId: process.env.AF_PROJECT_ID,
  }),
});

// Deploy the build output
const result = await af.ipfs().add('./dist');
console.log('Deployed! CID:', result.pin.cid);

Common Issues

"Build fails with 'Cannot use import statement outside a module'"

Make sure your package.json includes "type": "module" (Astro requires ESM).

"Images not loading after deployment"

  • Use Astro's built-in <Image /> component for optimized images
  • Make sure image paths are relative, not absolute
  • If using public/ folder images, reference them with a leading /
---
import { Image } from 'astro:assets';
import myImage from '../assets/hero.png';
---

<!-- Optimized image (recommended) -->
<Image src={myImage} alt="Hero image" />

<!-- Public folder image -->
<img src="/images/logo.png" alt="Logo" />

"Dynamic routes return 404"

Make sure all dynamic routes use getStaticPaths():

---
// src/pages/blog/[slug].astro
export async function getStaticPaths() {
  const posts = await getCollection('blog');
  return posts.map(post => ({
    params: { slug: post.slug },
    props: { post },
  }));
}

const { post } = Astro.props;
---

<h1>{post.data.title}</h1>

"Content Collections not building"

  • Verify your content is in the src/content/ directory
  • Check that src/content/config.ts defines your collections correctly
  • Run astro check to validate your project

"Build output is unexpectedly large"

  • Use astro build --verbose to see what is being included
  • Remove unused integrations
  • Optimize images before adding them to your project
  • Use Astro's built-in image optimization

Next Steps

On this page