Deploy a React app
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 React application to decentralized infrastructure using Alternate Futures. This guide covers both Vite-based and Create React App projects.
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
- A React project (or we will create one below)
Quick Deploy (Existing React Project)
If you already have a React project, deploy it in three commands:
# Build the production bundle
npm run build
# Initialize AF configuration
af sites init
# Deploy to IPFS
af sites deployOutput Directory
- Vite projects output to
./distby default - Create React App projects output to
./buildby default
Set the correct directory when running af sites init.
Step 1: Create a New React Project
If you do not have a project yet, start from our template or create one from scratch.
Option A: Use the AF Template (Recommended)
# Clone the AF-optimized React template
git clone https://github.com/alternatefutures/template-react my-react-app
cd my-react-app
# Install dependencies
npm installOption B: Create with Vite (Recommended)
# Create a new React + Vite project
npm create vite@latest my-react-app -- --template react-ts
cd my-react-app
# Install dependencies
npm installOption C: Create with Create React App
# Create a new CRA project
npx create-react-app my-react-app --template typescript
cd my-react-app
# Install dependencies
npm installStep 2: Configure for Deployment
Vite Configuration
Vite projects work out of the box with Alternate Futures. No additional configuration is needed for basic deployments.
If you need a custom base path, edit vite.config.ts:
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
// Set base path if deploying to a subdirectory
// base: '/my-app/',
build: {
// Output directory (default: 'dist')
outDir: 'dist',
// Generate source maps for debugging (optional)
sourcemap: false,
},
});Create React App Configuration
CRA projects also work out of the box. If you need a custom base path, set the homepage field in package.json:
{
"homepage": ".",
"scripts": {
"build": "react-scripts build"
}
}Setting homepage to '.'
Setting homepage to "." ensures all asset paths are relative, which is important for IPFS deployments where your site may be served from different gateway URLs.
Step 3: Build Your Project
# Build the production bundle
npm run build
# Preview locally (optional)
npm run previewStep 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_hereStep 5: Initialize and Deploy
# Initialize AF site configuration
af sites init
# When prompted, configure:
# Site name: my-react-app
# Build command: npm run build
# Output directory: dist
# Storage network: ipfs
# Deploy to decentralized storage
af sites deployYou should see output like:
Building site...
Uploading files to IPFS...
Deployment successful!
CID: bafybei...
URL: https://ipfs.io/ipfs/bafybei...Step 6: Handle Client-Side Routing
If your React app uses React Router (or any client-side routing), you need to handle the case where users navigate directly to a route like /about. On a traditional server, this would return a 404 because /about/index.html does not exist.
Solution: Add a 404 Redirect
Create a public/_redirects file (for Vite) or a _redirects file in your public/ folder (for CRA):
/* /index.html 200This tells the gateway to serve index.html for all routes, letting React Router handle the routing.
Alternative: Use Hash Router
If redirects are not available, switch to HashRouter:
import { HashRouter, Routes, Route } from 'react-router-dom';
function App() {
return (
<HashRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</HashRouter>
);
}Hash-based URLs (e.g., /#/about) work on any static server without configuration.
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);Environment Variables
Vite
Vite exposes environment variables prefixed with VITE_ to your application:
# .env
VITE_API_URL=https://api.example.com
VITE_APP_TITLE=My AppAccess them in your code:
const apiUrl = import.meta.env.VITE_API_URL;Create React App
CRA exposes variables prefixed with REACT_APP_:
# .env
REACT_APP_API_URL=https://api.example.com
REACT_APP_TITLE=My AppAccess them in your code:
const apiUrl = process.env.REACT_APP_API_URL;Security
Environment variables prefixed with VITE_ or REACT_APP_ are embedded in your build output and visible to anyone who inspects your site. Never put secrets (API keys, tokens) in client-side environment variables.
Common Issues
"Page not found" on route refresh
Your app uses client-side routing but the static server cannot find the route. See the Handle Client-Side Routing section above.
"Build output is too large"
- Enable code splitting (Vite does this automatically)
- Use
React.lazy()for route-based code splitting - Analyze your bundle:
npx vite-bundle-visualizer(Vite) ornpx source-map-explorer build/static/js/*.js(CRA) - Remove unused dependencies
"Assets not loading after deployment"
- Make sure
baseinvite.config.tsis set to'/'or'./' - For CRA, set
"homepage": "."inpackage.json - Check that asset paths are relative, not absolute
"Blank white page after deployment"
- Open the browser console for JavaScript errors
- Verify the
index.htmlfile references the correct bundle paths - Try building with
npm run buildand testing locally withnpx serve distbefore deploying
Next Steps
- Custom Domains - Connect your own domain
- CI/CD Integration - Automate deployments
- Storage Management - Choose the right storage network
- Deploy Next.js - Deploy a Next.js app
- Deploy Astro - Deploy an Astro site