GoFlow's project structure and CLI are inspired by Flutter, providing a familiar experience for developers who know Flutter while staying true to Go idioms.
| Flutter | GoFlow | Description |
|---|---|---|
flutter create |
goflow new |
Create new project |
flutter pub get |
go mod tidy |
Get dependencies |
flutter run |
cd macos && go run main.go |
Run on platform |
flutter build |
cd macos && go build |
Build for platform |
my_app/
├── lib/
│ └── main.dart
├── macos/
│ ├── Runner.xcodeproj
│ └── Runner/
├── linux/
│ ├── CMakeLists.txt
│ └── runner/
├── windows/
│ ├── CMakeLists.txt
│ └── runner/
├── android/
├── ios/
├── web/
├── test/
├── assets/
├── pubspec.yaml
└── analysis_options.yaml
my_app/
├── lib/
│ └── main.go # Go instead of Dart
├── macos/
│ ├── main.go # Go runner (will become Xcode project)
│ ├── runner/
│ └── .gitignore
├── linux/
│ ├── main.go # Go runner (will become CMake)
│ ├── runner/
│ └── .gitignore
├── windows/
│ ├── main.go # Go runner (will become CMake)
│ ├── runner/
│ └── .gitignore
├── test/
├── assets/
│ ├── fonts/
│ ├── images/
│ └── icons/
├── goflow.yaml # Like pubspec.yaml
├── go.mod # Go dependencies
└── analysis_options.yaml # Future linting config
Flutter's pubspec.yaml:
name: my_app
description: A Flutter application
version: 1.0.0+1
environment:
sdk: ^3.10.0
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.8
flutter:
uses-material-design: true
assets:
- images/
fonts:
- family: Roboto
fonts:
- asset: fonts/Roboto-Regular.ttfGoFlow's goflow.yaml:
name: my_app
description: A GoFlow application
version: 0.1.0+1
# Go module path
module: com.example/my_app
# Minimum Go version
environment:
go: "1.21"
# Dependencies
dependencies:
goflow:
git: https://github.com/base-go/GoFlow
version: v0.1.0
# Platform configuration
platforms:
- macos
- windows
- linux
# Assets
assets:
- assets/images/
- assets/fonts/
# Fonts
fonts:
- family: Roboto
fonts:
- asset: assets/fonts/Roboto-Regular.ttf
- asset: assets/fonts/Roboto-Bold.ttf
weight: 700import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Text('$_counter'),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
child: Icon(Icons.add),
),
);
}
}package lib
import (
"fmt"
"github.com/base-go/GoFlow/pkg/core/framework"
"github.com/base-go/GoFlow/pkg/core/signals"
"github.com/base-go/GoFlow/pkg/core/widgets"
)
type MyApp struct {
goflow.BaseWidget
counter *signals.Signal[int]
}
func NewMyApp() *MyApp {
return &MyApp{
counter: signals.New(0),
}
}
func (app *MyApp) Build(ctx goflow.BuildContext) goflow.Widget {
count := app.counter.Get()
return widgets.NewCenter(
widgets.NewText(fmt.Sprintf("%d", count)),
)
}
func (app *MyApp) Increment() {
app.counter.Update(func(v int) int { return v + 1 })
}
func Run() {
app := NewMyApp()
goflow.RunApp(app)
}- Project Structure: Same directory layout with lib/, platform dirs, assets/
- Configuration File: goflow.yaml mirrors pubspec.yaml
- Platform Separation: Platform-specific code in separate directories
- CLI Commands: Similar command structure (new, run, build)
- Widget System: Declarative UI with widget trees
- Build Method: Widgets have Build() methods
- Language: Go instead of Dart
- State Management: Signals instead of StatefulWidget/setState
- Single Widget Type: No StatelessWidget vs StatefulWidget distinction
- Dependencies: go.mod for packages, not pub
- Type System: Go's static typing with generics for signals
- No Hot Reload: (yet - planned for future)
- Desktop Focus: No iOS/Android (desktop-first framework)
Platform directories contain simple Go runners that call into lib/ code:
// macos/main.go
package main
import "your.module/lib"
func main() {
lib.Run()
}Platform directories will contain native projects:
macOS: Xcode project with Swift/Objective-C calling into Go Windows: Visual Studio project with C++ calling into Go DLL Linux: CMake project with C++ calling into Go shared library
This matches Flutter's model where each platform has native launcher code.
- Familiarity: Developers coming from Flutter feel at home
- Best Practices: Proven project structure from successful framework
- Clear Separation: Platform code vs shared app code
- Scalability: Structure works for small and large projects
- Asset Management: Centralized assets/ directory
- Configuration: Single source of truth (goflow.yaml)
- Consistency: Similar patterns across all platforms
For Flutter developers moving to GoFlow:
- Project Setup:
goflow newinstead offlutter create - Dependencies: Use go.mod instead of pubspec.yaml for packages
- State: Replace StatefulWidget with Signals
- Widgets: Similar widget names (Text, Container, Column, etc.)
- Build:
cd platform && go buildinstead offlutter build - Run:
cd platform && go run main.goinstead offlutter run