Spread is an OTA (Over-the-Air) update server designed specifically for React Native applications. It enables developers to push JavaScript bundle updates to their React Native apps without requiring users to download new versions from app stores. A react-native-code-push compatible server.
Spread uses Cloudflare R2 bucket for storing bundles. You can learn more about Cloudflare R2 here
You can use this article to set Spread Host URL in react-native-code-push.
- Fully Self-hostable - Complete control over your update infrastructure
- CodePush compatible - Drop-in replacement for Microsoft CodePush
- Multi-platform support - iOS and Android bundle management
- Environment management - Separate configurations for development, staging, and production
- Version control - Track and manage different app versions
- Rollback capabilities - Quickly revert to previous versions
- Web dashboard - React-based admin interface
git clone https://github.com/SwishHQ/spread.git
cd spread
Copy the example environment file and configure your settings:
cp .env.example .env
Edit .env
with your configuration:
ENV=local
APP_NAME=spread
PORT=4000
# MongoDB Configuration
MONGODB_URL=mongodb://localhost:27017
MONGODB_DATABASE=spread
# Cloudflare R2 Configuration (for bundle storage)
CLOUDFLARE_R2_ACCOUNT_ID=your_account_id
CLOUDFLARE_R2_BUCKET=your_bucket_name
CLOUDFLARE_R2_ACCESS_KEY_ID=your_access_key
CLOUDFLARE_R2_SECRET_ACCESS_KEY=your_secret_key
Install Go dependencies:
go mod download
Install frontend dependencies:
cd web
npm install
cd ..
Build the backend:
make build
Build the frontend:
cd web
npm run build
cd ..
Start the Spread server:
./spread serve
The server will be available at http://localhost:4000
Project Structure
βββ cmd/ # Command-line interface (CLI) entrypoints
β βββ root.go # Root command configuration
β βββ serve.go # Server command
β βββ client.go # Client/release commands
βββ cli/ # CLI utilities
β βββ bundle_cli.go # Bundle management CLI
βββ config/ # Configuration management
βββ middleware/ # HTTP middleware (auth, logging, etc.)
βββ pkg/ # External package integrations
β βββ cloudflare.go # Cloudflare R2 integration
β βββ db.go # Database connection
βββ src/ # Main application source code
β βββ controller/ # HTTP controllers (route handlers)
β βββ model/ # Data models and schemas
β βββ repository/ # Data access layer
β βββ service/ # Business logic and orchestration
βββ types/ # Shared type definitions
βββ utils/ # Utility/helper functions
βββ logger/ # Logging configuration and utilities
βββ exception/ # Centralized error handling
βββ web/ # Frontend React application
β βββ src/ # React source code
β βββ public/ # Static assets
β βββ dist/ # Built frontend assets
β βββ package.json # Frontend dependencies
βββ script/ # Build and deployment scripts
βββ main.go # Application entry point
βββ go.mod # Go module definition
βββ go.sum # Go dependency checksums
βββ Makefile # Build automation
βββ Dockerfile # Container configuration
βββ .env.example # Environment variable template
βββ README.md # This file (the one youβre reading)
Pro tip: Each directory is lovingly crafted to keep things decoupled and maintainable. Whether youβre a backend buff, a frontend fanatic, or just here for the scripts, youβll find your happy place.
-
Start MongoDB (if not already running):
# macOS with Homebrew brew services start mongodb-community # Ubuntu/Debian sudo systemctl start mongod # Windows net start MongoDB
-
Run in development mode:
# Terminal 1: Run backend go run *.go serve # Terminal 2: Run frontend (in web directory) cd web npm run dev
-
Access the application:
- Backend API:
http://localhost:4000
- Frontend:
http://localhost:5173
(Vite dev server)
- Backend API:
Variable | Description | Default | Required |
---|---|---|---|
ENV |
Environment (local, development, production) | local |
Yes |
APP_NAME |
Application name | spread |
No |
PORT |
Server port | 4000 |
No |
MONGODB_URL |
MongoDB connection string | - | Yes |
MONGODB_DATABASE |
MongoDB database name | spread |
Yes |
CLOUDFLARE_R2_ACCOUNT_ID |
Cloudflare R2 account ID | - | Yes |
CLOUDFLARE_R2_BUCKET |
Cloudflare R2 bucket name | - | Yes |
CLOUDFLARE_R2_ACCESS_KEY_ID |
Cloudflare R2 access key | - | Yes |
CLOUDFLARE_R2_SECRET_ACCESS_KEY |
Cloudflare R2 secret key | - | Yes |
# Build the entire application
make build
# Build with specific GOOS and GOARCH
GOOS=linux GOARCH=amd64 go build -o spread-linux-amd64
GOOS=darwin GOARCH=amd64 go build -o spread-darwin-amd64
GOOS=windows GOARCH=amd64 go build -o spread-windows-amd64.exe
# Build Docker image
docker build -t spread .
# Run with Docker
docker run -p 4000:4000 --env-file .env spread
- Set up a production MongoDB instance
- Configure Cloudflare R2 storage
- Set environment variables for production
- Build and deploy the application
Example production deployment with Docker Compose:
version: '3.8'
services:
spread:
build: .
ports:
- "4000:4000"
environment:
- ENV=production
- MONGODB_URL=mongodb://mongo:27017
- MONGODB_DATABASE=spread
- CLOUDFLARE_R2_ACCOUNT_ID=${CLOUDFLARE_R2_ACCOUNT_ID}
- CLOUDFLARE_R2_BUCKET=${CLOUDFLARE_R2_BUCKET}
- CLOUDFLARE_R2_ACCESS_KEY_ID=${CLOUDFLARE_R2_ACCESS_KEY_ID}
- CLOUDFLARE_R2_SECRET_ACCESS_KEY=${CLOUDFLARE_R2_SECRET_ACCESS_KEY}
depends_on:
- mongo
restart: unless-stopped
mongo:
image: mongo:6.0
ports:
- "27017:27017"
volumes:
- mongo_data:/data/db
restart: unless-stopped
volumes:
mongo_data:
Install the Spread CLI globally:
# From source
go install github.com/SwishHQ/spread/cmd/spread@latest
# Or build locally
make build
sudo cp spread /usr/local/bin/
# Or use the install script
curl -fsSL https://cdn-swish.justswish.in/spread-install.sh | sh
spread release \
--remote https://your-spread-server.com \
--auth-key YOUR_AUTH_KEY \
--app-name my-react-native-app \
--environment production \
--target-version 1.2.0 \
--os-name ios \
--project-dir /path/to/react-native/project \
--is-typescript true \
--description "Bug fixes and performance improvements"
Flag | Description | Required | Default |
---|---|---|---|
--remote |
Spread server URL | Yes | - |
--auth-key |
Authentication key | Yes | - |
--app-name |
Application name | Yes | - |
--environment |
Environment (development, staging, production) | Yes | - |
--target-version |
Target app version | Yes | - |
--os-name |
Operating system (ios, android) | Yes | - |
--project-dir |
React Native project directory | No | Current directory |
--is-typescript |
Is TypeScript project | No | false |
--description |
Release description | No | - |
--disable-minify |
Disable bundle minification | No | false |
--hermes |
Enable Hermes engine | No | false |
We welcome contributions from the community! Here's how you can help:
- Fork the repository
- Create a feature branch:
git checkout -b feature/your-feature-name
- Make your changes
- Run tests:
go test ./...
- Commit your changes:
git commit -m "feat: add your feature description"
- Push to your fork:
git push origin feature/your-feature-name
- Create a Pull Request
- Follow Go conventions and use
gofmt
for formatting - Write meaningful commit messages following conventional commits
- Add tests for new functionality
- Update documentation for API changes
- Ensure all tests pass before submitting PR
# Run all tests
go test ./...
# Run tests with coverage
go test -cover ./...
# Run specific test
go test ./src/service -v
Made with π by the Swish Engineering