If you’ve deployed a Flutter web application, you’ve likely noticed that your URLs contain a hash symbol (#) like yourdomain.com/#/home. While functional, these URLs aren’t as clean or SEO-friendly as they could be. Fortunately, Flutter provides a built-in solution to remove this hash and use path-based URLs instead.
Why Remove the Hash?
SEO Benefits
Search engines traditionally struggle with hash-based URLs when crawling and indexing content. Path-based URLs (yourdomain.com/home) are treated as distinct pages, improving your app’s discoverability.
Professional Appearance
Clean URLs look more professional and are easier to share. yourdomain.com/products/widget is more intuitive than yourdomain.com/#/products/widget.
Better Analytics
Path-based URLs provide clearer tracking data in analytics platforms like Google Analytics.
The Built-In Solution: Flutter’s URL Strategy
Flutter includes a url_strategy package as part of its SDK, though its implementation has evolved over time.
For Flutter 2.5 and Above (Recommended Approach)
Since Flutter 2.5, the solution is simpler than ever:
import 'package:flutter/material.dart';
import 'package:flutter_web_plugins/url_strategy.dart';
void main() {
// Call this before running the app
usePathUrlStrategy();
runApp(MyApp());
}
For Earlier Flutter Versions
If you’re using an older version, you might need this approach:
import 'package:flutter/material.dart';
import 'package:flutter_web_plugins/flutter_web_plugins.dart';
void main() {
// Set the URL strategy before running the app
setUrlStrategy(PathUrlStrategy());
runApp(MyApp());
}
Complete Implementation Example
Here’s a full example with routing:
import 'package:flutter/material.dart';
import 'package:flutter_web_plugins/url_strategy.dart';
void main() {
// Remove the hash from URLs
usePathUrlStrategy();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Web with Clean URLs',
initialRoute: '/',
routes: {
'/': (context) => HomePage(),
'/about': (context) => AboutPage(),
'/products': (context) => ProductsPage(),
'/contact': (context) => ContactPage(),
},
);
}
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Home')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Welcome to the Home Page'),
ElevatedButton(
onPressed: () => Navigator.pushNamed(context, '/about'),
child: Text('Go to About'),
),
],
),
),
);
}
}
class AboutPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('About')),
body: Center(child: Text('About Page Content')),
);
}
}
// Additional page classes...
Important Considerations
1. Server Configuration
When using path-based URLs, you need to configure your web server to redirect all requests to your index.html file. This is crucial because browsers make direct requests for paths like /about that don’t exist as separate files.
For Firebase Hosting:
Add this to your firebase.json:
{
"hosting": {
"public": "build/web",
"ignore": ["firebase.json", "**/.*", "**/node_modules/**"],
"rewrites": [
{
"source": "**",
"destination": "/index.html"
}
]
}
}
For NGINX:
location / {
try_files $uri $uri/ /index.html;
}
For Apache (.htaccess):
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
2. Testing Locally
When testing locally, use:
flutter run -d chrome --web-hostname localhost --web-port 8080
3. Browser History
Path-based URLs work with browser history navigation (back/forward buttons) seamlessly.
4. Deep Linking
Ensure deep links work by testing direct navigation to paths like yourdomain.com/about without first visiting the homepage.
Troubleshooting Common Issues
Blank Page on Refresh
This is almost always a server configuration issue. Double-check your server rewrite rules.
404 Errors on Direct Navigation
Again, this is a server configuration problem. The server must serve index.html for all routes.
Development vs Production
Remember that setUrlStrategy() or usePathUrlStrategy() should only be called once, at app startup.
Migration Tips
If you’re migrating an existing Flutter web app:
- Implement the URL strategy change
- Update all internal navigation to use path-based routes
- Configure your server
- Test thoroughly, especially:
- Direct URL access
- Page refreshes
- Browser navigation buttons
- Any existing bookmarks or shared links
Conclusion
Removing the hash from your Flutter web app URLs is a straightforward process that significantly improves user experience and SEO. With Flutter’s built-in URL strategy support and proper server configuration, you can achieve clean, professional URLs in just a few lines of code.
The result? Better-looking URLs, improved search engine visibility, and a more polished application overall. It’s a small change that makes a big difference in how users perceive and interact with your Flutter web application.
Pro Tip: Always test your URL changes across different scenarios before deploying to production. Clean URLs are worth the effort, but they require proper implementation to work seamlessly.

























Leave a Comment
Your email address will not be published. Required fields are marked with *