Simple guide for building and deploying your Flutter web application.
Prerequisites: Ensure backend setup and Flutter installation are complete before proceeding with web deployment.
Build your Flutter web application for deployment:
flutter build web
This command creates optimized web files in the build/web/ directory.
Upload your built web application to your web server:
After running the build command, go to /build/web/ directory
Copy all files from the build/web/ folder and upload them to your domain
Note: Include hidden files like .htaccess if present
Deploy your Flutter web application to Vercel for free hosting:
npm install -g vercel
flutter build web
cd build/web
vercel --prod
flutter build webbuild/webEnsure your base URL in the app points to your backend API server
Configure CORS settings on your backend to allow web app requests
Test your web application on different screen sizes and devices
Laravel application hosted on web server
Flutter web application for administrators
Parent and Student apps for iOS/Android
Windows and macOS desktop versions
Deploy the Flutter web admin panel for school administrators:
# Navigate to admin panel directory
cd admin_panel
# Clean previous builds
flutter clean
flutter pub get
# Build for web production
flutter build web --release --web-renderer html
# Build with specific base href (for subdirectories)
flutter build web --release --base-href="/admin/" --web-renderer html
# Apache .htaccess for Flutter web
# Place in admin_panel/build/web/.htaccess
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^.*$ /index.html [L]
# Enable compression
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/xml
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE application/xhtml+xml
AddOutputFilterByType DEFLATE application/rss+xml
AddOutputFilterByType DEFLATE application/javascript
AddOutputFilterByType DEFLATE application/x-javascript
# Cache static assets
ExpiresActive on
ExpiresByType text/css "access plus 1 year"
ExpiresByType application/javascript "access plus 1 year"
ExpiresByType image/png "access plus 1 year"
ExpiresByType image/jpg "access plus 1 year"
ExpiresByType image/jpeg "access plus 1 year"
# Upload to web server
# Method 1: FTP/SFTP
scp -r build/web/* user@your-server.com:/var/www/html/admin/
# Method 2: Using rsync
rsync -avz --delete build/web/ user@your-server.com:/var/www/html/admin/
# Method 3: cPanel File Manager
# 1. Compress build/web folder to zip
# 2. Upload via cPanel File Manager
# 3. Extract in public_html/admin directory
URL: admin.yourschool.com
# Apache Virtual Host
<VirtualHost *:80>
ServerName admin.yourschool.com
DocumentRoot /var/www/html/admin
<Directory /var/www/html/admin>
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
URL: yourschool.com/admin
# Apache Alias
Alias /admin /var/www/html/admin
<Directory /var/www/html/admin>
AllowOverride All
Require all granted
</Directory>
Configure mobile applications for different deployment environments:
# lib/config/deployment_config.dart
class DeploymentConfig {
static const String environment = String.fromEnvironment(
'ENVIRONMENT',
defaultValue: 'production'
);
static const Map<String, Map<String, String>> configs = {
'development': {
'apiUrl': 'http://localhost:8000/api',
'webUrl': 'http://localhost:3000',
'socketUrl': 'ws://localhost:6001',
},
'staging': {
'apiUrl': 'https://staging-api.yourschool.com/api',
'webUrl': 'https://staging-admin.yourschool.com',
'socketUrl': 'wss://staging-api.yourschool.com:6001',
},
'production': {
'apiUrl': 'https://api.yourschool.com/api',
'webUrl': 'https://admin.yourschool.com',
'socketUrl': 'wss://api.yourschool.com:6001',
},
};
static String get apiUrl => configs[environment]!['apiUrl']!;
static String get webUrl => configs[environment]!['webUrl']!;
static String get socketUrl => configs[environment]!['socketUrl']!;
}
# android/app/build.gradle
android {
flavorDimensions "environment"
productFlavors {
development {
dimension "environment"
applicationIdSuffix ".dev"
versionNameSuffix "-dev"
resValue "string", "app_name", "Mighty School (Dev)"
}
staging {
dimension "environment"
applicationIdSuffix ".staging"
versionNameSuffix "-staging"
resValue "string", "app_name", "Mighty School (Staging)"
}
production {
dimension "environment"
resValue "string", "app_name", "Mighty School"
}
}
}
# Build different environments for iOS
# Development
flutter build ios --flavor development --dart-define=ENVIRONMENT=development
# Staging
flutter build ios --flavor staging --dart-define=ENVIRONMENT=staging
# Production
flutter build ios --flavor production --dart-define=ENVIRONMENT=production
Build and deploy desktop applications for Windows and macOS:
# Enable Windows desktop support
flutter config --enable-windows-desktop
# Build Windows application
cd admin_panel
flutter build windows --release
# Create installer (using Inno Setup)
# 1. Install Inno Setup Compiler
# 2. Create installer script (admin_panel_installer.iss)
# 3. Compile installer
# admin_panel_installer.iss
[Setup]
AppName=Mighty School Admin Panel
AppVersion=1.0.0
DefaultDirName={pf}\Mighty School
DefaultGroupName=Mighty School
OutputDir=dist
OutputBaseFilename=MightySchoolAdminSetup
Compression=lzma
SolidCompression=yes
[Files]
Source: "build\windows\runner\Release\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs
[Icons]
Name: "{group}\Mighty School Admin"; Filename: "{app}\mighty_school_admin.exe"
Name: "{commondesktop}\Mighty School Admin"; Filename: "{app}\mighty_school_admin.exe"
[Run]
Filename: "{app}\mighty_school_admin.exe"; Description: "Launch Mighty School Admin"; Flags: nowait postinstall skipifsilent
# Enable macOS desktop support
flutter config --enable-macos-desktop
# Build macOS application
cd admin_panel
flutter build macos --release
# Create DMG installer (using create-dmg)
brew install create-dmg
create-dmg \
--volname "Mighty School Admin" \
--window-pos 200 120 \
--window-size 600 300 \
--icon-size 100 \
--icon "Mighty School Admin.app" 175 120 \
--hide-extension "Mighty School Admin.app" \
--app-drop-link 425 120 \
"MightySchoolAdmin.dmg" \
"build/macos/Build/Products/Release/"
Configure domains and SSL certificates for all applications:
yourschool.com
Marketing website and landing page
api.yourschool.com
Laravel backend API endpoints
admin.yourschool.com
Web admin panel for administrators
files.yourschool.com
Static file storage and CDN
# Using Let's Encrypt with Certbot
# Install Certbot
sudo apt install certbot python3-certbot-apache
# Generate certificates for all domains
sudo certbot --apache -d yourschool.com -d www.yourschool.com \
-d api.yourschool.com -d admin.yourschool.com -d files.yourschool.com
# Auto-renewal setup
sudo crontab -e
# Add: 0 12 * * * /usr/bin/certbot renew --quiet
# /etc/nginx/sites-available/mighty-school
server {
listen 80;
server_name api.yourschool.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name api.yourschool.com;
ssl_certificate /etc/letsencrypt/live/yourschool.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourschool.com/privkey.pem;
root /var/www/html/mighty-school-backend/public;
index index.php;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
}
}
server {
listen 443 ssl http2;
server_name admin.yourschool.com;
ssl_certificate /etc/letsencrypt/live/yourschool.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourschool.com/privkey.pem;
root /var/www/html/admin-panel;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
# Cache static assets
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
}